1e443b333SAlexander Shishkin /* 2e443b333SAlexander Shishkin * core.c - ChipIdea USB IP core family device controller 3e443b333SAlexander Shishkin * 4e443b333SAlexander Shishkin * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. 5e443b333SAlexander Shishkin * 6e443b333SAlexander Shishkin * Author: David Lopo 7e443b333SAlexander Shishkin * 8e443b333SAlexander Shishkin * This program is free software; you can redistribute it and/or modify 9e443b333SAlexander Shishkin * it under the terms of the GNU General Public License version 2 as 10e443b333SAlexander Shishkin * published by the Free Software Foundation. 11e443b333SAlexander Shishkin */ 12e443b333SAlexander Shishkin 13e443b333SAlexander Shishkin /* 14e443b333SAlexander Shishkin * Description: ChipIdea USB IP core family device controller 15e443b333SAlexander Shishkin * 16e443b333SAlexander Shishkin * This driver is composed of several blocks: 17e443b333SAlexander Shishkin * - HW: hardware interface 18e443b333SAlexander Shishkin * - DBG: debug facilities (optional) 19e443b333SAlexander Shishkin * - UTIL: utilities 20e443b333SAlexander Shishkin * - ISR: interrupts handling 21e443b333SAlexander Shishkin * - ENDPT: endpoint operations (Gadget API) 22e443b333SAlexander Shishkin * - GADGET: gadget operations (Gadget API) 23e443b333SAlexander Shishkin * - BUS: bus glue code, bus abstraction layer 24e443b333SAlexander Shishkin * 25e443b333SAlexander Shishkin * Compile Options 2658ce8499SPeter Chen * - CONFIG_USB_CHIPIDEA_DEBUG: enable debug facilities 27e443b333SAlexander Shishkin * - STALL_IN: non-empty bulk-in pipes cannot be halted 28e443b333SAlexander Shishkin * if defined mass storage compliance succeeds but with warnings 29e443b333SAlexander Shishkin * => case 4: Hi > Dn 30e443b333SAlexander Shishkin * => case 5: Hi > Di 31e443b333SAlexander Shishkin * => case 8: Hi <> Do 32e443b333SAlexander Shishkin * if undefined usbtest 13 fails 33e443b333SAlexander Shishkin * - TRACE: enable function tracing (depends on DEBUG) 34e443b333SAlexander Shishkin * 35e443b333SAlexander Shishkin * Main Features 36e443b333SAlexander Shishkin * - Chapter 9 & Mass Storage Compliance with Gadget File Storage 37e443b333SAlexander Shishkin * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) 38e443b333SAlexander Shishkin * - Normal & LPM support 39e443b333SAlexander Shishkin * 40e443b333SAlexander Shishkin * USBTEST Report 41e443b333SAlexander Shishkin * - OK: 0-12, 13 (STALL_IN defined) & 14 42e443b333SAlexander Shishkin * - Not Supported: 15 & 16 (ISO) 43e443b333SAlexander Shishkin * 44e443b333SAlexander Shishkin * TODO List 45e443b333SAlexander Shishkin * - Suspend & Remote Wakeup 46e443b333SAlexander Shishkin */ 47e443b333SAlexander Shishkin #include <linux/delay.h> 48e443b333SAlexander Shishkin #include <linux/device.h> 49e443b333SAlexander Shishkin #include <linux/dma-mapping.h> 501e5e2d3dSAntoine Tenart #include <linux/phy/phy.h> 51e443b333SAlexander Shishkin #include <linux/platform_device.h> 52e443b333SAlexander Shishkin #include <linux/module.h> 53fe6e125eSRichard Zhao #include <linux/idr.h> 54e443b333SAlexander Shishkin #include <linux/interrupt.h> 55e443b333SAlexander Shishkin #include <linux/io.h> 56e443b333SAlexander Shishkin #include <linux/kernel.h> 57e443b333SAlexander Shishkin #include <linux/slab.h> 58e443b333SAlexander Shishkin #include <linux/pm_runtime.h> 59e443b333SAlexander Shishkin #include <linux/usb/ch9.h> 60e443b333SAlexander Shishkin #include <linux/usb/gadget.h> 61e443b333SAlexander Shishkin #include <linux/usb/otg.h> 62e443b333SAlexander Shishkin #include <linux/usb/chipidea.h> 6340dcd0e8SMichael Grzeschik #include <linux/usb/of.h> 644f6743d5SMichael Grzeschik #include <linux/of.h> 6540dcd0e8SMichael Grzeschik #include <linux/phy.h> 661542d9c3SPeter Chen #include <linux/regulator/consumer.h> 67e443b333SAlexander Shishkin 68e443b333SAlexander Shishkin #include "ci.h" 69e443b333SAlexander Shishkin #include "udc.h" 70e443b333SAlexander Shishkin #include "bits.h" 71eb70e5abSAlexander Shishkin #include "host.h" 72e443b333SAlexander Shishkin #include "debug.h" 73c10b4f03SPeter Chen #include "otg.h" 744dcf720cSLi Jun #include "otg_fsm.h" 75e443b333SAlexander Shishkin 765f36e231SAlexander Shishkin /* Controller register map */ 77987e7bc3SMarc Kleine-Budde static const u8 ci_regs_nolpm[] = { 78987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 79987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 80987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 81987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0x38U, 82987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 83987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 84987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 85987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 86987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 87987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 88987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 89987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0x64U, 90987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0x68U, 91987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0x6CU, 92987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0x70U, 93987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0x74U, 94987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0x78U, 95987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0x7CU, 96987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0x80U, 97e443b333SAlexander Shishkin }; 98e443b333SAlexander Shishkin 99987e7bc3SMarc Kleine-Budde static const u8 ci_regs_lpm[] = { 100987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 101987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 102987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 103987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0xFCU, 104987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 105987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 106987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 107987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 108987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 109987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 110987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 111987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0xC4U, 112987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0xC8U, 113987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0xD8U, 114987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0xDCU, 115987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0xE0U, 116987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0xE4U, 117987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0xE8U, 118987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0xECU, 119e443b333SAlexander Shishkin }; 120e443b333SAlexander Shishkin 1218e22978cSAlexander Shishkin static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) 122e443b333SAlexander Shishkin { 123e443b333SAlexander Shishkin int i; 124e443b333SAlexander Shishkin 125e443b333SAlexander Shishkin for (i = 0; i < OP_ENDPTCTRL; i++) 1265f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = 1275f36e231SAlexander Shishkin (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + 128e443b333SAlexander Shishkin (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); 129e443b333SAlexander Shishkin 130e443b333SAlexander Shishkin for (; i <= OP_LAST; i++) 1315f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = ci->hw_bank.op + 132e443b333SAlexander Shishkin 4 * (i - OP_ENDPTCTRL) + 133e443b333SAlexander Shishkin (is_lpm 134e443b333SAlexander Shishkin ? ci_regs_lpm[OP_ENDPTCTRL] 135e443b333SAlexander Shishkin : ci_regs_nolpm[OP_ENDPTCTRL]); 136e443b333SAlexander Shishkin 137e443b333SAlexander Shishkin return 0; 138e443b333SAlexander Shishkin } 139e443b333SAlexander Shishkin 140cb271f3cSPeter Chen static enum ci_revision ci_get_revision(struct ci_hdrc *ci) 141cb271f3cSPeter Chen { 142cb271f3cSPeter Chen int ver = hw_read_id_reg(ci, ID_ID, VERSION) >> __ffs(VERSION); 143cb271f3cSPeter Chen enum ci_revision rev = CI_REVISION_UNKNOWN; 144cb271f3cSPeter Chen 145cb271f3cSPeter Chen if (ver == 0x2) { 146cb271f3cSPeter Chen rev = hw_read_id_reg(ci, ID_ID, REVISION) 147cb271f3cSPeter Chen >> __ffs(REVISION); 148cb271f3cSPeter Chen rev += CI_REVISION_20; 149cb271f3cSPeter Chen } else if (ver == 0x0) { 150cb271f3cSPeter Chen rev = CI_REVISION_1X; 151cb271f3cSPeter Chen } 152cb271f3cSPeter Chen 153cb271f3cSPeter Chen return rev; 154cb271f3cSPeter Chen } 155cb271f3cSPeter Chen 156e443b333SAlexander Shishkin /** 15736304b06SLi Jun * hw_read_intr_enable: returns interrupt enable register 15836304b06SLi Jun * 15919353881SPeter Chen * @ci: the controller 16019353881SPeter Chen * 16136304b06SLi Jun * This function returns register data 16236304b06SLi Jun */ 16336304b06SLi Jun u32 hw_read_intr_enable(struct ci_hdrc *ci) 16436304b06SLi Jun { 16536304b06SLi Jun return hw_read(ci, OP_USBINTR, ~0); 16636304b06SLi Jun } 16736304b06SLi Jun 16836304b06SLi Jun /** 16936304b06SLi Jun * hw_read_intr_status: returns interrupt status register 17036304b06SLi Jun * 17119353881SPeter Chen * @ci: the controller 17219353881SPeter Chen * 17336304b06SLi Jun * This function returns register data 17436304b06SLi Jun */ 17536304b06SLi Jun u32 hw_read_intr_status(struct ci_hdrc *ci) 17636304b06SLi Jun { 17736304b06SLi Jun return hw_read(ci, OP_USBSTS, ~0); 17836304b06SLi Jun } 17936304b06SLi Jun 18036304b06SLi Jun /** 181e443b333SAlexander Shishkin * hw_port_test_set: writes port test mode (execute without interruption) 182e443b333SAlexander Shishkin * @mode: new value 183e443b333SAlexander Shishkin * 184e443b333SAlexander Shishkin * This function returns an error code 185e443b333SAlexander Shishkin */ 1868e22978cSAlexander Shishkin int hw_port_test_set(struct ci_hdrc *ci, u8 mode) 187e443b333SAlexander Shishkin { 188e443b333SAlexander Shishkin const u8 TEST_MODE_MAX = 7; 189e443b333SAlexander Shishkin 190e443b333SAlexander Shishkin if (mode > TEST_MODE_MAX) 191e443b333SAlexander Shishkin return -EINVAL; 192e443b333SAlexander Shishkin 193727b4ddbSFelipe Balbi hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC)); 194e443b333SAlexander Shishkin return 0; 195e443b333SAlexander Shishkin } 196e443b333SAlexander Shishkin 197e443b333SAlexander Shishkin /** 198e443b333SAlexander Shishkin * hw_port_test_get: reads port test mode value 199e443b333SAlexander Shishkin * 20019353881SPeter Chen * @ci: the controller 20119353881SPeter Chen * 202e443b333SAlexander Shishkin * This function returns port test mode value 203e443b333SAlexander Shishkin */ 2048e22978cSAlexander Shishkin u8 hw_port_test_get(struct ci_hdrc *ci) 205e443b333SAlexander Shishkin { 206727b4ddbSFelipe Balbi return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); 207e443b333SAlexander Shishkin } 208e443b333SAlexander Shishkin 209b82613cfSPeter Chen static void hw_wait_phy_stable(void) 210b82613cfSPeter Chen { 211b82613cfSPeter Chen /* 212b82613cfSPeter Chen * The phy needs some delay to output the stable status from low 213b82613cfSPeter Chen * power mode. And for OTGSC, the status inputs are debounced 214b82613cfSPeter Chen * using a 1 ms time constant, so, delay 2ms for controller to get 215b82613cfSPeter Chen * the stable status, like vbus and id when the phy leaves low power. 216b82613cfSPeter Chen */ 217b82613cfSPeter Chen usleep_range(2000, 2500); 218b82613cfSPeter Chen } 219b82613cfSPeter Chen 220864cf949SPeter Chen /* The PHY enters/leaves low power mode */ 221864cf949SPeter Chen static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) 222864cf949SPeter Chen { 223864cf949SPeter Chen enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; 224864cf949SPeter Chen bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); 225864cf949SPeter Chen 2266d037db6SPeter Chen if (enable && !lpm) 227864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 228864cf949SPeter Chen PORTSC_PHCD(ci->hw_bank.lpm)); 2296d037db6SPeter Chen else if (!enable && lpm) 230864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 231864cf949SPeter Chen 0); 232864cf949SPeter Chen } 233864cf949SPeter Chen 2348e22978cSAlexander Shishkin static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) 235e443b333SAlexander Shishkin { 236e443b333SAlexander Shishkin u32 reg; 237e443b333SAlexander Shishkin 238e443b333SAlexander Shishkin /* bank is a module variable */ 2395f36e231SAlexander Shishkin ci->hw_bank.abs = base; 240e443b333SAlexander Shishkin 2415f36e231SAlexander Shishkin ci->hw_bank.cap = ci->hw_bank.abs; 24277c4400fSRichard Zhao ci->hw_bank.cap += ci->platdata->capoffset; 243938d323fSSvetoslav Neykov ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); 244e443b333SAlexander Shishkin 2455f36e231SAlexander Shishkin hw_alloc_regmap(ci, false); 2465f36e231SAlexander Shishkin reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> 247727b4ddbSFelipe Balbi __ffs(HCCPARAMS_LEN); 2485f36e231SAlexander Shishkin ci->hw_bank.lpm = reg; 249aeb2c121SChris Ruehl if (reg) 2505f36e231SAlexander Shishkin hw_alloc_regmap(ci, !!reg); 2515f36e231SAlexander Shishkin ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; 2525f36e231SAlexander Shishkin ci->hw_bank.size += OP_LAST; 2535f36e231SAlexander Shishkin ci->hw_bank.size /= sizeof(u32); 254e443b333SAlexander Shishkin 2555f36e231SAlexander Shishkin reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> 256727b4ddbSFelipe Balbi __ffs(DCCPARAMS_DEN); 2575f36e231SAlexander Shishkin ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 258e443b333SAlexander Shishkin 25909c94e62SRichard Zhao if (ci->hw_ep_max > ENDPT_MAX) 260e443b333SAlexander Shishkin return -ENODEV; 261e443b333SAlexander Shishkin 262864cf949SPeter Chen ci_hdrc_enter_lpm(ci, false); 263864cf949SPeter Chen 264c344b518SPeter Chen /* Disable all interrupts bits */ 265c344b518SPeter Chen hw_write(ci, OP_USBINTR, 0xffffffff, 0); 266c344b518SPeter Chen 267c344b518SPeter Chen /* Clear all interrupts status bits*/ 268c344b518SPeter Chen hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff); 269c344b518SPeter Chen 270cb271f3cSPeter Chen ci->rev = ci_get_revision(ci); 271cb271f3cSPeter Chen 272cb271f3cSPeter Chen dev_dbg(ci->dev, 273cb271f3cSPeter Chen "ChipIdea HDRC found, revision: %d, lpm: %d; cap: %p op: %p\n", 274cb271f3cSPeter Chen ci->rev, ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); 275e443b333SAlexander Shishkin 276e443b333SAlexander Shishkin /* setup lock mode ? */ 277e443b333SAlexander Shishkin 278e443b333SAlexander Shishkin /* ENDPTSETUPSTAT is '0' by default */ 279e443b333SAlexander Shishkin 280e443b333SAlexander Shishkin /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 281e443b333SAlexander Shishkin 282e443b333SAlexander Shishkin return 0; 283e443b333SAlexander Shishkin } 284e443b333SAlexander Shishkin 2858e22978cSAlexander Shishkin static void hw_phymode_configure(struct ci_hdrc *ci) 28640dcd0e8SMichael Grzeschik { 2873b5d3e68SChris Ruehl u32 portsc, lpm, sts = 0; 28840dcd0e8SMichael Grzeschik 28940dcd0e8SMichael Grzeschik switch (ci->platdata->phy_mode) { 29040dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMI: 29140dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI); 29240dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI); 29340dcd0e8SMichael Grzeschik break; 29440dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMIW: 29540dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW; 29640dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW; 29740dcd0e8SMichael Grzeschik break; 29840dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_ULPI: 29940dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_ULPI); 30040dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_ULPI); 30140dcd0e8SMichael Grzeschik break; 30240dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_SERIAL: 30340dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_SERIAL); 30440dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_SERIAL); 30540dcd0e8SMichael Grzeschik sts = 1; 30640dcd0e8SMichael Grzeschik break; 30740dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_HSIC: 30840dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_HSIC); 30940dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_HSIC); 31040dcd0e8SMichael Grzeschik break; 31140dcd0e8SMichael Grzeschik default: 31240dcd0e8SMichael Grzeschik return; 31340dcd0e8SMichael Grzeschik } 31440dcd0e8SMichael Grzeschik 31540dcd0e8SMichael Grzeschik if (ci->hw_bank.lpm) { 31640dcd0e8SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm); 3173b5d3e68SChris Ruehl if (sts) 3183b5d3e68SChris Ruehl hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS); 31940dcd0e8SMichael Grzeschik } else { 32040dcd0e8SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); 3213b5d3e68SChris Ruehl if (sts) 3223b5d3e68SChris Ruehl hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); 32340dcd0e8SMichael Grzeschik } 32440dcd0e8SMichael Grzeschik } 32540dcd0e8SMichael Grzeschik 326e443b333SAlexander Shishkin /** 3271e5e2d3dSAntoine Tenart * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy 3281e5e2d3dSAntoine Tenart * interfaces 3291e5e2d3dSAntoine Tenart * @ci: the controller 3301e5e2d3dSAntoine Tenart * 3311e5e2d3dSAntoine Tenart * This function returns an error code if the phy failed to init 3321e5e2d3dSAntoine Tenart */ 3331e5e2d3dSAntoine Tenart static int _ci_usb_phy_init(struct ci_hdrc *ci) 3341e5e2d3dSAntoine Tenart { 3351e5e2d3dSAntoine Tenart int ret; 3361e5e2d3dSAntoine Tenart 3371e5e2d3dSAntoine Tenart if (ci->phy) { 3381e5e2d3dSAntoine Tenart ret = phy_init(ci->phy); 3391e5e2d3dSAntoine Tenart if (ret) 3401e5e2d3dSAntoine Tenart return ret; 3411e5e2d3dSAntoine Tenart 3421e5e2d3dSAntoine Tenart ret = phy_power_on(ci->phy); 3431e5e2d3dSAntoine Tenart if (ret) { 3441e5e2d3dSAntoine Tenart phy_exit(ci->phy); 3451e5e2d3dSAntoine Tenart return ret; 3461e5e2d3dSAntoine Tenart } 3471e5e2d3dSAntoine Tenart } else { 3481e5e2d3dSAntoine Tenart ret = usb_phy_init(ci->usb_phy); 3491e5e2d3dSAntoine Tenart } 3501e5e2d3dSAntoine Tenart 3511e5e2d3dSAntoine Tenart return ret; 3521e5e2d3dSAntoine Tenart } 3531e5e2d3dSAntoine Tenart 3541e5e2d3dSAntoine Tenart /** 3551e5e2d3dSAntoine Tenart * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy 3561e5e2d3dSAntoine Tenart * interfaces 3571e5e2d3dSAntoine Tenart * @ci: the controller 3581e5e2d3dSAntoine Tenart */ 3591e5e2d3dSAntoine Tenart static void ci_usb_phy_exit(struct ci_hdrc *ci) 3601e5e2d3dSAntoine Tenart { 3611e5e2d3dSAntoine Tenart if (ci->phy) { 3621e5e2d3dSAntoine Tenart phy_power_off(ci->phy); 3631e5e2d3dSAntoine Tenart phy_exit(ci->phy); 3641e5e2d3dSAntoine Tenart } else { 3651e5e2d3dSAntoine Tenart usb_phy_shutdown(ci->usb_phy); 3661e5e2d3dSAntoine Tenart } 3671e5e2d3dSAntoine Tenart } 3681e5e2d3dSAntoine Tenart 3691e5e2d3dSAntoine Tenart /** 370d03cccffSPeter Chen * ci_usb_phy_init: initialize phy according to different phy type 371d03cccffSPeter Chen * @ci: the controller 372d03cccffSPeter Chen * 373d03cccffSPeter Chen * This function returns an error code if usb_phy_init has failed 374d03cccffSPeter Chen */ 375d03cccffSPeter Chen static int ci_usb_phy_init(struct ci_hdrc *ci) 376d03cccffSPeter Chen { 377d03cccffSPeter Chen int ret; 378d03cccffSPeter Chen 379d03cccffSPeter Chen switch (ci->platdata->phy_mode) { 380d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMI: 381d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMIW: 382d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_HSIC: 3831e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 384b82613cfSPeter Chen if (!ret) 385b82613cfSPeter Chen hw_wait_phy_stable(); 386b82613cfSPeter Chen else 387d03cccffSPeter Chen return ret; 388d03cccffSPeter Chen hw_phymode_configure(ci); 389d03cccffSPeter Chen break; 390d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_ULPI: 391d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_SERIAL: 392d03cccffSPeter Chen hw_phymode_configure(ci); 3931e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 394d03cccffSPeter Chen if (ret) 395d03cccffSPeter Chen return ret; 396d03cccffSPeter Chen break; 397d03cccffSPeter Chen default: 3981e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 399b82613cfSPeter Chen if (!ret) 400b82613cfSPeter Chen hw_wait_phy_stable(); 401d03cccffSPeter Chen } 402d03cccffSPeter Chen 403d03cccffSPeter Chen return ret; 404d03cccffSPeter Chen } 405d03cccffSPeter Chen 406d03cccffSPeter Chen /** 407cdd278f2SPeter Chen * hw_controller_reset: do controller reset 408cdd278f2SPeter Chen * @ci: the controller 409cdd278f2SPeter Chen * 410cdd278f2SPeter Chen * This function returns an error code 411cdd278f2SPeter Chen */ 412cdd278f2SPeter Chen static int hw_controller_reset(struct ci_hdrc *ci) 413cdd278f2SPeter Chen { 414cdd278f2SPeter Chen int count = 0; 415cdd278f2SPeter Chen 416cdd278f2SPeter Chen hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); 417cdd278f2SPeter Chen while (hw_read(ci, OP_USBCMD, USBCMD_RST)) { 418cdd278f2SPeter Chen udelay(10); 419cdd278f2SPeter Chen if (count++ > 1000) 420cdd278f2SPeter Chen return -ETIMEDOUT; 421cdd278f2SPeter Chen } 422cdd278f2SPeter Chen 423cdd278f2SPeter Chen return 0; 424cdd278f2SPeter Chen } 425cdd278f2SPeter Chen 426cdd278f2SPeter Chen /** 427e443b333SAlexander Shishkin * hw_device_reset: resets chip (execute without interruption) 428e443b333SAlexander Shishkin * @ci: the controller 429e443b333SAlexander Shishkin * 430e443b333SAlexander Shishkin * This function returns an error code 431e443b333SAlexander Shishkin */ 4325b157300SPeter Chen int hw_device_reset(struct ci_hdrc *ci) 433e443b333SAlexander Shishkin { 434cdd278f2SPeter Chen int ret; 435cdd278f2SPeter Chen 436e443b333SAlexander Shishkin /* should flush & stop before reset */ 437e443b333SAlexander Shishkin hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); 438e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 439e443b333SAlexander Shishkin 440cdd278f2SPeter Chen ret = hw_controller_reset(ci); 441cdd278f2SPeter Chen if (ret) { 442cdd278f2SPeter Chen dev_err(ci->dev, "error resetting controller, ret=%d\n", ret); 443cdd278f2SPeter Chen return ret; 444cdd278f2SPeter Chen } 445e443b333SAlexander Shishkin 44677c4400fSRichard Zhao if (ci->platdata->notify_event) 44777c4400fSRichard Zhao ci->platdata->notify_event(ci, 4488e22978cSAlexander Shishkin CI_HDRC_CONTROLLER_RESET_EVENT); 449e443b333SAlexander Shishkin 4508e22978cSAlexander Shishkin if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) 451758fc986SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); 452e443b333SAlexander Shishkin 4534f6743d5SMichael Grzeschik if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { 4544f6743d5SMichael Grzeschik if (ci->hw_bank.lpm) 4554f6743d5SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); 4564f6743d5SMichael Grzeschik else 4574f6743d5SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); 4584f6743d5SMichael Grzeschik } 4594f6743d5SMichael Grzeschik 460e443b333SAlexander Shishkin /* USBMODE should be configured step by step */ 461e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 4625b157300SPeter Chen hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); 463e443b333SAlexander Shishkin /* HW >= 2.3 */ 464e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); 465e443b333SAlexander Shishkin 4665b157300SPeter Chen if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) { 4675b157300SPeter Chen pr_err("cannot enter in %s device mode", ci_role(ci)->name); 468e443b333SAlexander Shishkin pr_err("lpm = %i", ci->hw_bank.lpm); 469e443b333SAlexander Shishkin return -ENODEV; 470e443b333SAlexander Shishkin } 471e443b333SAlexander Shishkin 472e443b333SAlexander Shishkin return 0; 473e443b333SAlexander Shishkin } 474e443b333SAlexander Shishkin 47522fa8445SPeter Chen /** 47622fa8445SPeter Chen * hw_wait_reg: wait the register value 47722fa8445SPeter Chen * 47822fa8445SPeter Chen * Sometimes, it needs to wait register value before going on. 47922fa8445SPeter Chen * Eg, when switch to device mode, the vbus value should be lower 48022fa8445SPeter Chen * than OTGSC_BSV before connects to host. 48122fa8445SPeter Chen * 48222fa8445SPeter Chen * @ci: the controller 48322fa8445SPeter Chen * @reg: register index 48422fa8445SPeter Chen * @mask: mast bit 48522fa8445SPeter Chen * @value: the bit value to wait 48622fa8445SPeter Chen * @timeout_ms: timeout in millisecond 48722fa8445SPeter Chen * 48822fa8445SPeter Chen * This function returns an error code if timeout 48922fa8445SPeter Chen */ 49022fa8445SPeter Chen int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, 49122fa8445SPeter Chen u32 value, unsigned int timeout_ms) 49222fa8445SPeter Chen { 49322fa8445SPeter Chen unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); 49422fa8445SPeter Chen 49522fa8445SPeter Chen while (hw_read(ci, reg, mask) != value) { 49622fa8445SPeter Chen if (time_after(jiffies, elapse)) { 49722fa8445SPeter Chen dev_err(ci->dev, "timeout waiting for %08x in %d\n", 49822fa8445SPeter Chen mask, reg); 49922fa8445SPeter Chen return -ETIMEDOUT; 50022fa8445SPeter Chen } 50122fa8445SPeter Chen msleep(20); 50222fa8445SPeter Chen } 50322fa8445SPeter Chen 50422fa8445SPeter Chen return 0; 50522fa8445SPeter Chen } 50622fa8445SPeter Chen 5075f36e231SAlexander Shishkin static irqreturn_t ci_irq(int irq, void *data) 5085f36e231SAlexander Shishkin { 5098e22978cSAlexander Shishkin struct ci_hdrc *ci = data; 5105f36e231SAlexander Shishkin irqreturn_t ret = IRQ_NONE; 511b183c19fSRichard Zhao u32 otgsc = 0; 5125f36e231SAlexander Shishkin 5131f874edcSPeter Chen if (ci->in_lpm) { 5141f874edcSPeter Chen disable_irq_nosync(irq); 5151f874edcSPeter Chen ci->wakeup_int = true; 5161f874edcSPeter Chen pm_runtime_get(ci->dev); 5171f874edcSPeter Chen return IRQ_HANDLED; 5181f874edcSPeter Chen } 5191f874edcSPeter Chen 5204dcf720cSLi Jun if (ci->is_otg) { 5210c33bf78SLi Jun otgsc = hw_read_otgsc(ci, ~0); 5224dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) { 5234dcf720cSLi Jun ret = ci_otg_fsm_irq(ci); 5244dcf720cSLi Jun if (ret == IRQ_HANDLED) 5254dcf720cSLi Jun return ret; 5264dcf720cSLi Jun } 5274dcf720cSLi Jun } 5285f36e231SAlexander Shishkin 529a107f8c5SPeter Chen /* 530a107f8c5SPeter Chen * Handle id change interrupt, it indicates device/host function 531a107f8c5SPeter Chen * switch. 532a107f8c5SPeter Chen */ 533a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { 534a107f8c5SPeter Chen ci->id_event = true; 5350c33bf78SLi Jun /* Clear ID change irq status */ 5360c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); 537be6b0c1bSPeter Chen ci_otg_queue_work(ci); 538a107f8c5SPeter Chen return IRQ_HANDLED; 5395f36e231SAlexander Shishkin } 5405f36e231SAlexander Shishkin 541a107f8c5SPeter Chen /* 542a107f8c5SPeter Chen * Handle vbus change interrupt, it indicates device connection 543a107f8c5SPeter Chen * and disconnection events. 544a107f8c5SPeter Chen */ 545a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { 546a107f8c5SPeter Chen ci->b_sess_valid_event = true; 5470c33bf78SLi Jun /* Clear BSV irq */ 5480c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); 549be6b0c1bSPeter Chen ci_otg_queue_work(ci); 550a107f8c5SPeter Chen return IRQ_HANDLED; 551a107f8c5SPeter Chen } 552a107f8c5SPeter Chen 553a107f8c5SPeter Chen /* Handle device/host interrupt */ 554a107f8c5SPeter Chen if (ci->role != CI_ROLE_END) 555a107f8c5SPeter Chen ret = ci_role(ci)->irq(ci); 556a107f8c5SPeter Chen 557b183c19fSRichard Zhao return ret; 5585f36e231SAlexander Shishkin } 5595f36e231SAlexander Shishkin 5601542d9c3SPeter Chen static int ci_get_platdata(struct device *dev, 5611542d9c3SPeter Chen struct ci_hdrc_platform_data *platdata) 5621542d9c3SPeter Chen { 563c22600c3SPeter Chen if (!platdata->phy_mode) 564c22600c3SPeter Chen platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); 565c22600c3SPeter Chen 566c22600c3SPeter Chen if (!platdata->dr_mode) 567c22600c3SPeter Chen platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); 568c22600c3SPeter Chen 569c22600c3SPeter Chen if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) 570c22600c3SPeter Chen platdata->dr_mode = USB_DR_MODE_OTG; 571c22600c3SPeter Chen 572c2ec3a73SPeter Chen if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { 573c2ec3a73SPeter Chen /* Get the vbus regulator */ 574c2ec3a73SPeter Chen platdata->reg_vbus = devm_regulator_get(dev, "vbus"); 575c2ec3a73SPeter Chen if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { 576c2ec3a73SPeter Chen return -EPROBE_DEFER; 577c2ec3a73SPeter Chen } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { 5786629467bSMickael Maison /* no vbus regulator is needed */ 579c2ec3a73SPeter Chen platdata->reg_vbus = NULL; 580c2ec3a73SPeter Chen } else if (IS_ERR(platdata->reg_vbus)) { 581c2ec3a73SPeter Chen dev_err(dev, "Getting regulator error: %ld\n", 582c2ec3a73SPeter Chen PTR_ERR(platdata->reg_vbus)); 583c2ec3a73SPeter Chen return PTR_ERR(platdata->reg_vbus); 584c2ec3a73SPeter Chen } 585f6a9ff07SPeter Chen /* Get TPL support */ 586f6a9ff07SPeter Chen if (!platdata->tpl_support) 587f6a9ff07SPeter Chen platdata->tpl_support = 588f6a9ff07SPeter Chen of_usb_host_tpl_support(dev->of_node); 589c2ec3a73SPeter Chen } 590c2ec3a73SPeter Chen 5914f6743d5SMichael Grzeschik if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) 5924f6743d5SMichael Grzeschik platdata->flags |= CI_HDRC_FORCE_FULLSPEED; 5934f6743d5SMichael Grzeschik 5941542d9c3SPeter Chen return 0; 5951542d9c3SPeter Chen } 5961542d9c3SPeter Chen 597fe6e125eSRichard Zhao static DEFINE_IDA(ci_ida); 598fe6e125eSRichard Zhao 5998e22978cSAlexander Shishkin struct platform_device *ci_hdrc_add_device(struct device *dev, 600cbc6dc2aSRichard Zhao struct resource *res, int nres, 6018e22978cSAlexander Shishkin struct ci_hdrc_platform_data *platdata) 602cbc6dc2aSRichard Zhao { 603cbc6dc2aSRichard Zhao struct platform_device *pdev; 604fe6e125eSRichard Zhao int id, ret; 605cbc6dc2aSRichard Zhao 6061542d9c3SPeter Chen ret = ci_get_platdata(dev, platdata); 6071542d9c3SPeter Chen if (ret) 6081542d9c3SPeter Chen return ERR_PTR(ret); 6091542d9c3SPeter Chen 610fe6e125eSRichard Zhao id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); 611fe6e125eSRichard Zhao if (id < 0) 612fe6e125eSRichard Zhao return ERR_PTR(id); 613fe6e125eSRichard Zhao 614fe6e125eSRichard Zhao pdev = platform_device_alloc("ci_hdrc", id); 615fe6e125eSRichard Zhao if (!pdev) { 616fe6e125eSRichard Zhao ret = -ENOMEM; 617fe6e125eSRichard Zhao goto put_id; 618fe6e125eSRichard Zhao } 619cbc6dc2aSRichard Zhao 620cbc6dc2aSRichard Zhao pdev->dev.parent = dev; 621cbc6dc2aSRichard Zhao pdev->dev.dma_mask = dev->dma_mask; 622cbc6dc2aSRichard Zhao pdev->dev.dma_parms = dev->dma_parms; 623cbc6dc2aSRichard Zhao dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask); 624cbc6dc2aSRichard Zhao 625cbc6dc2aSRichard Zhao ret = platform_device_add_resources(pdev, res, nres); 626cbc6dc2aSRichard Zhao if (ret) 627cbc6dc2aSRichard Zhao goto err; 628cbc6dc2aSRichard Zhao 629cbc6dc2aSRichard Zhao ret = platform_device_add_data(pdev, platdata, sizeof(*platdata)); 630cbc6dc2aSRichard Zhao if (ret) 631cbc6dc2aSRichard Zhao goto err; 632cbc6dc2aSRichard Zhao 633cbc6dc2aSRichard Zhao ret = platform_device_add(pdev); 634cbc6dc2aSRichard Zhao if (ret) 635cbc6dc2aSRichard Zhao goto err; 636cbc6dc2aSRichard Zhao 637cbc6dc2aSRichard Zhao return pdev; 638cbc6dc2aSRichard Zhao 639cbc6dc2aSRichard Zhao err: 640cbc6dc2aSRichard Zhao platform_device_put(pdev); 641fe6e125eSRichard Zhao put_id: 642fe6e125eSRichard Zhao ida_simple_remove(&ci_ida, id); 643cbc6dc2aSRichard Zhao return ERR_PTR(ret); 644cbc6dc2aSRichard Zhao } 6458e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_add_device); 646cbc6dc2aSRichard Zhao 6478e22978cSAlexander Shishkin void ci_hdrc_remove_device(struct platform_device *pdev) 648cbc6dc2aSRichard Zhao { 64998c35534SLothar Waßmann int id = pdev->id; 650cbc6dc2aSRichard Zhao platform_device_unregister(pdev); 65198c35534SLothar Waßmann ida_simple_remove(&ci_ida, id); 652cbc6dc2aSRichard Zhao } 6538e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); 654cbc6dc2aSRichard Zhao 6553f124d23SPeter Chen static inline void ci_role_destroy(struct ci_hdrc *ci) 6563f124d23SPeter Chen { 6573f124d23SPeter Chen ci_hdrc_gadget_destroy(ci); 6583f124d23SPeter Chen ci_hdrc_host_destroy(ci); 659cbec6bd5SPeter Chen if (ci->is_otg) 660cbec6bd5SPeter Chen ci_hdrc_otg_destroy(ci); 6613f124d23SPeter Chen } 6623f124d23SPeter Chen 663577b232fSPeter Chen static void ci_get_otg_capable(struct ci_hdrc *ci) 664577b232fSPeter Chen { 665577b232fSPeter Chen if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) 666577b232fSPeter Chen ci->is_otg = false; 667577b232fSPeter Chen else 668577b232fSPeter Chen ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, 669577b232fSPeter Chen DCCPARAMS_DC | DCCPARAMS_HC) 670577b232fSPeter Chen == (DCCPARAMS_DC | DCCPARAMS_HC)); 6712e37cfd8SPeter Chen if (ci->is_otg) { 672577b232fSPeter Chen dev_dbg(ci->dev, "It is OTG capable controller\n"); 6732e37cfd8SPeter Chen /* Disable and clear all OTG irq */ 6742e37cfd8SPeter Chen hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, 6752e37cfd8SPeter Chen OTGSC_INT_STATUS_BITS); 6762e37cfd8SPeter Chen } 677577b232fSPeter Chen } 678577b232fSPeter Chen 67941ac7b3aSBill Pemberton static int ci_hdrc_probe(struct platform_device *pdev) 680e443b333SAlexander Shishkin { 681e443b333SAlexander Shishkin struct device *dev = &pdev->dev; 6828e22978cSAlexander Shishkin struct ci_hdrc *ci; 683e443b333SAlexander Shishkin struct resource *res; 684e443b333SAlexander Shishkin void __iomem *base; 685e443b333SAlexander Shishkin int ret; 686691962d1SSascha Hauer enum usb_dr_mode dr_mode; 687e443b333SAlexander Shishkin 688fad56745SJingoo Han if (!dev_get_platdata(dev)) { 689e443b333SAlexander Shishkin dev_err(dev, "platform data missing\n"); 690e443b333SAlexander Shishkin return -ENODEV; 691e443b333SAlexander Shishkin } 692e443b333SAlexander Shishkin 693e443b333SAlexander Shishkin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 69419290816SFelipe Balbi base = devm_ioremap_resource(dev, res); 69519290816SFelipe Balbi if (IS_ERR(base)) 69619290816SFelipe Balbi return PTR_ERR(base); 697e443b333SAlexander Shishkin 6985f36e231SAlexander Shishkin ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); 699d0f99249SFabio Estevam if (!ci) 7005f36e231SAlexander Shishkin return -ENOMEM; 701e443b333SAlexander Shishkin 7025f36e231SAlexander Shishkin ci->dev = dev; 703fad56745SJingoo Han ci->platdata = dev_get_platdata(dev); 704ed8f8318SPeter Chen ci->imx28_write_fix = !!(ci->platdata->flags & 705ed8f8318SPeter Chen CI_HDRC_IMX28_WRITE_FIX); 7061f874edcSPeter Chen ci->supports_runtime_pm = !!(ci->platdata->flags & 7071f874edcSPeter Chen CI_HDRC_SUPPORTS_RUNTIME_PM); 7085f36e231SAlexander Shishkin 7095f36e231SAlexander Shishkin ret = hw_device_init(ci, base); 7105f36e231SAlexander Shishkin if (ret < 0) { 7115f36e231SAlexander Shishkin dev_err(dev, "can't initialize hardware\n"); 7125f36e231SAlexander Shishkin return -ENODEV; 7135f36e231SAlexander Shishkin } 7145f36e231SAlexander Shishkin 7151e5e2d3dSAntoine Tenart if (ci->platdata->phy) { 7161e5e2d3dSAntoine Tenart ci->phy = ci->platdata->phy; 7171e5e2d3dSAntoine Tenart } else if (ci->platdata->usb_phy) { 718ef44cb42SAntoine Tenart ci->usb_phy = ci->platdata->usb_phy; 7191e5e2d3dSAntoine Tenart } else { 72021a5b579SAntoine Tenart ci->phy = devm_phy_get(dev->parent, "usb-phy"); 72121a5b579SAntoine Tenart ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); 722c859aa65SPeter Chen 7231e5e2d3dSAntoine Tenart /* if both generic PHY and USB PHY layers aren't enabled */ 7241e5e2d3dSAntoine Tenart if (PTR_ERR(ci->phy) == -ENOSYS && 7251e5e2d3dSAntoine Tenart PTR_ERR(ci->usb_phy) == -ENXIO) 7261e5e2d3dSAntoine Tenart return -ENXIO; 727c859aa65SPeter Chen 7281e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) 729c859aa65SPeter Chen return -EPROBE_DEFER; 7301e5e2d3dSAntoine Tenart 7311e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy)) 7321e5e2d3dSAntoine Tenart ci->phy = NULL; 7331e5e2d3dSAntoine Tenart else if (IS_ERR(ci->usb_phy)) 7341e5e2d3dSAntoine Tenart ci->usb_phy = NULL; 735c859aa65SPeter Chen } 736c859aa65SPeter Chen 737d03cccffSPeter Chen ret = ci_usb_phy_init(ci); 73874475edeSPeter Chen if (ret) { 73974475edeSPeter Chen dev_err(dev, "unable to init phy: %d\n", ret); 74074475edeSPeter Chen return ret; 74174475edeSPeter Chen } 74274475edeSPeter Chen 743eb70e5abSAlexander Shishkin ci->hw_bank.phys = res->start; 744eb70e5abSAlexander Shishkin 7455f36e231SAlexander Shishkin ci->irq = platform_get_irq(pdev, 0); 7465f36e231SAlexander Shishkin if (ci->irq < 0) { 747e443b333SAlexander Shishkin dev_err(dev, "missing IRQ\n"); 74842d18212SFabio Estevam ret = ci->irq; 749c859aa65SPeter Chen goto deinit_phy; 750e443b333SAlexander Shishkin } 751e443b333SAlexander Shishkin 752577b232fSPeter Chen ci_get_otg_capable(ci); 753577b232fSPeter Chen 754691962d1SSascha Hauer dr_mode = ci->platdata->dr_mode; 7555f36e231SAlexander Shishkin /* initialize role(s) before the interrupt is requested */ 756691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 757eb70e5abSAlexander Shishkin ret = ci_hdrc_host_init(ci); 758eb70e5abSAlexander Shishkin if (ret) 759eb70e5abSAlexander Shishkin dev_info(dev, "doesn't support host\n"); 760691962d1SSascha Hauer } 761eb70e5abSAlexander Shishkin 762691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 7635f36e231SAlexander Shishkin ret = ci_hdrc_gadget_init(ci); 764e443b333SAlexander Shishkin if (ret) 7655f36e231SAlexander Shishkin dev_info(dev, "doesn't support gadget\n"); 766691962d1SSascha Hauer } 7675f36e231SAlexander Shishkin 7685f36e231SAlexander Shishkin if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { 7695f36e231SAlexander Shishkin dev_err(dev, "no supported roles\n"); 77074475edeSPeter Chen ret = -ENODEV; 771c859aa65SPeter Chen goto deinit_phy; 772cbec6bd5SPeter Chen } 773cbec6bd5SPeter Chen 77427c62c2dSPeter Chen if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) { 775cbec6bd5SPeter Chen ret = ci_hdrc_otg_init(ci); 776cbec6bd5SPeter Chen if (ret) { 777cbec6bd5SPeter Chen dev_err(dev, "init otg fails, ret = %d\n", ret); 778cbec6bd5SPeter Chen goto stop; 779cbec6bd5SPeter Chen } 7805f36e231SAlexander Shishkin } 7815f36e231SAlexander Shishkin 7825f36e231SAlexander Shishkin if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { 783577b232fSPeter Chen if (ci->is_otg) { 7845f36e231SAlexander Shishkin ci->role = ci_otg_role(ci); 7850c33bf78SLi Jun /* Enable ID change irq */ 7860c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); 787577b232fSPeter Chen } else { 788577b232fSPeter Chen /* 789577b232fSPeter Chen * If the controller is not OTG capable, but support 790577b232fSPeter Chen * role switch, the defalt role is gadget, and the 791577b232fSPeter Chen * user can switch it through debugfs. 792577b232fSPeter Chen */ 793577b232fSPeter Chen ci->role = CI_ROLE_GADGET; 794577b232fSPeter Chen } 7955f36e231SAlexander Shishkin } else { 7965f36e231SAlexander Shishkin ci->role = ci->roles[CI_ROLE_HOST] 7975f36e231SAlexander Shishkin ? CI_ROLE_HOST 7985f36e231SAlexander Shishkin : CI_ROLE_GADGET; 7995f36e231SAlexander Shishkin } 8005f36e231SAlexander Shishkin 801961ea496SLi Jun if (!ci_otg_is_fsm_mode(ci)) { 8025a1e1456SPeter Chen /* only update vbus status for peripheral */ 8035a1e1456SPeter Chen if (ci->role == CI_ROLE_GADGET) 8045a1e1456SPeter Chen ci_handle_vbus_change(ci); 8055a1e1456SPeter Chen 8065f36e231SAlexander Shishkin ret = ci_role_start(ci, ci->role); 8075f36e231SAlexander Shishkin if (ret) { 8084dcf720cSLi Jun dev_err(dev, "can't start %s role\n", 8094dcf720cSLi Jun ci_role(ci)->name); 810cbec6bd5SPeter Chen goto stop; 8115f36e231SAlexander Shishkin } 8124dcf720cSLi Jun } 8135f36e231SAlexander Shishkin 81424c498dfSPeter Chen platform_set_drvdata(pdev, ci); 8154c503dd5SPeter Chen ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, 8164c503dd5SPeter Chen ci->platdata->name, ci); 8175f36e231SAlexander Shishkin if (ret) 8185f36e231SAlexander Shishkin goto stop; 8195f36e231SAlexander Shishkin 8201f874edcSPeter Chen if (ci->supports_runtime_pm) { 8211f874edcSPeter Chen pm_runtime_set_active(&pdev->dev); 8221f874edcSPeter Chen pm_runtime_enable(&pdev->dev); 8231f874edcSPeter Chen pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); 8241f874edcSPeter Chen pm_runtime_mark_last_busy(ci->dev); 8251f874edcSPeter Chen pm_runtime_use_autosuspend(&pdev->dev); 8261f874edcSPeter Chen } 8271f874edcSPeter Chen 8284dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) 8294dcf720cSLi Jun ci_hdrc_otg_fsm_start(ci); 8304dcf720cSLi Jun 831f8efa766SPeter Chen device_set_wakeup_capable(&pdev->dev, true); 832f8efa766SPeter Chen 833adf0f735SAlexander Shishkin ret = dbg_create_files(ci); 834adf0f735SAlexander Shishkin if (!ret) 835adf0f735SAlexander Shishkin return 0; 8365f36e231SAlexander Shishkin 8375f36e231SAlexander Shishkin stop: 8383f124d23SPeter Chen ci_role_destroy(ci); 839c859aa65SPeter Chen deinit_phy: 8401e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 841e443b333SAlexander Shishkin 842e443b333SAlexander Shishkin return ret; 843e443b333SAlexander Shishkin } 844e443b333SAlexander Shishkin 845fb4e98abSBill Pemberton static int ci_hdrc_remove(struct platform_device *pdev) 846e443b333SAlexander Shishkin { 8478e22978cSAlexander Shishkin struct ci_hdrc *ci = platform_get_drvdata(pdev); 848e443b333SAlexander Shishkin 8491f874edcSPeter Chen if (ci->supports_runtime_pm) { 8501f874edcSPeter Chen pm_runtime_get_sync(&pdev->dev); 8511f874edcSPeter Chen pm_runtime_disable(&pdev->dev); 8521f874edcSPeter Chen pm_runtime_put_noidle(&pdev->dev); 8531f874edcSPeter Chen } 8541f874edcSPeter Chen 855adf0f735SAlexander Shishkin dbg_remove_files(ci); 8563f124d23SPeter Chen ci_role_destroy(ci); 857864cf949SPeter Chen ci_hdrc_enter_lpm(ci, true); 8581e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 859e443b333SAlexander Shishkin 860e443b333SAlexander Shishkin return 0; 861e443b333SAlexander Shishkin } 862e443b333SAlexander Shishkin 8631f874edcSPeter Chen #ifdef CONFIG_PM 864961ea496SLi Jun /* Prepare wakeup by SRP before suspend */ 865961ea496SLi Jun static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci) 866961ea496SLi Jun { 867961ea496SLi Jun if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) && 868961ea496SLi Jun !hw_read_otgsc(ci, OTGSC_ID)) { 869961ea496SLi Jun hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 870961ea496SLi Jun PORTSC_PP); 871961ea496SLi Jun hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN, 872961ea496SLi Jun PORTSC_WKCN); 873961ea496SLi Jun } 874961ea496SLi Jun } 875961ea496SLi Jun 876961ea496SLi Jun /* Handle SRP when wakeup by data pulse */ 877961ea496SLi Jun static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci) 878961ea496SLi Jun { 879961ea496SLi Jun if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) && 880961ea496SLi Jun (ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) { 881961ea496SLi Jun if (!hw_read_otgsc(ci, OTGSC_ID)) { 882961ea496SLi Jun ci->fsm.a_srp_det = 1; 883961ea496SLi Jun ci->fsm.a_bus_drop = 0; 884961ea496SLi Jun } else { 885961ea496SLi Jun ci->fsm.id = 1; 886961ea496SLi Jun } 887961ea496SLi Jun ci_otg_queue_work(ci); 888961ea496SLi Jun } 889961ea496SLi Jun } 890961ea496SLi Jun 8918076932fSPeter Chen static void ci_controller_suspend(struct ci_hdrc *ci) 8928076932fSPeter Chen { 8931f874edcSPeter Chen disable_irq(ci->irq); 8948076932fSPeter Chen ci_hdrc_enter_lpm(ci, true); 8958076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 1); 8961f874edcSPeter Chen ci->in_lpm = true; 8971f874edcSPeter Chen enable_irq(ci->irq); 8988076932fSPeter Chen } 8998076932fSPeter Chen 9008076932fSPeter Chen static int ci_controller_resume(struct device *dev) 9018076932fSPeter Chen { 9028076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9038076932fSPeter Chen 9048076932fSPeter Chen dev_dbg(dev, "at %s\n", __func__); 9058076932fSPeter Chen 9061f874edcSPeter Chen if (!ci->in_lpm) { 9071f874edcSPeter Chen WARN_ON(1); 9081f874edcSPeter Chen return 0; 9091f874edcSPeter Chen } 9108076932fSPeter Chen 9111f874edcSPeter Chen ci_hdrc_enter_lpm(ci, false); 9128076932fSPeter Chen if (ci->usb_phy) { 9138076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 0); 9148076932fSPeter Chen usb_phy_set_wakeup(ci->usb_phy, false); 9158076932fSPeter Chen hw_wait_phy_stable(); 9168076932fSPeter Chen } 9178076932fSPeter Chen 9181f874edcSPeter Chen ci->in_lpm = false; 9191f874edcSPeter Chen if (ci->wakeup_int) { 9201f874edcSPeter Chen ci->wakeup_int = false; 9211f874edcSPeter Chen pm_runtime_mark_last_busy(ci->dev); 9221f874edcSPeter Chen pm_runtime_put_autosuspend(ci->dev); 9231f874edcSPeter Chen enable_irq(ci->irq); 924961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 925961ea496SLi Jun ci_otg_fsm_wakeup_by_srp(ci); 9261f874edcSPeter Chen } 9271f874edcSPeter Chen 9288076932fSPeter Chen return 0; 9298076932fSPeter Chen } 9308076932fSPeter Chen 9311f874edcSPeter Chen #ifdef CONFIG_PM_SLEEP 9328076932fSPeter Chen static int ci_suspend(struct device *dev) 9338076932fSPeter Chen { 9348076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9358076932fSPeter Chen 9368076932fSPeter Chen if (ci->wq) 9378076932fSPeter Chen flush_workqueue(ci->wq); 9381f874edcSPeter Chen /* 9391f874edcSPeter Chen * Controller needs to be active during suspend, otherwise the core 9401f874edcSPeter Chen * may run resume when the parent is at suspend if other driver's 9411f874edcSPeter Chen * suspend fails, it occurs before parent's suspend has not started, 9421f874edcSPeter Chen * but the core suspend has finished. 9431f874edcSPeter Chen */ 9441f874edcSPeter Chen if (ci->in_lpm) 9451f874edcSPeter Chen pm_runtime_resume(dev); 9461f874edcSPeter Chen 9471f874edcSPeter Chen if (ci->in_lpm) { 9481f874edcSPeter Chen WARN_ON(1); 9491f874edcSPeter Chen return 0; 9501f874edcSPeter Chen } 9518076932fSPeter Chen 952f8efa766SPeter Chen if (device_may_wakeup(dev)) { 953961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 954961ea496SLi Jun ci_otg_fsm_suspend_for_srp(ci); 955961ea496SLi Jun 956f8efa766SPeter Chen usb_phy_set_wakeup(ci->usb_phy, true); 957f8efa766SPeter Chen enable_irq_wake(ci->irq); 958f8efa766SPeter Chen } 959f8efa766SPeter Chen 9608076932fSPeter Chen ci_controller_suspend(ci); 9618076932fSPeter Chen 9628076932fSPeter Chen return 0; 9638076932fSPeter Chen } 9648076932fSPeter Chen 9658076932fSPeter Chen static int ci_resume(struct device *dev) 9668076932fSPeter Chen { 9671f874edcSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9681f874edcSPeter Chen int ret; 9691f874edcSPeter Chen 970f8efa766SPeter Chen if (device_may_wakeup(dev)) 971f8efa766SPeter Chen disable_irq_wake(ci->irq); 972f8efa766SPeter Chen 9731f874edcSPeter Chen ret = ci_controller_resume(dev); 9741f874edcSPeter Chen if (ret) 9751f874edcSPeter Chen return ret; 9761f874edcSPeter Chen 9771f874edcSPeter Chen if (ci->supports_runtime_pm) { 9781f874edcSPeter Chen pm_runtime_disable(dev); 9791f874edcSPeter Chen pm_runtime_set_active(dev); 9801f874edcSPeter Chen pm_runtime_enable(dev); 9811f874edcSPeter Chen } 9821f874edcSPeter Chen 9831f874edcSPeter Chen return ret; 9848076932fSPeter Chen } 9858076932fSPeter Chen #endif /* CONFIG_PM_SLEEP */ 9868076932fSPeter Chen 9871f874edcSPeter Chen static int ci_runtime_suspend(struct device *dev) 9881f874edcSPeter Chen { 9891f874edcSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9901f874edcSPeter Chen 9911f874edcSPeter Chen dev_dbg(dev, "at %s\n", __func__); 9921f874edcSPeter Chen 9931f874edcSPeter Chen if (ci->in_lpm) { 9941f874edcSPeter Chen WARN_ON(1); 9951f874edcSPeter Chen return 0; 9961f874edcSPeter Chen } 9971f874edcSPeter Chen 998961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 999961ea496SLi Jun ci_otg_fsm_suspend_for_srp(ci); 1000961ea496SLi Jun 10011f874edcSPeter Chen usb_phy_set_wakeup(ci->usb_phy, true); 10021f874edcSPeter Chen ci_controller_suspend(ci); 10031f874edcSPeter Chen 10041f874edcSPeter Chen return 0; 10051f874edcSPeter Chen } 10061f874edcSPeter Chen 10071f874edcSPeter Chen static int ci_runtime_resume(struct device *dev) 10081f874edcSPeter Chen { 10091f874edcSPeter Chen return ci_controller_resume(dev); 10101f874edcSPeter Chen } 10111f874edcSPeter Chen 10121f874edcSPeter Chen #endif /* CONFIG_PM */ 10138076932fSPeter Chen static const struct dev_pm_ops ci_pm_ops = { 10148076932fSPeter Chen SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume) 10151f874edcSPeter Chen SET_RUNTIME_PM_OPS(ci_runtime_suspend, ci_runtime_resume, NULL) 10168076932fSPeter Chen }; 10171f874edcSPeter Chen 10185f36e231SAlexander Shishkin static struct platform_driver ci_hdrc_driver = { 10195f36e231SAlexander Shishkin .probe = ci_hdrc_probe, 10207690417dSBill Pemberton .remove = ci_hdrc_remove, 1021e443b333SAlexander Shishkin .driver = { 10225f36e231SAlexander Shishkin .name = "ci_hdrc", 10238076932fSPeter Chen .pm = &ci_pm_ops, 1024e443b333SAlexander Shishkin }, 1025e443b333SAlexander Shishkin }; 1026e443b333SAlexander Shishkin 10275f36e231SAlexander Shishkin module_platform_driver(ci_hdrc_driver); 1028e443b333SAlexander Shishkin 10295f36e231SAlexander Shishkin MODULE_ALIAS("platform:ci_hdrc"); 1030e443b333SAlexander Shishkin MODULE_LICENSE("GPL v2"); 1031e443b333SAlexander Shishkin MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); 10325f36e231SAlexander Shishkin MODULE_DESCRIPTION("ChipIdea HDRC Driver"); 1033