10807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
20807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Copyright (C) 2007,2008 Freescale semiconductor, Inc.
30807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
40807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Author: Li Yang <LeoLi@freescale.com>
50807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *         Jerry Huang <Chang-Ming.Huang@freescale.com>
60807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
70807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Initialization based on code from Shlomi Gridish.
80807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
90807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * This program is free software; you can redistribute  it and/or modify it
100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * under  the terms of  the GNU General  Public License as published by the
110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Free Software Foundation;  either version 2 of the  License, or (at your
120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * option) any later version.
130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * This program is distributed in the hope that it will be useful, but
150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * WITHOUT ANY WARRANTY; without even the implied warranty of
160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * General Public License for more details.
180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * You should have received a copy of the  GNU General Public License along
200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * with this program; if not, write  to the Free Software Foundation, Inc.,
210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * 675 Mass Ave, Cambridge, MA 02139, USA.
220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/module.h>
250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/kernel.h>
260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/delay.h>
270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/slab.h>
280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/proc_fs.h>
290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/errno.h>
300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/init.h>
310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/interrupt.h>
320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/io.h>
330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/timer.h>
340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/usb.h>
350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/device.h>
360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/usb/ch9.h>
370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/usb/gadget.h>
380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/workqueue.h>
390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/time.h>
400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/fsl_devices.h>
410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/platform_device.h>
420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <linux/uaccess.h>
430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include <asm/unaligned.h>
450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#include "fsl_otg.h"
470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define DRIVER_VERSION "Rev. 1.55"
490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define DRIVER_INFO DRIVER_DESC " " DRIVER_VERSION
520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic const char driver_name[] = "fsl-usb2-otg";
540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangconst pm_message_t otg_suspend_state = {
560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.event = 1,
570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang};
580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define HA_DATA_PULSE
600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic struct usb_dr_mmap *usb_dr_regs;
620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic struct fsl_otg *fsl_otg_dev;
630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int srp_wait_done;
640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* FSM timers */
660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstruct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr,
670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	*b_ase0_brst_tmr, *b_se0_srp_tmr;
680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Driver specific timers */
700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstruct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr,
710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	*b_srp_wait_tmr, *a_wait_enum_tmr;
720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic struct list_head active_timers;
740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic struct fsl_otg_config fsl_otg_initdata = {
760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.otg_port = 1,
770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang};
780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#ifdef CONFIG_PPC32
800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic u32 _fsl_readl_be(const unsigned __iomem *p)
810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return in_be32(p);
830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic u32 _fsl_readl_le(const unsigned __iomem *p)
860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return in_le32(p);
880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic void _fsl_writel_be(u32 v, unsigned __iomem *p)
910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	out_be32(p, v);
930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic void _fsl_writel_le(u32 v, unsigned __iomem *p)
960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	out_le32(p, v);
980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic u32 (*_fsl_readl)(const unsigned __iomem *p);
1010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic void (*_fsl_writel)(u32 v, unsigned __iomem *p);
1020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define fsl_readl(p)		(*_fsl_readl)((p))
1040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define fsl_writel(v, p)	(*_fsl_writel)((v), (p))
1050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#else
1070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define fsl_readl(addr)		readl(addr)
1080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#define fsl_writel(val, addr)	writel(val, addr)
1090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#endif /* CONFIG_PPC32 */
1100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Routines to access transceiver ULPI registers */
1120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangu8 view_ulpi(u8 addr)
1130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 temp;
1150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = 0x40000000 | (addr << 16);
1170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &usb_dr_regs->ulpiview);
1180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	udelay(1000);
1190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	while (temp & 0x40)
1200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp = fsl_readl(&usb_dr_regs->ulpiview);
1210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
1220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
1230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint write_ulpi(u8 addr, u8 data)
1250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 temp;
1270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = 0x60000000 | (addr << 16) | data;
1290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &usb_dr_regs->ulpiview);
1300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
1310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
1320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* -------------------------------------------------------------*/
1340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Operations that will be called from OTG Finite State Machine */
1350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Charge vbus for vbus pulsing in SRP */
1370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_chrg_vbus(int on)
1380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
1400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
1420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on)
1440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* stop discharging, start charging */
1450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp = (tmp & ~OTGSC_CTRL_VBUS_DISCHARGE) |
1460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			OTGSC_CTRL_VBUS_CHARGE;
1470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	else
1480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* stop charging */
1490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp &= ~OTGSC_CTRL_VBUS_CHARGE;
1500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(tmp, &usb_dr_regs->otgsc);
1520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
1530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Discharge vbus through a resistor to ground */
1550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_dischrg_vbus(int on)
1560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
1580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
1600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on)
1620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* stop charging, start discharging */
1630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp = (tmp & ~OTGSC_CTRL_VBUS_CHARGE) |
1640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			OTGSC_CTRL_VBUS_DISCHARGE;
1650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	else
1660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* stop discharging */
1670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE;
1680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(tmp, &usb_dr_regs->otgsc);
1700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
1710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* A-device driver vbus, controlled through PP bit in PORTSC */
1730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_drv_vbus(int on)
1740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
1760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on) {
1780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp = fsl_readl(&usb_dr_regs->portsc) & ~PORTSC_W1C_BITS;
1790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_writel(tmp | PORTSC_PORT_POWER, &usb_dr_regs->portsc);
1800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
1810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp = fsl_readl(&usb_dr_regs->portsc) &
1820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		      ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER;
1830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_writel(tmp, &usb_dr_regs->portsc);
1840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
1850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
1860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
1880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Pull-up D+, signalling connect by periperal. Also used in
1890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * data-line pulsing in SRP
1900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
1910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_loc_conn(int on)
1920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
1930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
1940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
1960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on)
1980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp |= OTGSC_CTRL_DATA_PULSING;
1990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	else
2000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp &= ~OTGSC_CTRL_DATA_PULSING;
2010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(tmp, &usb_dr_regs->otgsc);
2030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
2060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Generate SOF by host.  This is controlled through suspend/resume the
2070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * port.  In host mode, controller will automatically send SOF.
2080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Suspend will block the data on the port.
2090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
2100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_loc_sof(int on)
2110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
2130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp = fsl_readl(&fsl_otg_dev->dr_mem_map->portsc) & ~PORTSC_W1C_BITS;
2150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on)
2160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp |= PORTSC_PORT_FORCE_RESUME;
2170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	else
2180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp |= PORTSC_PORT_SUSPEND;
2190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(tmp, &fsl_otg_dev->dr_mem_map->portsc);
2210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */
2250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_start_pulse(void)
2260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 tmp;
2280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	srp_wait_done = 0;
2300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#ifdef HA_DATA_PULSE
2310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK;
2320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	tmp |= OTGSC_HA_DATA_PULSE;
2330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(tmp, &usb_dr_regs->otgsc);
2340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#else
2350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_loc_conn(1);
2360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#endif
2370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_add_timer(b_data_pulse_tmr);
2390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid b_data_pulse_end(unsigned long foo)
2420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#ifdef HA_DATA_PULSE
2440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#else
2450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_loc_conn(0);
2460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang#endif
2470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Do VBUS pulse after data pulse */
2490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_pulse_vbus();
2500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_pulse_vbus(void)
2530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	srp_wait_done = 0;
2550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_chrg_vbus(1);
2560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* start the timer to end vbus charge */
2570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_add_timer(b_vbus_pulse_tmr);
2580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid b_vbus_pulse_end(unsigned long foo)
2610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_chrg_vbus(0);
2630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/*
2650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * As USB3300 using the same a_sess_vld and b_sess_vld voltage
2660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * we need to discharge the bus for a while to distinguish
2670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * residual voltage of vbus pulsing and A device pull up
2680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 */
2690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_dischrg_vbus(1);
2700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_add_timer(b_srp_wait_tmr);
2710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid b_srp_end(unsigned long foo)
2740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_dischrg_vbus(0);
2760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	srp_wait_done = 1;
2770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2787e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
2790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	    fsl_otg_dev->fsm.b_sess_vld)
2800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_dev->fsm.b_srp_done = 1;
2810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
2840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Workaround for a_host suspending too fast.  When a_bus_req=0,
2850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * a_host will start by SRP.  It needs to set b_hnp_enable before
2860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * actually suspending to start HNP
2870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
2880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid a_wait_enum(unsigned long foo)
2890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
2900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	VDBG("a_wait_enum timeout\n");
2917e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
2920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_add_timer(a_wait_enum_tmr);
2930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	else
2940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_statemachine(&fsl_otg_dev->fsm);
2950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
2960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
2970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* The timeout callback function to set time out bit */
2980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid set_tmout(unsigned long indicator)
2990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
3000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	*(int *)indicator = 1;
3010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
3020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Initialize timers */
3040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint fsl_otg_init_timers(struct otg_fsm *fsm)
3050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
3060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* FSM used timers */
3070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
3080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->a_wait_vrise_tmout);
3090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!a_wait_vrise_tmr)
3100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
3130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->a_wait_bcon_tmout);
3140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!a_wait_bcon_tmr)
3150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
3180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->a_aidl_bdis_tmout);
3190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!a_aidl_bdis_tmr)
3200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
3230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->b_ase0_brst_tmout);
3240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_ase0_brst_tmr)
3250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
3280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->b_se0_srp);
3290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_se0_srp_tmr)
3300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_srp_fail_tmr = otg_timer_initializer(&set_tmout, TB_SRP_FAIL,
3330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm->b_srp_done);
3340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_srp_fail_tmr)
3350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	a_wait_enum_tmr = otg_timer_initializer(&a_wait_enum, 10,
3380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				(unsigned long)&fsm);
3390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!a_wait_enum_tmr)
3400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* device driver used timers */
3430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_srp_wait_tmr = otg_timer_initializer(&b_srp_end, TB_SRP_WAIT, 0);
3440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_srp_wait_tmr)
3450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_data_pulse_tmr = otg_timer_initializer(&b_data_pulse_end,
3480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				TB_DATA_PLS, 0);
3490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_data_pulse_tmr)
3500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	b_vbus_pulse_tmr = otg_timer_initializer(&b_vbus_pulse_end,
3530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				TB_VBUS_PLS, 0);
3540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!b_vbus_pulse_tmr)
3550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
3560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
3580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
3590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Uninitialize timers */
3610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_uninit_timers(void)
3620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
3630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* FSM used timers */
3640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (a_wait_vrise_tmr != NULL)
3650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(a_wait_vrise_tmr);
3660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (a_wait_bcon_tmr != NULL)
3670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(a_wait_bcon_tmr);
3680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (a_aidl_bdis_tmr != NULL)
3690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(a_aidl_bdis_tmr);
3700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_ase0_brst_tmr != NULL)
3710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_ase0_brst_tmr);
3720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_se0_srp_tmr != NULL)
3730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_se0_srp_tmr);
3740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_srp_fail_tmr != NULL)
3750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_srp_fail_tmr);
3760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (a_wait_enum_tmr != NULL)
3770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(a_wait_enum_tmr);
3780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* device driver used timers */
3800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_srp_wait_tmr != NULL)
3810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_srp_wait_tmr);
3820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_data_pulse_tmr != NULL)
3830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_data_pulse_tmr);
3840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (b_vbus_pulse_tmr != NULL)
3850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(b_vbus_pulse_tmr);
3860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
3870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Add timer to timer list */
3890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_add_timer(void *gtimer)
3900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
3910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg_timer *timer = gtimer;
3920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg_timer *tmp_timer;
3930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
3940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/*
3950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * Check if the timer is already in the active list,
3960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * if so update timer count
3970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 */
3980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	list_for_each_entry(tmp_timer, &active_timers, list)
3990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	    if (tmp_timer == timer) {
4000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		timer->count = timer->expires;
4010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return;
4020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
4030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	timer->count = timer->expires;
4040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	list_add_tail(&timer->list, &active_timers);
4050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
4060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Remove timer from the timer list; clear timeout status */
4080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid fsl_otg_del_timer(void *gtimer)
4090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
4100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg_timer *timer = gtimer;
4110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg_timer *tmp_timer, *del_tmp;
4120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
4140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (tmp_timer == timer)
4150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			list_del(&timer->list);
4160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
4170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
4190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Reduce timer count by 1, and find timeout conditions.
4200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Called by fsl_otg 1ms timer interrupt
4210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
4220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint fsl_otg_tick_timer(void)
4230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
4240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg_timer *tmp_timer, *del_tmp;
4250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	int expired = 0;
4260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
4280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		tmp_timer->count--;
4290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* check if timer expires */
4300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (!tmp_timer->count) {
4310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			list_del(&tmp_timer->list);
4320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			tmp_timer->function(tmp_timer->data);
4330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			expired = 1;
4340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		}
4350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
4360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return expired;
4380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
4390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Reset controller, not reset the bus */
4410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangvoid otg_reset_controller(void)
4420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
4430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 command;
4440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	command = fsl_readl(&usb_dr_regs->usbcmd);
4460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	command |= (1 << 1);
4470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(command, &usb_dr_regs->usbcmd);
4480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	while (fsl_readl(&usb_dr_regs->usbcmd) & (1 << 1))
4490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		;
4500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
4510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Call suspend/resume routines in host driver */
4530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint fsl_otg_start_host(struct otg_fsm *fsm, int on)
4540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
4557e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct usb_otg *otg = fsm->otg;
4560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct device *dev;
4577e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
4580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 retval = 0;
4590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4607e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg->host)
4610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
4627e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	dev = otg->host->controller;
4630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/*
4650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * Update a_vbus_vld state as a_vbus_vld int is disabled
4660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * in device mode
4670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 */
4680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsm->a_vbus_vld =
4690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		!!(fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_A_VBUS_VALID);
4700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on) {
4710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* start fsl usb host controller */
4720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (otg_dev->host_working)
4730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			goto end;
4740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		else {
4750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			otg_reset_controller();
4760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			VDBG("host on......\n");
4770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (dev->driver->pm && dev->driver->pm->resume) {
4780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				retval = dev->driver->pm->resume(dev);
4790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				if (fsm->id) {
4800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					/* default-b */
4810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					fsl_otg_drv_vbus(1);
4820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					/*
4830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 * Workaround: b_host can't driver
4840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 * vbus, but PP in PORTSC needs to
4850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 * be 1 for host to work.
4860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 * So we set drv_vbus bit in
4870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 * transceiver to 0 thru ULPI.
4880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					 */
4890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					write_ulpi(0x0c, 0x20);
4900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				}
4910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			}
4920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
4930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			otg_dev->host_working = 1;
4940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		}
4950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
4960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* stop fsl usb host controller */
4970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (!otg_dev->host_working)
4980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			goto end;
4990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		else {
5000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			VDBG("host off......\n");
5010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (dev && dev->driver) {
5020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				if (dev->driver->pm && dev->driver->pm->suspend)
5030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					retval = dev->driver->pm->suspend(dev);
5040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				if (fsm->id)
5050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					/* default-b */
5060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					fsl_otg_drv_vbus(0);
5070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			}
5080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			otg_dev->host_working = 0;
5090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		}
5100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
5110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangend:
5120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return retval;
5130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
5140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
5160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Call suspend and resume function in udc driver
5170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * to stop and start udc driver.
5180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
5190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
5200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
5217e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct usb_otg *otg = fsm->otg;
5220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct device *dev;
5230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5247e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg->gadget || !otg->gadget->dev.parent)
5250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
5260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	VDBG("gadget %s\n", on ? "on" : "off");
5287e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	dev = otg->gadget->dev.parent;
5290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (on) {
5310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (dev->driver->resume)
5320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			dev->driver->resume(dev);
5330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
5340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (dev->driver->suspend)
5350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			dev->driver->suspend(dev, otg_suspend_state);
5360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
5370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
5390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
5400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
5420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Called by initialization code of host driver.  Register host controller
5430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * to the OTG.  Suspend host for OTG role detection.
5440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
5457e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerusstatic int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
5460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
5477e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
5480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5497e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg || otg_dev != fsl_otg_dev)
5500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
5510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5527e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	otg->host = host;
5530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->fsm.a_bus_drop = 0;
5550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->fsm.a_bus_req = 1;
5560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (host) {
5580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		VDBG("host off......\n");
5590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5607e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		otg->host->otg_port = fsl_otg_initdata.otg_port;
5617e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		otg->host->is_b_host = otg_dev->fsm.id;
5620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/*
5630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		 * must leave time for khubd to finish its thing
5640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		 * before yanking the host driver out from under it,
5650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		 * so suspend the host after a short delay.
5660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		 */
5670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_dev->host_working = 1;
5680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		schedule_delayed_work(&otg_dev->otg_event, 100);
5690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return 0;
5700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
5710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* host driver going away */
5720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) &
5730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		      OTGSC_STS_USB_ID)) {
5740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			/* Mini-A cable connected */
5750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			struct otg_fsm *fsm = &otg_dev->fsm;
5760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5777e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus			otg->phy->state = OTG_STATE_UNDEFINED;
5780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->protocol = PROTO_UNDEF;
5790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		}
5800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
5810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->host_working = 0;
5830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_statemachine(&otg_dev->fsm);
5850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
5870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
5880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Called by initialization code of udc.  Register udc to OTG. */
5907e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerusstatic int fsl_otg_set_peripheral(struct usb_otg *otg,
5917e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus					struct usb_gadget *gadget)
5920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
5937e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
5940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	VDBG("otg_dev 0x%x\n", (int)otg_dev);
5960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
5970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
5987e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg || otg_dev != fsl_otg_dev)
5990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
6000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!gadget) {
6027e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		if (!otg->default_a)
6037e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus			otg->gadget->ops->vbus_draw(otg->gadget, 0);
6047e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		usb_gadget_vbus_disconnect(otg->gadget);
6057e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		otg->gadget = 0;
6060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_dev->fsm.b_bus_req = 0;
6070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_statemachine(&otg_dev->fsm);
6080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return 0;
6090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
6100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6117e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	otg->gadget = gadget;
6127e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
6130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->fsm.b_bus_req = 1;
6150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* start the gadget right away if the ID pin says Mini-B */
6170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	DBG("ID pin=%d\n", otg_dev->fsm.id);
6180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (otg_dev->fsm.id == 1) {
6190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_start_host(&otg_dev->fsm, 0);
6200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_drv_vbus(&otg_dev->fsm, 0);
6210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_start_gadget(&otg_dev->fsm, 1);
6220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
6230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
6250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
6260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Set OTG port power, only for B-device */
6287e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerusstatic int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
6290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
6300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!fsl_otg_dev)
6310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
6327e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (phy->state == OTG_STATE_B_PERIPHERAL)
6330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		pr_info("FSL OTG: Draw %d mA\n", mA);
6340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
6360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
6370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
6390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Delayed pin detect interrupt processing.
6400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang *
6410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * When the Mini-A cable is disconnected from the board,
64242b2aa86c6670347a2a07e6d7af0e0ecc8fdbff9Justin P. Mattock * the pin-detect interrupt happens before the disconnect
6430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * interrupts for the connected device(s).  In order to
6440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * process the disconnect interrupt(s) prior to switching
6450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * roles, the pin-detect interrupts are delayed, and handled
6460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * by this routine.
6470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
6480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic void fsl_otg_event(struct work_struct *work)
6490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
6500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
6510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct otg_fsm *fsm = &og->fsm;
6520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (fsm->id) {		/* switch to gadget */
6540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_start_host(fsm, 0);
6550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		otg_drv_vbus(fsm, 0);
6560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_start_gadget(fsm, 1);
6570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
6580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
6590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* B-device start SRP */
6617e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerusstatic int fsl_otg_start_srp(struct usb_otg *otg)
6620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
6637e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
6640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6657e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg || otg_dev != fsl_otg_dev
6667e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	    || otg->phy->state != OTG_STATE_B_IDLE)
6670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
6680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->fsm.b_bus_req = 1;
6700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_statemachine(&otg_dev->fsm);
6710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
6730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
6740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* A_host suspend will call this function to start hnp */
6767e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerusstatic int fsl_otg_start_hnp(struct usb_otg *otg)
6770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
6787e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
6790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6807e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!otg || otg_dev != fsl_otg_dev)
6810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
6820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	DBG("start_hnp...n");
6840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* clear a_bus_req to enter a_suspend state */
6860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_dev->fsm.a_bus_req = 0;
6870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_statemachine(&otg_dev->fsm);
6880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
6900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
6910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
6920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
6930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Interrupt handler.  OTG/host/peripheral share the same int line.
6940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * OTG driver clears OTGSC interrupts and leaves USB interrupts
6950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * intact.  It needs to have knowledge of some USB interrupts
6960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * such as port change.
6970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
6980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangirqreturn_t fsl_otg_isr(int irq, void *dev_id)
6990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
7000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
7017e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
7020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 otg_int_src, otg_sc;
7030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_sc = fsl_readl(&usb_dr_regs->otgsc);
7050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8);
7060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Only clear otg interrupts */
7080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(otg_sc, &usb_dr_regs->otgsc);
7090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/*FIXME: ID change not generate when init to 0 */
7110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
7120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg->default_a = (fsm->id == 0);
7130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* process OTG interrupts */
7150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (otg_int_src) {
7160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		if (otg_int_src & OTGSC_INTSTS_USB_ID) {
7170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
7180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			otg->default_a = (fsm->id == 0);
7190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			/* clear conn information */
7200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (fsm->id)
7210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				fsm->b_conn = 0;
7220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			else
7230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				fsm->a_conn = 0;
7240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (otg->host)
7260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				otg->host->is_b_host = fsm->id;
7270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (otg->gadget)
7280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				otg->gadget->is_a_peripheral = !fsm->id;
7290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			VDBG("ID int (ID is %d)\n", fsm->id);
7300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			if (fsm->id) {	/* switch to gadget */
7320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				schedule_delayed_work(
7330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					&((struct fsl_otg *)dev_id)->otg_event,
7340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang					100);
7350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			} else {	/* switch to host */
7360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				cancel_delayed_work(&
7370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang						    ((struct fsl_otg *)dev_id)->
7380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang						    otg_event);
7390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				fsl_otg_start_gadget(fsm, 0);
7400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				otg_drv_vbus(fsm, 1);
7410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				fsl_otg_start_host(fsm, 1);
7420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			}
7430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			return IRQ_HANDLED;
7440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		}
7450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
7460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return IRQ_NONE;
7470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
7480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic struct otg_fsm_ops fsl_otg_ops = {
7500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.chrg_vbus = fsl_otg_chrg_vbus,
7510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.drv_vbus = fsl_otg_drv_vbus,
7520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.loc_conn = fsl_otg_loc_conn,
7530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.loc_sof = fsl_otg_loc_sof,
7540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.start_pulse = fsl_otg_start_pulse,
7550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.add_timer = fsl_otg_add_timer,
7570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.del_timer = fsl_otg_del_timer,
7580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.start_host = fsl_otg_start_host,
7600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.start_gadget = fsl_otg_start_gadget,
7610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang};
7620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Initialize the global variable fsl_otg_dev and request IRQ for OTG */
7640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int fsl_otg_conf(struct platform_device *pdev)
7650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
7660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg *fsl_otg_tc;
7670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	int status;
7680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (fsl_otg_dev)
7700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return 0;
7710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* allocate space to fsl otg device */
7730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_tc = kzalloc(sizeof(struct fsl_otg), GFP_KERNEL);
7740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!fsl_otg_tc)
7750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENOMEM;
7760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7777e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
7787e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	if (!fsl_otg_tc->phy.otg) {
7797e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		kfree(fsl_otg_tc);
7807e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		return -ENOMEM;
7817e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	}
7827e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus
7830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
7840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	INIT_LIST_HEAD(&active_timers);
7860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	status = fsl_otg_init_timers(&fsl_otg_tc->fsm);
7870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (status) {
7880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		pr_info("Couldn't init OTG timers\n");
7890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		goto err;
7900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
7910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	spin_lock_init(&fsl_otg_tc->fsm.lock);
7920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Set OTG state machine operations */
7940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_tc->fsm.ops = &fsl_otg_ops;
7950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
7960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* initialize the otg structure */
7977e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.label = DRIVER_DESC;
7987e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.set_power = fsl_otg_set_power;
7997e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus
8007e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
8017e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
8027e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
8037e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
8047e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp;
8050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_dev = fsl_otg_tc;
8070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Store the otg transceiver */
8097e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	status = usb_set_transceiver(&fsl_otg_tc->phy);
8100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (status) {
8110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
8120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		goto err;
8130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
8140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
8160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangerr:
8170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_uninit_timers();
8187e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	kfree(fsl_otg_tc->phy.otg);
8190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	kfree(fsl_otg_tc);
8200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return status;
8210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
8220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* OTG Initialization */
8240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangint usb_otg_start(struct platform_device *pdev)
8250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
8260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_otg *p_otg;
8277e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	struct usb_phy *otg_trans = usb_get_transceiver();
8280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct otg_fsm *fsm;
8290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	int status;
8300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct resource *res;
8310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 temp;
8320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
8330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8347e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	p_otg = container_of(otg_trans, struct fsl_otg, phy);
8350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsm = &p_otg->fsm;
8360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Initialize the state machine structure with default values */
8380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
8397e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	fsm->otg = p_otg->phy.otg;
8400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* We don't require predefined MEM/IRQ resource index */
8420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!res)
8440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENXIO;
8450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* We don't request_mem_region here to enable resource sharing
8470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * with host/device */
8480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	usb_dr_regs = ioremap(res->start, sizeof(struct usb_dr_mmap));
8500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	p_otg->dr_mem_map = (struct usb_dr_mmap *)usb_dr_regs;
8510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	pdata->regs = (void *)usb_dr_regs;
8520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (pdata->init && pdata->init(pdev) != 0)
8540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -EINVAL;
8550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (pdata->big_endian_mmio) {
8570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		_fsl_readl = _fsl_readl_be;
8580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		_fsl_writel = _fsl_writel_be;
8590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
8600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		_fsl_readl = _fsl_readl_le;
8610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		_fsl_writel = _fsl_writel_le;
8620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
8630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* request irq */
8650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	p_otg->irq = platform_get_irq(pdev, 0);
8660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	status = request_irq(p_otg->irq, fsl_otg_isr,
8670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				IRQF_SHARED, driver_name, p_otg);
8680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (status) {
8697e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n",
8700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			p_otg->irq, status);
8710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		iounmap(p_otg->dr_mem_map);
8727e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		kfree(p_otg->phy.otg);
8730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		kfree(p_otg);
8740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return status;
8750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
8760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* stop the controller */
8780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
8790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp &= ~USB_CMD_RUN_STOP;
8800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
8810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* reset the controller */
8830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = fsl_readl(&p_otg->dr_mem_map->usbcmd);
8840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp |= USB_CMD_CTRL_RESET;
8850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->usbcmd);
8860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* wait reset completed */
8880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	while (fsl_readl(&p_otg->dr_mem_map->usbcmd) & USB_CMD_CTRL_RESET)
8890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		;
8900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* configure the VBUSHS as IDLE(both host and device) */
8920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USB_MODE_ES : 0);
8930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->usbmode);
8940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
8950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* configure PHY interface */
8960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = fsl_readl(&p_otg->dr_mem_map->portsc);
8970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW);
8980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	switch (pdata->phy_mode) {
8990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case FSL_USB2_PHY_ULPI:
9000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp |= PORTSC_PTS_ULPI;
9010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
9020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case FSL_USB2_PHY_UTMI_WIDE:
9030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp |= PORTSC_PTW_16BIT;
9040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* fall through */
9050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case FSL_USB2_PHY_UTMI:
9060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp |= PORTSC_PTS_UTMI;
9070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* fall through */
9080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	default:
9090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
9100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
9110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->portsc);
9120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (pdata->have_sysif_regs) {
9140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		/* configure control enable IO output, big endian register */
9150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp = __raw_readl(&p_otg->dr_mem_map->control);
9160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		temp |= USB_CTRL_IOENB;
9170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		__raw_writel(temp, &p_otg->dr_mem_map->control);
9180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
9190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* disable all interrupt and clear all OTGSC status */
9210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
9220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK;
9230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE;
9240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
9250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/*
9270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * The identification (id) input is FALSE when a Mini-A plug is inserted
9280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * in the devices Mini-AB receptacle. Otherwise, this input is TRUE.
9290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 * Also: record initial state of ID pin
9300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	 */
9310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
9327e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		p_otg->phy.state = OTG_STATE_UNDEFINED;
9330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		p_otg->fsm.id = 1;
9340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	} else {
9357e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		p_otg->phy.state = OTG_STATE_A_IDLE;
9360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		p_otg->fsm.id = 0;
9370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
9380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	DBG("initial ID pin=%d\n", p_otg->fsm.id);
9400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* enable OTG ID pin interrupt */
9420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
9430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp |= OTGSC_INTR_USB_ID_EN;
9440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN);
9450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_writel(temp, &p_otg->dr_mem_map->otgsc);
9460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
9480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
9490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
9510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * state file in sysfs
9520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
9530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int show_fsl_usb2_otg_state(struct device *dev,
9540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang				   struct device_attribute *attr, char *buf)
9550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
9560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct otg_fsm *fsm = &fsl_otg_dev->fsm;
9570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	char *next = buf;
9580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	unsigned size = PAGE_SIZE;
9590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	unsigned long flags;
9600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	int t;
9610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	spin_lock_irqsave(&fsm->lock, flags);
9630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* basic driver infomation */
9650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	t = scnprintf(next, size,
9660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n",
9670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			DRIVER_VERSION);
9680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	size -= t;
9690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	next += t;
9700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* Registers */
9720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	t = scnprintf(next, size,
9730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"OTGSC:   0x%08x\n"
9740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"PORTSC:  0x%08x\n"
9750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"USBMODE: 0x%08x\n"
9760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"USBCMD:  0x%08x\n"
9770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"USBSTS:  0x%08x\n"
9780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"USBINTR: 0x%08x\n",
9790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->otgsc),
9800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->portsc),
9810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->usbmode),
9820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->usbcmd),
9830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->usbsts),
9840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsl_readl(&usb_dr_regs->usbintr));
9850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	size -= t;
9860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	next += t;
9870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* State */
9890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	t = scnprintf(next, size,
9900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		      "OTG state: %s\n\n",
9917e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus		      otg_state_string(fsl_otg_dev->phy.state));
9920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	size -= t;
9930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	next += t;
9940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
9950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* State Machine Variables */
9960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	t = scnprintf(next, size,
9970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_bus_req: %d\n"
9980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_bus_req: %d\n"
9990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_bus_resume: %d\n"
10000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_bus_suspend: %d\n"
10010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_conn: %d\n"
10020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_sess_vld: %d\n"
10030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_srp_det: %d\n"
10040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"a_vbus_vld: %d\n"
10050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_bus_resume: %d\n"
10060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_bus_suspend: %d\n"
10070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_conn: %d\n"
10080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_se0_srp: %d\n"
10090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_sess_end: %d\n"
10100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"b_sess_vld: %d\n"
10110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			"id: %d\n",
10120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_bus_req,
10130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_bus_req,
10140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_bus_resume,
10150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_bus_suspend,
10160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_conn,
10170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_sess_vld,
10180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_srp_det,
10190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->a_vbus_vld,
10200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_bus_resume,
10210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_bus_suspend,
10220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_conn,
10230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_se0_srp,
10240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_sess_end,
10250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->b_sess_vld,
10260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			fsm->id);
10270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	size -= t;
10280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	next += t;
10290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	spin_unlock_irqrestore(&fsm->lock, flags);
10310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return PAGE_SIZE - size;
10330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
10340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL);
10360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10370807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/* Char driver interface to control some OTG input */
10390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang/*
10410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * Handle some ioctl command, such as get otg
10420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang * status and set host suspend
10430807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang */
10440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic long fsl_otg_ioctl(struct file *file, unsigned int cmd,
10450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang			  unsigned long arg)
10460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
10470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	u32 retval = 0;
10480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	switch (cmd) {
10500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case GET_OTG_STATUS:
10510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		retval = fsl_otg_dev->host_working;
10520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case SET_A_SUSPEND_REQ:
10550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_dev->fsm.a_suspend_req = arg;
10560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case SET_A_BUS_DROP:
10590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_dev->fsm.a_bus_drop = arg;
10600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case SET_A_BUS_REQ:
10630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_dev->fsm.a_bus_req = arg;
10640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10650807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	case SET_B_BUS_REQ:
10670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		fsl_otg_dev->fsm.b_bus_req = arg;
10680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10700807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	default:
10710807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		break;
10720807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
10730807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10740807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	otg_statemachine(&fsl_otg_dev->fsm);
10750807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10760807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return retval;
10770807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
10780807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10790807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int fsl_otg_open(struct inode *inode, struct file *file)
10800807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
10810807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
10820807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
10830807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10840807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int fsl_otg_release(struct inode *inode, struct file *file)
10850807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
10860807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
10870807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
10880807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10890807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic const struct file_operations otg_fops = {
10900807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.owner = THIS_MODULE,
10910807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.llseek = NULL,
10920807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.read = NULL,
10930807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.write = NULL,
10940807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.unlocked_ioctl = fsl_otg_ioctl,
10950807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.open = fsl_otg_open,
10960807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.release = fsl_otg_release,
10970807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang};
10980807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
10990807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int __devinit fsl_otg_probe(struct platform_device *pdev)
11000807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
11010807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	int ret;
11020807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11030807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (!pdev->dev.platform_data)
11040807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return -ENODEV;
11050807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11060807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* configure the OTG */
11070807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	ret = fsl_otg_conf(pdev);
11080807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (ret) {
11090807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		dev_err(&pdev->dev, "Couldn't configure OTG module\n");
11100807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return ret;
11110807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
11120807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11130807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	/* start OTG */
11140807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	ret = usb_otg_start(pdev);
11150807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (ret) {
11160807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		dev_err(&pdev->dev, "Can't init FSL OTG device\n");
11170807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return ret;
11180807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
11190807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11200807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	ret = register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops);
11210807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (ret) {
11220807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		dev_err(&pdev->dev, "unable to register FSL OTG device\n");
11230807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		return ret;
11240807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	}
11250807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11260807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	ret = device_create_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
11270807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (ret)
11280807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
11290807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11300807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return ret;
11310807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
11320807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11330807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstatic int __devexit fsl_otg_remove(struct platform_device *pdev)
11340807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang{
11350807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
11360807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11377e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	usb_set_transceiver(NULL);
11380807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	free_irq(fsl_otg_dev->irq, fsl_otg_dev);
11390807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11400807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	iounmap((void *)usb_dr_regs);
11410807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11420807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	fsl_otg_uninit_timers();
11437e062c0f8888001d28cf74da0c3d16a651bd7489Heikki Krogerus	kfree(fsl_otg_dev->phy.otg);
11440807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	kfree(fsl_otg_dev);
11450807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11460807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
11470807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11480807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME);
11490807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11500807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	if (pdata->exit)
11510807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		pdata->exit(pdev);
11520807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11530807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	return 0;
11540807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang}
11550807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11560807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yangstruct platform_driver fsl_otg_driver = {
11570807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.probe = fsl_otg_probe,
11580807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.remove = __devexit_p(fsl_otg_remove),
11590807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	.driver = {
11600807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		.name = driver_name,
11610807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang		.owner = THIS_MODULE,
11620807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang	},
11630807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang};
11640807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
1165cc27c96c2bee93068bfc60ea6b09611d88cef429Axel Linmodule_platform_driver(fsl_otg_driver);
11660807c500a1a6d7fa20cbd7bbe7fea14a66112463Li Yang
11670807c500a1a6d7fa20cbd7bbe7fea14a66112463Li YangMODULE_DESCRIPTION(DRIVER_INFO);
11680807c500a1a6d7fa20cbd7bbe7fea14a66112463Li YangMODULE_AUTHOR(DRIVER_AUTHOR);
11690807c500a1a6d7fa20cbd7bbe7fea14a66112463Li YangMODULE_LICENSE("GPL");
1170