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