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 { 56379742351SLi Jun int ret; 56479742351SLi Jun 565c22600c3SPeter Chen if (!platdata->phy_mode) 566c22600c3SPeter Chen platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); 567c22600c3SPeter Chen 568c22600c3SPeter Chen if (!platdata->dr_mode) 569c22600c3SPeter Chen platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); 570c22600c3SPeter Chen 571c22600c3SPeter Chen if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) 572c22600c3SPeter Chen platdata->dr_mode = USB_DR_MODE_OTG; 573c22600c3SPeter Chen 574c2ec3a73SPeter Chen if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { 575c2ec3a73SPeter Chen /* Get the vbus regulator */ 576c2ec3a73SPeter Chen platdata->reg_vbus = devm_regulator_get(dev, "vbus"); 577c2ec3a73SPeter Chen if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { 578c2ec3a73SPeter Chen return -EPROBE_DEFER; 579c2ec3a73SPeter Chen } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { 5806629467bSMickael Maison /* no vbus regulator is needed */ 581c2ec3a73SPeter Chen platdata->reg_vbus = NULL; 582c2ec3a73SPeter Chen } else if (IS_ERR(platdata->reg_vbus)) { 583c2ec3a73SPeter Chen dev_err(dev, "Getting regulator error: %ld\n", 584c2ec3a73SPeter Chen PTR_ERR(platdata->reg_vbus)); 585c2ec3a73SPeter Chen return PTR_ERR(platdata->reg_vbus); 586c2ec3a73SPeter Chen } 587f6a9ff07SPeter Chen /* Get TPL support */ 588f6a9ff07SPeter Chen if (!platdata->tpl_support) 589f6a9ff07SPeter Chen platdata->tpl_support = 590f6a9ff07SPeter Chen of_usb_host_tpl_support(dev->of_node); 591c2ec3a73SPeter Chen } 592c2ec3a73SPeter Chen 59379742351SLi Jun if (platdata->dr_mode == USB_DR_MODE_OTG) { 59479742351SLi Jun /* We can support HNP and SRP of OTG 2.0 */ 59579742351SLi Jun platdata->ci_otg_caps.otg_rev = 0x0200; 59679742351SLi Jun platdata->ci_otg_caps.hnp_support = true; 59779742351SLi Jun platdata->ci_otg_caps.srp_support = true; 59879742351SLi Jun 59979742351SLi Jun /* Update otg capabilities by DT properties */ 60079742351SLi Jun ret = of_usb_update_otg_caps(dev->of_node, 60179742351SLi Jun &platdata->ci_otg_caps); 60279742351SLi Jun if (ret) 60379742351SLi Jun return ret; 60479742351SLi Jun } 60579742351SLi Jun 6064f6743d5SMichael Grzeschik if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) 6074f6743d5SMichael Grzeschik platdata->flags |= CI_HDRC_FORCE_FULLSPEED; 6084f6743d5SMichael Grzeschik 6091542d9c3SPeter Chen return 0; 6101542d9c3SPeter Chen } 6111542d9c3SPeter Chen 612fe6e125eSRichard Zhao static DEFINE_IDA(ci_ida); 613fe6e125eSRichard Zhao 6148e22978cSAlexander Shishkin struct platform_device *ci_hdrc_add_device(struct device *dev, 615cbc6dc2aSRichard Zhao struct resource *res, int nres, 6168e22978cSAlexander Shishkin struct ci_hdrc_platform_data *platdata) 617cbc6dc2aSRichard Zhao { 618cbc6dc2aSRichard Zhao struct platform_device *pdev; 619fe6e125eSRichard Zhao int id, ret; 620cbc6dc2aSRichard Zhao 6211542d9c3SPeter Chen ret = ci_get_platdata(dev, platdata); 6221542d9c3SPeter Chen if (ret) 6231542d9c3SPeter Chen return ERR_PTR(ret); 6241542d9c3SPeter Chen 625fe6e125eSRichard Zhao id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); 626fe6e125eSRichard Zhao if (id < 0) 627fe6e125eSRichard Zhao return ERR_PTR(id); 628fe6e125eSRichard Zhao 629fe6e125eSRichard Zhao pdev = platform_device_alloc("ci_hdrc", id); 630fe6e125eSRichard Zhao if (!pdev) { 631fe6e125eSRichard Zhao ret = -ENOMEM; 632fe6e125eSRichard Zhao goto put_id; 633fe6e125eSRichard Zhao } 634cbc6dc2aSRichard Zhao 635cbc6dc2aSRichard Zhao pdev->dev.parent = dev; 636cbc6dc2aSRichard Zhao pdev->dev.dma_mask = dev->dma_mask; 637cbc6dc2aSRichard Zhao pdev->dev.dma_parms = dev->dma_parms; 638cbc6dc2aSRichard Zhao dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask); 639cbc6dc2aSRichard Zhao 640cbc6dc2aSRichard Zhao ret = platform_device_add_resources(pdev, res, nres); 641cbc6dc2aSRichard Zhao if (ret) 642cbc6dc2aSRichard Zhao goto err; 643cbc6dc2aSRichard Zhao 644cbc6dc2aSRichard Zhao ret = platform_device_add_data(pdev, platdata, sizeof(*platdata)); 645cbc6dc2aSRichard Zhao if (ret) 646cbc6dc2aSRichard Zhao goto err; 647cbc6dc2aSRichard Zhao 648cbc6dc2aSRichard Zhao ret = platform_device_add(pdev); 649cbc6dc2aSRichard Zhao if (ret) 650cbc6dc2aSRichard Zhao goto err; 651cbc6dc2aSRichard Zhao 652cbc6dc2aSRichard Zhao return pdev; 653cbc6dc2aSRichard Zhao 654cbc6dc2aSRichard Zhao err: 655cbc6dc2aSRichard Zhao platform_device_put(pdev); 656fe6e125eSRichard Zhao put_id: 657fe6e125eSRichard Zhao ida_simple_remove(&ci_ida, id); 658cbc6dc2aSRichard Zhao return ERR_PTR(ret); 659cbc6dc2aSRichard Zhao } 6608e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_add_device); 661cbc6dc2aSRichard Zhao 6628e22978cSAlexander Shishkin void ci_hdrc_remove_device(struct platform_device *pdev) 663cbc6dc2aSRichard Zhao { 66498c35534SLothar Waßmann int id = pdev->id; 665cbc6dc2aSRichard Zhao platform_device_unregister(pdev); 66698c35534SLothar Waßmann ida_simple_remove(&ci_ida, id); 667cbc6dc2aSRichard Zhao } 6688e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); 669cbc6dc2aSRichard Zhao 6703f124d23SPeter Chen static inline void ci_role_destroy(struct ci_hdrc *ci) 6713f124d23SPeter Chen { 6723f124d23SPeter Chen ci_hdrc_gadget_destroy(ci); 6733f124d23SPeter Chen ci_hdrc_host_destroy(ci); 674cbec6bd5SPeter Chen if (ci->is_otg) 675cbec6bd5SPeter Chen ci_hdrc_otg_destroy(ci); 6763f124d23SPeter Chen } 6773f124d23SPeter Chen 678577b232fSPeter Chen static void ci_get_otg_capable(struct ci_hdrc *ci) 679577b232fSPeter Chen { 680577b232fSPeter Chen if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) 681577b232fSPeter Chen ci->is_otg = false; 682577b232fSPeter Chen else 683577b232fSPeter Chen ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, 684577b232fSPeter Chen DCCPARAMS_DC | DCCPARAMS_HC) 685577b232fSPeter Chen == (DCCPARAMS_DC | DCCPARAMS_HC)); 6862e37cfd8SPeter Chen if (ci->is_otg) { 687577b232fSPeter Chen dev_dbg(ci->dev, "It is OTG capable controller\n"); 6882e37cfd8SPeter Chen /* Disable and clear all OTG irq */ 6892e37cfd8SPeter Chen hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, 6902e37cfd8SPeter Chen OTGSC_INT_STATUS_BITS); 6912e37cfd8SPeter Chen } 692577b232fSPeter Chen } 693577b232fSPeter Chen 69441ac7b3aSBill Pemberton static int ci_hdrc_probe(struct platform_device *pdev) 695e443b333SAlexander Shishkin { 696e443b333SAlexander Shishkin struct device *dev = &pdev->dev; 6978e22978cSAlexander Shishkin struct ci_hdrc *ci; 698e443b333SAlexander Shishkin struct resource *res; 699e443b333SAlexander Shishkin void __iomem *base; 700e443b333SAlexander Shishkin int ret; 701691962d1SSascha Hauer enum usb_dr_mode dr_mode; 702e443b333SAlexander Shishkin 703fad56745SJingoo Han if (!dev_get_platdata(dev)) { 704e443b333SAlexander Shishkin dev_err(dev, "platform data missing\n"); 705e443b333SAlexander Shishkin return -ENODEV; 706e443b333SAlexander Shishkin } 707e443b333SAlexander Shishkin 708e443b333SAlexander Shishkin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 70919290816SFelipe Balbi base = devm_ioremap_resource(dev, res); 71019290816SFelipe Balbi if (IS_ERR(base)) 71119290816SFelipe Balbi return PTR_ERR(base); 712e443b333SAlexander Shishkin 7135f36e231SAlexander Shishkin ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); 714d0f99249SFabio Estevam if (!ci) 7155f36e231SAlexander Shishkin return -ENOMEM; 716e443b333SAlexander Shishkin 7175f36e231SAlexander Shishkin ci->dev = dev; 718fad56745SJingoo Han ci->platdata = dev_get_platdata(dev); 719ed8f8318SPeter Chen ci->imx28_write_fix = !!(ci->platdata->flags & 720ed8f8318SPeter Chen CI_HDRC_IMX28_WRITE_FIX); 7211f874edcSPeter Chen ci->supports_runtime_pm = !!(ci->platdata->flags & 7221f874edcSPeter Chen CI_HDRC_SUPPORTS_RUNTIME_PM); 7235f36e231SAlexander Shishkin 7245f36e231SAlexander Shishkin ret = hw_device_init(ci, base); 7255f36e231SAlexander Shishkin if (ret < 0) { 7265f36e231SAlexander Shishkin dev_err(dev, "can't initialize hardware\n"); 7275f36e231SAlexander Shishkin return -ENODEV; 7285f36e231SAlexander Shishkin } 7295f36e231SAlexander Shishkin 7301e5e2d3dSAntoine Tenart if (ci->platdata->phy) { 7311e5e2d3dSAntoine Tenart ci->phy = ci->platdata->phy; 7321e5e2d3dSAntoine Tenart } else if (ci->platdata->usb_phy) { 733ef44cb42SAntoine Tenart ci->usb_phy = ci->platdata->usb_phy; 7341e5e2d3dSAntoine Tenart } else { 73521a5b579SAntoine Tenart ci->phy = devm_phy_get(dev->parent, "usb-phy"); 73621a5b579SAntoine Tenart ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); 737c859aa65SPeter Chen 7381e5e2d3dSAntoine Tenart /* if both generic PHY and USB PHY layers aren't enabled */ 7391e5e2d3dSAntoine Tenart if (PTR_ERR(ci->phy) == -ENOSYS && 7401e5e2d3dSAntoine Tenart PTR_ERR(ci->usb_phy) == -ENXIO) 7411e5e2d3dSAntoine Tenart return -ENXIO; 742c859aa65SPeter Chen 7431e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) 744c859aa65SPeter Chen return -EPROBE_DEFER; 7451e5e2d3dSAntoine Tenart 7461e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy)) 7471e5e2d3dSAntoine Tenart ci->phy = NULL; 7481e5e2d3dSAntoine Tenart else if (IS_ERR(ci->usb_phy)) 7491e5e2d3dSAntoine Tenart ci->usb_phy = NULL; 750c859aa65SPeter Chen } 751c859aa65SPeter Chen 752d03cccffSPeter Chen ret = ci_usb_phy_init(ci); 75374475edeSPeter Chen if (ret) { 75474475edeSPeter Chen dev_err(dev, "unable to init phy: %d\n", ret); 75574475edeSPeter Chen return ret; 75674475edeSPeter Chen } 75774475edeSPeter Chen 758eb70e5abSAlexander Shishkin ci->hw_bank.phys = res->start; 759eb70e5abSAlexander Shishkin 7605f36e231SAlexander Shishkin ci->irq = platform_get_irq(pdev, 0); 7615f36e231SAlexander Shishkin if (ci->irq < 0) { 762e443b333SAlexander Shishkin dev_err(dev, "missing IRQ\n"); 76342d18212SFabio Estevam ret = ci->irq; 764c859aa65SPeter Chen goto deinit_phy; 765e443b333SAlexander Shishkin } 766e443b333SAlexander Shishkin 767577b232fSPeter Chen ci_get_otg_capable(ci); 768577b232fSPeter Chen 769691962d1SSascha Hauer dr_mode = ci->platdata->dr_mode; 7705f36e231SAlexander Shishkin /* initialize role(s) before the interrupt is requested */ 771691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 772eb70e5abSAlexander Shishkin ret = ci_hdrc_host_init(ci); 773eb70e5abSAlexander Shishkin if (ret) 774eb70e5abSAlexander Shishkin dev_info(dev, "doesn't support host\n"); 775691962d1SSascha Hauer } 776eb70e5abSAlexander Shishkin 777691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 7785f36e231SAlexander Shishkin ret = ci_hdrc_gadget_init(ci); 779e443b333SAlexander Shishkin if (ret) 7805f36e231SAlexander Shishkin dev_info(dev, "doesn't support gadget\n"); 781691962d1SSascha Hauer } 7825f36e231SAlexander Shishkin 7835f36e231SAlexander Shishkin if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { 7845f36e231SAlexander Shishkin dev_err(dev, "no supported roles\n"); 78574475edeSPeter Chen ret = -ENODEV; 786c859aa65SPeter Chen goto deinit_phy; 787cbec6bd5SPeter Chen } 788cbec6bd5SPeter Chen 78927c62c2dSPeter Chen if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) { 790cbec6bd5SPeter Chen ret = ci_hdrc_otg_init(ci); 791cbec6bd5SPeter Chen if (ret) { 792cbec6bd5SPeter Chen dev_err(dev, "init otg fails, ret = %d\n", ret); 793cbec6bd5SPeter Chen goto stop; 794cbec6bd5SPeter Chen } 7955f36e231SAlexander Shishkin } 7965f36e231SAlexander Shishkin 7975f36e231SAlexander Shishkin if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { 798577b232fSPeter Chen if (ci->is_otg) { 7995f36e231SAlexander Shishkin ci->role = ci_otg_role(ci); 8000c33bf78SLi Jun /* Enable ID change irq */ 8010c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); 802577b232fSPeter Chen } else { 803577b232fSPeter Chen /* 804577b232fSPeter Chen * If the controller is not OTG capable, but support 805577b232fSPeter Chen * role switch, the defalt role is gadget, and the 806577b232fSPeter Chen * user can switch it through debugfs. 807577b232fSPeter Chen */ 808577b232fSPeter Chen ci->role = CI_ROLE_GADGET; 809577b232fSPeter Chen } 8105f36e231SAlexander Shishkin } else { 8115f36e231SAlexander Shishkin ci->role = ci->roles[CI_ROLE_HOST] 8125f36e231SAlexander Shishkin ? CI_ROLE_HOST 8135f36e231SAlexander Shishkin : CI_ROLE_GADGET; 8145f36e231SAlexander Shishkin } 8155f36e231SAlexander Shishkin 816961ea496SLi Jun if (!ci_otg_is_fsm_mode(ci)) { 8175a1e1456SPeter Chen /* only update vbus status for peripheral */ 8185a1e1456SPeter Chen if (ci->role == CI_ROLE_GADGET) 8195a1e1456SPeter Chen ci_handle_vbus_change(ci); 8205a1e1456SPeter Chen 8215f36e231SAlexander Shishkin ret = ci_role_start(ci, ci->role); 8225f36e231SAlexander Shishkin if (ret) { 8234dcf720cSLi Jun dev_err(dev, "can't start %s role\n", 8244dcf720cSLi Jun ci_role(ci)->name); 825cbec6bd5SPeter Chen goto stop; 8265f36e231SAlexander Shishkin } 8274dcf720cSLi Jun } 8285f36e231SAlexander Shishkin 82924c498dfSPeter Chen platform_set_drvdata(pdev, ci); 8304c503dd5SPeter Chen ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, 8314c503dd5SPeter Chen ci->platdata->name, ci); 8325f36e231SAlexander Shishkin if (ret) 8335f36e231SAlexander Shishkin goto stop; 8345f36e231SAlexander Shishkin 8351f874edcSPeter Chen if (ci->supports_runtime_pm) { 8361f874edcSPeter Chen pm_runtime_set_active(&pdev->dev); 8371f874edcSPeter Chen pm_runtime_enable(&pdev->dev); 8381f874edcSPeter Chen pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); 8391f874edcSPeter Chen pm_runtime_mark_last_busy(ci->dev); 8401f874edcSPeter Chen pm_runtime_use_autosuspend(&pdev->dev); 8411f874edcSPeter Chen } 8421f874edcSPeter Chen 8434dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) 8444dcf720cSLi Jun ci_hdrc_otg_fsm_start(ci); 8454dcf720cSLi Jun 846f8efa766SPeter Chen device_set_wakeup_capable(&pdev->dev, true); 847f8efa766SPeter Chen 848adf0f735SAlexander Shishkin ret = dbg_create_files(ci); 849adf0f735SAlexander Shishkin if (!ret) 850adf0f735SAlexander Shishkin return 0; 8515f36e231SAlexander Shishkin 8525f36e231SAlexander Shishkin stop: 8533f124d23SPeter Chen ci_role_destroy(ci); 854c859aa65SPeter Chen deinit_phy: 8551e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 856e443b333SAlexander Shishkin 857e443b333SAlexander Shishkin return ret; 858e443b333SAlexander Shishkin } 859e443b333SAlexander Shishkin 860fb4e98abSBill Pemberton static int ci_hdrc_remove(struct platform_device *pdev) 861e443b333SAlexander Shishkin { 8628e22978cSAlexander Shishkin struct ci_hdrc *ci = platform_get_drvdata(pdev); 863e443b333SAlexander Shishkin 8641f874edcSPeter Chen if (ci->supports_runtime_pm) { 8651f874edcSPeter Chen pm_runtime_get_sync(&pdev->dev); 8661f874edcSPeter Chen pm_runtime_disable(&pdev->dev); 8671f874edcSPeter Chen pm_runtime_put_noidle(&pdev->dev); 8681f874edcSPeter Chen } 8691f874edcSPeter Chen 870adf0f735SAlexander Shishkin dbg_remove_files(ci); 8713f124d23SPeter Chen ci_role_destroy(ci); 872864cf949SPeter Chen ci_hdrc_enter_lpm(ci, true); 8731e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 874e443b333SAlexander Shishkin 875e443b333SAlexander Shishkin return 0; 876e443b333SAlexander Shishkin } 877e443b333SAlexander Shishkin 8781f874edcSPeter Chen #ifdef CONFIG_PM 879961ea496SLi Jun /* Prepare wakeup by SRP before suspend */ 880961ea496SLi Jun static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci) 881961ea496SLi Jun { 882961ea496SLi Jun if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) && 883961ea496SLi Jun !hw_read_otgsc(ci, OTGSC_ID)) { 884961ea496SLi Jun hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 885961ea496SLi Jun PORTSC_PP); 886961ea496SLi Jun hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN, 887961ea496SLi Jun PORTSC_WKCN); 888961ea496SLi Jun } 889961ea496SLi Jun } 890961ea496SLi Jun 891961ea496SLi Jun /* Handle SRP when wakeup by data pulse */ 892961ea496SLi Jun static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci) 893961ea496SLi Jun { 894961ea496SLi Jun if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) && 895961ea496SLi Jun (ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) { 896961ea496SLi Jun if (!hw_read_otgsc(ci, OTGSC_ID)) { 897961ea496SLi Jun ci->fsm.a_srp_det = 1; 898961ea496SLi Jun ci->fsm.a_bus_drop = 0; 899961ea496SLi Jun } else { 900961ea496SLi Jun ci->fsm.id = 1; 901961ea496SLi Jun } 902961ea496SLi Jun ci_otg_queue_work(ci); 903961ea496SLi Jun } 904961ea496SLi Jun } 905961ea496SLi Jun 9068076932fSPeter Chen static void ci_controller_suspend(struct ci_hdrc *ci) 9078076932fSPeter Chen { 9081f874edcSPeter Chen disable_irq(ci->irq); 9098076932fSPeter Chen ci_hdrc_enter_lpm(ci, true); 9108076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 1); 9111f874edcSPeter Chen ci->in_lpm = true; 9121f874edcSPeter Chen enable_irq(ci->irq); 9138076932fSPeter Chen } 9148076932fSPeter Chen 9158076932fSPeter Chen static int ci_controller_resume(struct device *dev) 9168076932fSPeter Chen { 9178076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9188076932fSPeter Chen 9198076932fSPeter Chen dev_dbg(dev, "at %s\n", __func__); 9208076932fSPeter Chen 9211f874edcSPeter Chen if (!ci->in_lpm) { 9221f874edcSPeter Chen WARN_ON(1); 9231f874edcSPeter Chen return 0; 9241f874edcSPeter Chen } 9258076932fSPeter Chen 9261f874edcSPeter Chen ci_hdrc_enter_lpm(ci, false); 9278076932fSPeter Chen if (ci->usb_phy) { 9288076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 0); 9298076932fSPeter Chen usb_phy_set_wakeup(ci->usb_phy, false); 9308076932fSPeter Chen hw_wait_phy_stable(); 9318076932fSPeter Chen } 9328076932fSPeter Chen 9331f874edcSPeter Chen ci->in_lpm = false; 9341f874edcSPeter Chen if (ci->wakeup_int) { 9351f874edcSPeter Chen ci->wakeup_int = false; 9361f874edcSPeter Chen pm_runtime_mark_last_busy(ci->dev); 9371f874edcSPeter Chen pm_runtime_put_autosuspend(ci->dev); 9381f874edcSPeter Chen enable_irq(ci->irq); 939961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 940961ea496SLi Jun ci_otg_fsm_wakeup_by_srp(ci); 9411f874edcSPeter Chen } 9421f874edcSPeter Chen 9438076932fSPeter Chen return 0; 9448076932fSPeter Chen } 9458076932fSPeter Chen 9461f874edcSPeter Chen #ifdef CONFIG_PM_SLEEP 9478076932fSPeter Chen static int ci_suspend(struct device *dev) 9488076932fSPeter Chen { 9498076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9508076932fSPeter Chen 9518076932fSPeter Chen if (ci->wq) 9528076932fSPeter Chen flush_workqueue(ci->wq); 9531f874edcSPeter Chen /* 9541f874edcSPeter Chen * Controller needs to be active during suspend, otherwise the core 9551f874edcSPeter Chen * may run resume when the parent is at suspend if other driver's 9561f874edcSPeter Chen * suspend fails, it occurs before parent's suspend has not started, 9571f874edcSPeter Chen * but the core suspend has finished. 9581f874edcSPeter Chen */ 9591f874edcSPeter Chen if (ci->in_lpm) 9601f874edcSPeter Chen pm_runtime_resume(dev); 9611f874edcSPeter Chen 9621f874edcSPeter Chen if (ci->in_lpm) { 9631f874edcSPeter Chen WARN_ON(1); 9641f874edcSPeter Chen return 0; 9651f874edcSPeter Chen } 9668076932fSPeter Chen 967f8efa766SPeter Chen if (device_may_wakeup(dev)) { 968961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 969961ea496SLi Jun ci_otg_fsm_suspend_for_srp(ci); 970961ea496SLi Jun 971f8efa766SPeter Chen usb_phy_set_wakeup(ci->usb_phy, true); 972f8efa766SPeter Chen enable_irq_wake(ci->irq); 973f8efa766SPeter Chen } 974f8efa766SPeter Chen 9758076932fSPeter Chen ci_controller_suspend(ci); 9768076932fSPeter Chen 9778076932fSPeter Chen return 0; 9788076932fSPeter Chen } 9798076932fSPeter Chen 9808076932fSPeter Chen static int ci_resume(struct device *dev) 9818076932fSPeter Chen { 9821f874edcSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 9831f874edcSPeter Chen int ret; 9841f874edcSPeter Chen 985f8efa766SPeter Chen if (device_may_wakeup(dev)) 986f8efa766SPeter Chen disable_irq_wake(ci->irq); 987f8efa766SPeter Chen 9881f874edcSPeter Chen ret = ci_controller_resume(dev); 9891f874edcSPeter Chen if (ret) 9901f874edcSPeter Chen return ret; 9911f874edcSPeter Chen 9921f874edcSPeter Chen if (ci->supports_runtime_pm) { 9931f874edcSPeter Chen pm_runtime_disable(dev); 9941f874edcSPeter Chen pm_runtime_set_active(dev); 9951f874edcSPeter Chen pm_runtime_enable(dev); 9961f874edcSPeter Chen } 9971f874edcSPeter Chen 9981f874edcSPeter Chen return ret; 9998076932fSPeter Chen } 10008076932fSPeter Chen #endif /* CONFIG_PM_SLEEP */ 10018076932fSPeter Chen 10021f874edcSPeter Chen static int ci_runtime_suspend(struct device *dev) 10031f874edcSPeter Chen { 10041f874edcSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 10051f874edcSPeter Chen 10061f874edcSPeter Chen dev_dbg(dev, "at %s\n", __func__); 10071f874edcSPeter Chen 10081f874edcSPeter Chen if (ci->in_lpm) { 10091f874edcSPeter Chen WARN_ON(1); 10101f874edcSPeter Chen return 0; 10111f874edcSPeter Chen } 10121f874edcSPeter Chen 1013961ea496SLi Jun if (ci_otg_is_fsm_mode(ci)) 1014961ea496SLi Jun ci_otg_fsm_suspend_for_srp(ci); 1015961ea496SLi Jun 10161f874edcSPeter Chen usb_phy_set_wakeup(ci->usb_phy, true); 10171f874edcSPeter Chen ci_controller_suspend(ci); 10181f874edcSPeter Chen 10191f874edcSPeter Chen return 0; 10201f874edcSPeter Chen } 10211f874edcSPeter Chen 10221f874edcSPeter Chen static int ci_runtime_resume(struct device *dev) 10231f874edcSPeter Chen { 10241f874edcSPeter Chen return ci_controller_resume(dev); 10251f874edcSPeter Chen } 10261f874edcSPeter Chen 10271f874edcSPeter Chen #endif /* CONFIG_PM */ 10288076932fSPeter Chen static const struct dev_pm_ops ci_pm_ops = { 10298076932fSPeter Chen SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume) 10301f874edcSPeter Chen SET_RUNTIME_PM_OPS(ci_runtime_suspend, ci_runtime_resume, NULL) 10318076932fSPeter Chen }; 10321f874edcSPeter Chen 10335f36e231SAlexander Shishkin static struct platform_driver ci_hdrc_driver = { 10345f36e231SAlexander Shishkin .probe = ci_hdrc_probe, 10357690417dSBill Pemberton .remove = ci_hdrc_remove, 1036e443b333SAlexander Shishkin .driver = { 10375f36e231SAlexander Shishkin .name = "ci_hdrc", 10388076932fSPeter Chen .pm = &ci_pm_ops, 1039e443b333SAlexander Shishkin }, 1040e443b333SAlexander Shishkin }; 1041e443b333SAlexander Shishkin 10425f36e231SAlexander Shishkin module_platform_driver(ci_hdrc_driver); 1043e443b333SAlexander Shishkin 10445f36e231SAlexander Shishkin MODULE_ALIAS("platform:ci_hdrc"); 1045e443b333SAlexander Shishkin MODULE_LICENSE("GPL v2"); 1046e443b333SAlexander Shishkin MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); 10475f36e231SAlexander Shishkin MODULE_DESCRIPTION("ChipIdea HDRC Driver"); 1048