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 140e443b333SAlexander Shishkin /** 14136304b06SLi Jun * hw_read_intr_enable: returns interrupt enable register 14236304b06SLi Jun * 14319353881SPeter Chen * @ci: the controller 14419353881SPeter Chen * 14536304b06SLi Jun * This function returns register data 14636304b06SLi Jun */ 14736304b06SLi Jun u32 hw_read_intr_enable(struct ci_hdrc *ci) 14836304b06SLi Jun { 14936304b06SLi Jun return hw_read(ci, OP_USBINTR, ~0); 15036304b06SLi Jun } 15136304b06SLi Jun 15236304b06SLi Jun /** 15336304b06SLi Jun * hw_read_intr_status: returns interrupt status register 15436304b06SLi Jun * 15519353881SPeter Chen * @ci: the controller 15619353881SPeter Chen * 15736304b06SLi Jun * This function returns register data 15836304b06SLi Jun */ 15936304b06SLi Jun u32 hw_read_intr_status(struct ci_hdrc *ci) 16036304b06SLi Jun { 16136304b06SLi Jun return hw_read(ci, OP_USBSTS, ~0); 16236304b06SLi Jun } 16336304b06SLi Jun 16436304b06SLi Jun /** 165e443b333SAlexander Shishkin * hw_port_test_set: writes port test mode (execute without interruption) 166e443b333SAlexander Shishkin * @mode: new value 167e443b333SAlexander Shishkin * 168e443b333SAlexander Shishkin * This function returns an error code 169e443b333SAlexander Shishkin */ 1708e22978cSAlexander Shishkin int hw_port_test_set(struct ci_hdrc *ci, u8 mode) 171e443b333SAlexander Shishkin { 172e443b333SAlexander Shishkin const u8 TEST_MODE_MAX = 7; 173e443b333SAlexander Shishkin 174e443b333SAlexander Shishkin if (mode > TEST_MODE_MAX) 175e443b333SAlexander Shishkin return -EINVAL; 176e443b333SAlexander Shishkin 177727b4ddbSFelipe Balbi hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC)); 178e443b333SAlexander Shishkin return 0; 179e443b333SAlexander Shishkin } 180e443b333SAlexander Shishkin 181e443b333SAlexander Shishkin /** 182e443b333SAlexander Shishkin * hw_port_test_get: reads port test mode value 183e443b333SAlexander Shishkin * 18419353881SPeter Chen * @ci: the controller 18519353881SPeter Chen * 186e443b333SAlexander Shishkin * This function returns port test mode value 187e443b333SAlexander Shishkin */ 1888e22978cSAlexander Shishkin u8 hw_port_test_get(struct ci_hdrc *ci) 189e443b333SAlexander Shishkin { 190727b4ddbSFelipe Balbi return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); 191e443b333SAlexander Shishkin } 192e443b333SAlexander Shishkin 193b82613cfSPeter Chen static void hw_wait_phy_stable(void) 194b82613cfSPeter Chen { 195b82613cfSPeter Chen /* 196b82613cfSPeter Chen * The phy needs some delay to output the stable status from low 197b82613cfSPeter Chen * power mode. And for OTGSC, the status inputs are debounced 198b82613cfSPeter Chen * using a 1 ms time constant, so, delay 2ms for controller to get 199b82613cfSPeter Chen * the stable status, like vbus and id when the phy leaves low power. 200b82613cfSPeter Chen */ 201b82613cfSPeter Chen usleep_range(2000, 2500); 202b82613cfSPeter Chen } 203b82613cfSPeter Chen 204864cf949SPeter Chen /* The PHY enters/leaves low power mode */ 205864cf949SPeter Chen static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) 206864cf949SPeter Chen { 207864cf949SPeter Chen enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; 208864cf949SPeter Chen bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); 209864cf949SPeter Chen 2106d037db6SPeter Chen if (enable && !lpm) 211864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 212864cf949SPeter Chen PORTSC_PHCD(ci->hw_bank.lpm)); 2136d037db6SPeter Chen else if (!enable && lpm) 214864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 215864cf949SPeter Chen 0); 216864cf949SPeter Chen } 217864cf949SPeter Chen 2188e22978cSAlexander Shishkin static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) 219e443b333SAlexander Shishkin { 220e443b333SAlexander Shishkin u32 reg; 221e443b333SAlexander Shishkin 222e443b333SAlexander Shishkin /* bank is a module variable */ 2235f36e231SAlexander Shishkin ci->hw_bank.abs = base; 224e443b333SAlexander Shishkin 2255f36e231SAlexander Shishkin ci->hw_bank.cap = ci->hw_bank.abs; 22677c4400fSRichard Zhao ci->hw_bank.cap += ci->platdata->capoffset; 227938d323fSSvetoslav Neykov ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); 228e443b333SAlexander Shishkin 2295f36e231SAlexander Shishkin hw_alloc_regmap(ci, false); 2305f36e231SAlexander Shishkin reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> 231727b4ddbSFelipe Balbi __ffs(HCCPARAMS_LEN); 2325f36e231SAlexander Shishkin ci->hw_bank.lpm = reg; 233aeb2c121SChris Ruehl if (reg) 2345f36e231SAlexander Shishkin hw_alloc_regmap(ci, !!reg); 2355f36e231SAlexander Shishkin ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; 2365f36e231SAlexander Shishkin ci->hw_bank.size += OP_LAST; 2375f36e231SAlexander Shishkin ci->hw_bank.size /= sizeof(u32); 238e443b333SAlexander Shishkin 2395f36e231SAlexander Shishkin reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> 240727b4ddbSFelipe Balbi __ffs(DCCPARAMS_DEN); 2415f36e231SAlexander Shishkin ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 242e443b333SAlexander Shishkin 24309c94e62SRichard Zhao if (ci->hw_ep_max > ENDPT_MAX) 244e443b333SAlexander Shishkin return -ENODEV; 245e443b333SAlexander Shishkin 246864cf949SPeter Chen ci_hdrc_enter_lpm(ci, false); 247864cf949SPeter Chen 248c344b518SPeter Chen /* Disable all interrupts bits */ 249c344b518SPeter Chen hw_write(ci, OP_USBINTR, 0xffffffff, 0); 250c344b518SPeter Chen 251c344b518SPeter Chen /* Clear all interrupts status bits*/ 252c344b518SPeter Chen hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff); 253c344b518SPeter Chen 2545f36e231SAlexander Shishkin dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n", 2555f36e231SAlexander Shishkin ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); 256e443b333SAlexander Shishkin 257e443b333SAlexander Shishkin /* setup lock mode ? */ 258e443b333SAlexander Shishkin 259e443b333SAlexander Shishkin /* ENDPTSETUPSTAT is '0' by default */ 260e443b333SAlexander Shishkin 261e443b333SAlexander Shishkin /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 262e443b333SAlexander Shishkin 263e443b333SAlexander Shishkin return 0; 264e443b333SAlexander Shishkin } 265e443b333SAlexander Shishkin 2668e22978cSAlexander Shishkin static void hw_phymode_configure(struct ci_hdrc *ci) 26740dcd0e8SMichael Grzeschik { 2683b5d3e68SChris Ruehl u32 portsc, lpm, sts = 0; 26940dcd0e8SMichael Grzeschik 27040dcd0e8SMichael Grzeschik switch (ci->platdata->phy_mode) { 27140dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMI: 27240dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI); 27340dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI); 27440dcd0e8SMichael Grzeschik break; 27540dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMIW: 27640dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW; 27740dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW; 27840dcd0e8SMichael Grzeschik break; 27940dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_ULPI: 28040dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_ULPI); 28140dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_ULPI); 28240dcd0e8SMichael Grzeschik break; 28340dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_SERIAL: 28440dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_SERIAL); 28540dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_SERIAL); 28640dcd0e8SMichael Grzeschik sts = 1; 28740dcd0e8SMichael Grzeschik break; 28840dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_HSIC: 28940dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_HSIC); 29040dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_HSIC); 29140dcd0e8SMichael Grzeschik break; 29240dcd0e8SMichael Grzeschik default: 29340dcd0e8SMichael Grzeschik return; 29440dcd0e8SMichael Grzeschik } 29540dcd0e8SMichael Grzeschik 29640dcd0e8SMichael Grzeschik if (ci->hw_bank.lpm) { 29740dcd0e8SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm); 2983b5d3e68SChris Ruehl if (sts) 2993b5d3e68SChris Ruehl hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS); 30040dcd0e8SMichael Grzeschik } else { 30140dcd0e8SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); 3023b5d3e68SChris Ruehl if (sts) 3033b5d3e68SChris Ruehl hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); 30440dcd0e8SMichael Grzeschik } 30540dcd0e8SMichael Grzeschik } 30640dcd0e8SMichael Grzeschik 307e443b333SAlexander Shishkin /** 3081e5e2d3dSAntoine Tenart * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy 3091e5e2d3dSAntoine Tenart * interfaces 3101e5e2d3dSAntoine Tenart * @ci: the controller 3111e5e2d3dSAntoine Tenart * 3121e5e2d3dSAntoine Tenart * This function returns an error code if the phy failed to init 3131e5e2d3dSAntoine Tenart */ 3141e5e2d3dSAntoine Tenart static int _ci_usb_phy_init(struct ci_hdrc *ci) 3151e5e2d3dSAntoine Tenart { 3161e5e2d3dSAntoine Tenart int ret; 3171e5e2d3dSAntoine Tenart 3181e5e2d3dSAntoine Tenart if (ci->phy) { 3191e5e2d3dSAntoine Tenart ret = phy_init(ci->phy); 3201e5e2d3dSAntoine Tenart if (ret) 3211e5e2d3dSAntoine Tenart return ret; 3221e5e2d3dSAntoine Tenart 3231e5e2d3dSAntoine Tenart ret = phy_power_on(ci->phy); 3241e5e2d3dSAntoine Tenart if (ret) { 3251e5e2d3dSAntoine Tenart phy_exit(ci->phy); 3261e5e2d3dSAntoine Tenart return ret; 3271e5e2d3dSAntoine Tenart } 3281e5e2d3dSAntoine Tenart } else { 3291e5e2d3dSAntoine Tenart ret = usb_phy_init(ci->usb_phy); 3301e5e2d3dSAntoine Tenart } 3311e5e2d3dSAntoine Tenart 3321e5e2d3dSAntoine Tenart return ret; 3331e5e2d3dSAntoine Tenart } 3341e5e2d3dSAntoine Tenart 3351e5e2d3dSAntoine Tenart /** 3361e5e2d3dSAntoine Tenart * _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy 3371e5e2d3dSAntoine Tenart * interfaces 3381e5e2d3dSAntoine Tenart * @ci: the controller 3391e5e2d3dSAntoine Tenart */ 3401e5e2d3dSAntoine Tenart static void ci_usb_phy_exit(struct ci_hdrc *ci) 3411e5e2d3dSAntoine Tenart { 3421e5e2d3dSAntoine Tenart if (ci->phy) { 3431e5e2d3dSAntoine Tenart phy_power_off(ci->phy); 3441e5e2d3dSAntoine Tenart phy_exit(ci->phy); 3451e5e2d3dSAntoine Tenart } else { 3461e5e2d3dSAntoine Tenart usb_phy_shutdown(ci->usb_phy); 3471e5e2d3dSAntoine Tenart } 3481e5e2d3dSAntoine Tenart } 3491e5e2d3dSAntoine Tenart 3501e5e2d3dSAntoine Tenart /** 351d03cccffSPeter Chen * ci_usb_phy_init: initialize phy according to different phy type 352d03cccffSPeter Chen * @ci: the controller 353d03cccffSPeter Chen * 354d03cccffSPeter Chen * This function returns an error code if usb_phy_init has failed 355d03cccffSPeter Chen */ 356d03cccffSPeter Chen static int ci_usb_phy_init(struct ci_hdrc *ci) 357d03cccffSPeter Chen { 358d03cccffSPeter Chen int ret; 359d03cccffSPeter Chen 360d03cccffSPeter Chen switch (ci->platdata->phy_mode) { 361d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMI: 362d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMIW: 363d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_HSIC: 3641e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 365b82613cfSPeter Chen if (!ret) 366b82613cfSPeter Chen hw_wait_phy_stable(); 367b82613cfSPeter Chen else 368d03cccffSPeter Chen return ret; 369d03cccffSPeter Chen hw_phymode_configure(ci); 370d03cccffSPeter Chen break; 371d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_ULPI: 372d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_SERIAL: 373d03cccffSPeter Chen hw_phymode_configure(ci); 3741e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 375d03cccffSPeter Chen if (ret) 376d03cccffSPeter Chen return ret; 377d03cccffSPeter Chen break; 378d03cccffSPeter Chen default: 3791e5e2d3dSAntoine Tenart ret = _ci_usb_phy_init(ci); 380b82613cfSPeter Chen if (!ret) 381b82613cfSPeter Chen hw_wait_phy_stable(); 382d03cccffSPeter Chen } 383d03cccffSPeter Chen 384d03cccffSPeter Chen return ret; 385d03cccffSPeter Chen } 386d03cccffSPeter Chen 387d03cccffSPeter Chen /** 388cdd278f2SPeter Chen * hw_controller_reset: do controller reset 389cdd278f2SPeter Chen * @ci: the controller 390cdd278f2SPeter Chen * 391cdd278f2SPeter Chen * This function returns an error code 392cdd278f2SPeter Chen */ 393cdd278f2SPeter Chen static int hw_controller_reset(struct ci_hdrc *ci) 394cdd278f2SPeter Chen { 395cdd278f2SPeter Chen int count = 0; 396cdd278f2SPeter Chen 397cdd278f2SPeter Chen hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); 398cdd278f2SPeter Chen while (hw_read(ci, OP_USBCMD, USBCMD_RST)) { 399cdd278f2SPeter Chen udelay(10); 400cdd278f2SPeter Chen if (count++ > 1000) 401cdd278f2SPeter Chen return -ETIMEDOUT; 402cdd278f2SPeter Chen } 403cdd278f2SPeter Chen 404cdd278f2SPeter Chen return 0; 405cdd278f2SPeter Chen } 406cdd278f2SPeter Chen 407cdd278f2SPeter Chen /** 408e443b333SAlexander Shishkin * hw_device_reset: resets chip (execute without interruption) 409e443b333SAlexander Shishkin * @ci: the controller 410e443b333SAlexander Shishkin * 411e443b333SAlexander Shishkin * This function returns an error code 412e443b333SAlexander Shishkin */ 4135b157300SPeter Chen int hw_device_reset(struct ci_hdrc *ci) 414e443b333SAlexander Shishkin { 415cdd278f2SPeter Chen int ret; 416cdd278f2SPeter Chen 417e443b333SAlexander Shishkin /* should flush & stop before reset */ 418e443b333SAlexander Shishkin hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); 419e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 420e443b333SAlexander Shishkin 421cdd278f2SPeter Chen ret = hw_controller_reset(ci); 422cdd278f2SPeter Chen if (ret) { 423cdd278f2SPeter Chen dev_err(ci->dev, "error resetting controller, ret=%d\n", ret); 424cdd278f2SPeter Chen return ret; 425cdd278f2SPeter Chen } 426e443b333SAlexander Shishkin 42777c4400fSRichard Zhao if (ci->platdata->notify_event) 42877c4400fSRichard Zhao ci->platdata->notify_event(ci, 4298e22978cSAlexander Shishkin CI_HDRC_CONTROLLER_RESET_EVENT); 430e443b333SAlexander Shishkin 4318e22978cSAlexander Shishkin if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) 432758fc986SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); 433e443b333SAlexander Shishkin 4344f6743d5SMichael Grzeschik if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { 4354f6743d5SMichael Grzeschik if (ci->hw_bank.lpm) 4364f6743d5SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); 4374f6743d5SMichael Grzeschik else 4384f6743d5SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); 4394f6743d5SMichael Grzeschik } 4404f6743d5SMichael Grzeschik 441e443b333SAlexander Shishkin /* USBMODE should be configured step by step */ 442e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 4435b157300SPeter Chen hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); 444e443b333SAlexander Shishkin /* HW >= 2.3 */ 445e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); 446e443b333SAlexander Shishkin 4475b157300SPeter Chen if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) { 4485b157300SPeter Chen pr_err("cannot enter in %s device mode", ci_role(ci)->name); 449e443b333SAlexander Shishkin pr_err("lpm = %i", ci->hw_bank.lpm); 450e443b333SAlexander Shishkin return -ENODEV; 451e443b333SAlexander Shishkin } 452e443b333SAlexander Shishkin 453e443b333SAlexander Shishkin return 0; 454e443b333SAlexander Shishkin } 455e443b333SAlexander Shishkin 45622fa8445SPeter Chen /** 45722fa8445SPeter Chen * hw_wait_reg: wait the register value 45822fa8445SPeter Chen * 45922fa8445SPeter Chen * Sometimes, it needs to wait register value before going on. 46022fa8445SPeter Chen * Eg, when switch to device mode, the vbus value should be lower 46122fa8445SPeter Chen * than OTGSC_BSV before connects to host. 46222fa8445SPeter Chen * 46322fa8445SPeter Chen * @ci: the controller 46422fa8445SPeter Chen * @reg: register index 46522fa8445SPeter Chen * @mask: mast bit 46622fa8445SPeter Chen * @value: the bit value to wait 46722fa8445SPeter Chen * @timeout_ms: timeout in millisecond 46822fa8445SPeter Chen * 46922fa8445SPeter Chen * This function returns an error code if timeout 47022fa8445SPeter Chen */ 47122fa8445SPeter Chen int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, 47222fa8445SPeter Chen u32 value, unsigned int timeout_ms) 47322fa8445SPeter Chen { 47422fa8445SPeter Chen unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); 47522fa8445SPeter Chen 47622fa8445SPeter Chen while (hw_read(ci, reg, mask) != value) { 47722fa8445SPeter Chen if (time_after(jiffies, elapse)) { 47822fa8445SPeter Chen dev_err(ci->dev, "timeout waiting for %08x in %d\n", 47922fa8445SPeter Chen mask, reg); 48022fa8445SPeter Chen return -ETIMEDOUT; 48122fa8445SPeter Chen } 48222fa8445SPeter Chen msleep(20); 48322fa8445SPeter Chen } 48422fa8445SPeter Chen 48522fa8445SPeter Chen return 0; 48622fa8445SPeter Chen } 48722fa8445SPeter Chen 4885f36e231SAlexander Shishkin static irqreturn_t ci_irq(int irq, void *data) 4895f36e231SAlexander Shishkin { 4908e22978cSAlexander Shishkin struct ci_hdrc *ci = data; 4915f36e231SAlexander Shishkin irqreturn_t ret = IRQ_NONE; 492b183c19fSRichard Zhao u32 otgsc = 0; 4935f36e231SAlexander Shishkin 4944dcf720cSLi Jun if (ci->is_otg) { 4950c33bf78SLi Jun otgsc = hw_read_otgsc(ci, ~0); 4964dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) { 4974dcf720cSLi Jun ret = ci_otg_fsm_irq(ci); 4984dcf720cSLi Jun if (ret == IRQ_HANDLED) 4994dcf720cSLi Jun return ret; 5004dcf720cSLi Jun } 5014dcf720cSLi Jun } 5025f36e231SAlexander Shishkin 503a107f8c5SPeter Chen /* 504a107f8c5SPeter Chen * Handle id change interrupt, it indicates device/host function 505a107f8c5SPeter Chen * switch. 506a107f8c5SPeter Chen */ 507a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { 508a107f8c5SPeter Chen ci->id_event = true; 5090c33bf78SLi Jun /* Clear ID change irq status */ 5100c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); 511be6b0c1bSPeter Chen ci_otg_queue_work(ci); 512a107f8c5SPeter Chen return IRQ_HANDLED; 5135f36e231SAlexander Shishkin } 5145f36e231SAlexander Shishkin 515a107f8c5SPeter Chen /* 516a107f8c5SPeter Chen * Handle vbus change interrupt, it indicates device connection 517a107f8c5SPeter Chen * and disconnection events. 518a107f8c5SPeter Chen */ 519a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { 520a107f8c5SPeter Chen ci->b_sess_valid_event = true; 5210c33bf78SLi Jun /* Clear BSV irq */ 5220c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); 523be6b0c1bSPeter Chen ci_otg_queue_work(ci); 524a107f8c5SPeter Chen return IRQ_HANDLED; 525a107f8c5SPeter Chen } 526a107f8c5SPeter Chen 527a107f8c5SPeter Chen /* Handle device/host interrupt */ 528a107f8c5SPeter Chen if (ci->role != CI_ROLE_END) 529a107f8c5SPeter Chen ret = ci_role(ci)->irq(ci); 530a107f8c5SPeter Chen 531b183c19fSRichard Zhao return ret; 5325f36e231SAlexander Shishkin } 5335f36e231SAlexander Shishkin 5341542d9c3SPeter Chen static int ci_get_platdata(struct device *dev, 5351542d9c3SPeter Chen struct ci_hdrc_platform_data *platdata) 5361542d9c3SPeter Chen { 537c22600c3SPeter Chen if (!platdata->phy_mode) 538c22600c3SPeter Chen platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); 539c22600c3SPeter Chen 540c22600c3SPeter Chen if (!platdata->dr_mode) 541c22600c3SPeter Chen platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); 542c22600c3SPeter Chen 543c22600c3SPeter Chen if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) 544c22600c3SPeter Chen platdata->dr_mode = USB_DR_MODE_OTG; 545c22600c3SPeter Chen 546c2ec3a73SPeter Chen if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { 547c2ec3a73SPeter Chen /* Get the vbus regulator */ 548c2ec3a73SPeter Chen platdata->reg_vbus = devm_regulator_get(dev, "vbus"); 549c2ec3a73SPeter Chen if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { 550c2ec3a73SPeter Chen return -EPROBE_DEFER; 551c2ec3a73SPeter Chen } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { 5526629467bSMickael Maison /* no vbus regulator is needed */ 553c2ec3a73SPeter Chen platdata->reg_vbus = NULL; 554c2ec3a73SPeter Chen } else if (IS_ERR(platdata->reg_vbus)) { 555c2ec3a73SPeter Chen dev_err(dev, "Getting regulator error: %ld\n", 556c2ec3a73SPeter Chen PTR_ERR(platdata->reg_vbus)); 557c2ec3a73SPeter Chen return PTR_ERR(platdata->reg_vbus); 558c2ec3a73SPeter Chen } 559f6a9ff07SPeter Chen /* Get TPL support */ 560f6a9ff07SPeter Chen if (!platdata->tpl_support) 561f6a9ff07SPeter Chen platdata->tpl_support = 562f6a9ff07SPeter Chen of_usb_host_tpl_support(dev->of_node); 563c2ec3a73SPeter Chen } 564c2ec3a73SPeter Chen 5654f6743d5SMichael Grzeschik if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) 5664f6743d5SMichael Grzeschik platdata->flags |= CI_HDRC_FORCE_FULLSPEED; 5674f6743d5SMichael Grzeschik 5681542d9c3SPeter Chen return 0; 5691542d9c3SPeter Chen } 5701542d9c3SPeter Chen 571fe6e125eSRichard Zhao static DEFINE_IDA(ci_ida); 572fe6e125eSRichard Zhao 5738e22978cSAlexander Shishkin struct platform_device *ci_hdrc_add_device(struct device *dev, 574cbc6dc2aSRichard Zhao struct resource *res, int nres, 5758e22978cSAlexander Shishkin struct ci_hdrc_platform_data *platdata) 576cbc6dc2aSRichard Zhao { 577cbc6dc2aSRichard Zhao struct platform_device *pdev; 578fe6e125eSRichard Zhao int id, ret; 579cbc6dc2aSRichard Zhao 5801542d9c3SPeter Chen ret = ci_get_platdata(dev, platdata); 5811542d9c3SPeter Chen if (ret) 5821542d9c3SPeter Chen return ERR_PTR(ret); 5831542d9c3SPeter Chen 584fe6e125eSRichard Zhao id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); 585fe6e125eSRichard Zhao if (id < 0) 586fe6e125eSRichard Zhao return ERR_PTR(id); 587fe6e125eSRichard Zhao 588fe6e125eSRichard Zhao pdev = platform_device_alloc("ci_hdrc", id); 589fe6e125eSRichard Zhao if (!pdev) { 590fe6e125eSRichard Zhao ret = -ENOMEM; 591fe6e125eSRichard Zhao goto put_id; 592fe6e125eSRichard Zhao } 593cbc6dc2aSRichard Zhao 594cbc6dc2aSRichard Zhao pdev->dev.parent = dev; 595cbc6dc2aSRichard Zhao pdev->dev.dma_mask = dev->dma_mask; 596cbc6dc2aSRichard Zhao pdev->dev.dma_parms = dev->dma_parms; 597cbc6dc2aSRichard Zhao dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask); 598cbc6dc2aSRichard Zhao 599cbc6dc2aSRichard Zhao ret = platform_device_add_resources(pdev, res, nres); 600cbc6dc2aSRichard Zhao if (ret) 601cbc6dc2aSRichard Zhao goto err; 602cbc6dc2aSRichard Zhao 603cbc6dc2aSRichard Zhao ret = platform_device_add_data(pdev, platdata, sizeof(*platdata)); 604cbc6dc2aSRichard Zhao if (ret) 605cbc6dc2aSRichard Zhao goto err; 606cbc6dc2aSRichard Zhao 607cbc6dc2aSRichard Zhao ret = platform_device_add(pdev); 608cbc6dc2aSRichard Zhao if (ret) 609cbc6dc2aSRichard Zhao goto err; 610cbc6dc2aSRichard Zhao 611cbc6dc2aSRichard Zhao return pdev; 612cbc6dc2aSRichard Zhao 613cbc6dc2aSRichard Zhao err: 614cbc6dc2aSRichard Zhao platform_device_put(pdev); 615fe6e125eSRichard Zhao put_id: 616fe6e125eSRichard Zhao ida_simple_remove(&ci_ida, id); 617cbc6dc2aSRichard Zhao return ERR_PTR(ret); 618cbc6dc2aSRichard Zhao } 6198e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_add_device); 620cbc6dc2aSRichard Zhao 6218e22978cSAlexander Shishkin void ci_hdrc_remove_device(struct platform_device *pdev) 622cbc6dc2aSRichard Zhao { 62398c35534SLothar Waßmann int id = pdev->id; 624cbc6dc2aSRichard Zhao platform_device_unregister(pdev); 62598c35534SLothar Waßmann ida_simple_remove(&ci_ida, id); 626cbc6dc2aSRichard Zhao } 6278e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); 628cbc6dc2aSRichard Zhao 6293f124d23SPeter Chen static inline void ci_role_destroy(struct ci_hdrc *ci) 6303f124d23SPeter Chen { 6313f124d23SPeter Chen ci_hdrc_gadget_destroy(ci); 6323f124d23SPeter Chen ci_hdrc_host_destroy(ci); 633cbec6bd5SPeter Chen if (ci->is_otg) 634cbec6bd5SPeter Chen ci_hdrc_otg_destroy(ci); 6353f124d23SPeter Chen } 6363f124d23SPeter Chen 637577b232fSPeter Chen static void ci_get_otg_capable(struct ci_hdrc *ci) 638577b232fSPeter Chen { 639577b232fSPeter Chen if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) 640577b232fSPeter Chen ci->is_otg = false; 641577b232fSPeter Chen else 642577b232fSPeter Chen ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, 643577b232fSPeter Chen DCCPARAMS_DC | DCCPARAMS_HC) 644577b232fSPeter Chen == (DCCPARAMS_DC | DCCPARAMS_HC)); 64590893b90SPeter Chen if (ci->is_otg) 646577b232fSPeter Chen dev_dbg(ci->dev, "It is OTG capable controller\n"); 647577b232fSPeter Chen } 648577b232fSPeter Chen 64941ac7b3aSBill Pemberton static int ci_hdrc_probe(struct platform_device *pdev) 650e443b333SAlexander Shishkin { 651e443b333SAlexander Shishkin struct device *dev = &pdev->dev; 6528e22978cSAlexander Shishkin struct ci_hdrc *ci; 653e443b333SAlexander Shishkin struct resource *res; 654e443b333SAlexander Shishkin void __iomem *base; 655e443b333SAlexander Shishkin int ret; 656691962d1SSascha Hauer enum usb_dr_mode dr_mode; 657e443b333SAlexander Shishkin 658fad56745SJingoo Han if (!dev_get_platdata(dev)) { 659e443b333SAlexander Shishkin dev_err(dev, "platform data missing\n"); 660e443b333SAlexander Shishkin return -ENODEV; 661e443b333SAlexander Shishkin } 662e443b333SAlexander Shishkin 663e443b333SAlexander Shishkin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 66419290816SFelipe Balbi base = devm_ioremap_resource(dev, res); 66519290816SFelipe Balbi if (IS_ERR(base)) 66619290816SFelipe Balbi return PTR_ERR(base); 667e443b333SAlexander Shishkin 6685f36e231SAlexander Shishkin ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); 669d0f99249SFabio Estevam if (!ci) 6705f36e231SAlexander Shishkin return -ENOMEM; 671e443b333SAlexander Shishkin 6725f36e231SAlexander Shishkin ci->dev = dev; 673fad56745SJingoo Han ci->platdata = dev_get_platdata(dev); 674ed8f8318SPeter Chen ci->imx28_write_fix = !!(ci->platdata->flags & 675ed8f8318SPeter Chen CI_HDRC_IMX28_WRITE_FIX); 6765f36e231SAlexander Shishkin 6775f36e231SAlexander Shishkin ret = hw_device_init(ci, base); 6785f36e231SAlexander Shishkin if (ret < 0) { 6795f36e231SAlexander Shishkin dev_err(dev, "can't initialize hardware\n"); 6805f36e231SAlexander Shishkin return -ENODEV; 6815f36e231SAlexander Shishkin } 6825f36e231SAlexander Shishkin 6831e5e2d3dSAntoine Tenart if (ci->platdata->phy) { 6841e5e2d3dSAntoine Tenart ci->phy = ci->platdata->phy; 6851e5e2d3dSAntoine Tenart } else if (ci->platdata->usb_phy) { 686ef44cb42SAntoine Tenart ci->usb_phy = ci->platdata->usb_phy; 6871e5e2d3dSAntoine Tenart } else { 68821a5b579SAntoine Tenart ci->phy = devm_phy_get(dev->parent, "usb-phy"); 68921a5b579SAntoine Tenart ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2); 690c859aa65SPeter Chen 6911e5e2d3dSAntoine Tenart /* if both generic PHY and USB PHY layers aren't enabled */ 6921e5e2d3dSAntoine Tenart if (PTR_ERR(ci->phy) == -ENOSYS && 6931e5e2d3dSAntoine Tenart PTR_ERR(ci->usb_phy) == -ENXIO) 6941e5e2d3dSAntoine Tenart return -ENXIO; 695c859aa65SPeter Chen 6961e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) 697c859aa65SPeter Chen return -EPROBE_DEFER; 6981e5e2d3dSAntoine Tenart 6991e5e2d3dSAntoine Tenart if (IS_ERR(ci->phy)) 7001e5e2d3dSAntoine Tenart ci->phy = NULL; 7011e5e2d3dSAntoine Tenart else if (IS_ERR(ci->usb_phy)) 7021e5e2d3dSAntoine Tenart ci->usb_phy = NULL; 703c859aa65SPeter Chen } 704c859aa65SPeter Chen 705d03cccffSPeter Chen ret = ci_usb_phy_init(ci); 70674475edeSPeter Chen if (ret) { 70774475edeSPeter Chen dev_err(dev, "unable to init phy: %d\n", ret); 70874475edeSPeter Chen return ret; 70974475edeSPeter Chen } 71074475edeSPeter Chen 711eb70e5abSAlexander Shishkin ci->hw_bank.phys = res->start; 712eb70e5abSAlexander Shishkin 7135f36e231SAlexander Shishkin ci->irq = platform_get_irq(pdev, 0); 7145f36e231SAlexander Shishkin if (ci->irq < 0) { 715e443b333SAlexander Shishkin dev_err(dev, "missing IRQ\n"); 71642d18212SFabio Estevam ret = ci->irq; 717c859aa65SPeter Chen goto deinit_phy; 718e443b333SAlexander Shishkin } 719e443b333SAlexander Shishkin 720577b232fSPeter Chen ci_get_otg_capable(ci); 721577b232fSPeter Chen 722691962d1SSascha Hauer dr_mode = ci->platdata->dr_mode; 7235f36e231SAlexander Shishkin /* initialize role(s) before the interrupt is requested */ 724691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 725eb70e5abSAlexander Shishkin ret = ci_hdrc_host_init(ci); 726eb70e5abSAlexander Shishkin if (ret) 727eb70e5abSAlexander Shishkin dev_info(dev, "doesn't support host\n"); 728691962d1SSascha Hauer } 729eb70e5abSAlexander Shishkin 730691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 7315f36e231SAlexander Shishkin ret = ci_hdrc_gadget_init(ci); 732e443b333SAlexander Shishkin if (ret) 7335f36e231SAlexander Shishkin dev_info(dev, "doesn't support gadget\n"); 734691962d1SSascha Hauer } 7355f36e231SAlexander Shishkin 7365f36e231SAlexander Shishkin if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { 7375f36e231SAlexander Shishkin dev_err(dev, "no supported roles\n"); 73874475edeSPeter Chen ret = -ENODEV; 739c859aa65SPeter Chen goto deinit_phy; 740cbec6bd5SPeter Chen } 741cbec6bd5SPeter Chen 74227c62c2dSPeter Chen if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) { 74390893b90SPeter Chen /* Disable and clear all OTG irq */ 74490893b90SPeter Chen hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, 74590893b90SPeter Chen OTGSC_INT_STATUS_BITS); 746cbec6bd5SPeter Chen ret = ci_hdrc_otg_init(ci); 747cbec6bd5SPeter Chen if (ret) { 748cbec6bd5SPeter Chen dev_err(dev, "init otg fails, ret = %d\n", ret); 749cbec6bd5SPeter Chen goto stop; 750cbec6bd5SPeter Chen } 7515f36e231SAlexander Shishkin } 7525f36e231SAlexander Shishkin 7535f36e231SAlexander Shishkin if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { 754577b232fSPeter Chen if (ci->is_otg) { 7555f36e231SAlexander Shishkin ci->role = ci_otg_role(ci); 7560c33bf78SLi Jun /* Enable ID change irq */ 7570c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); 758577b232fSPeter Chen } else { 759577b232fSPeter Chen /* 760577b232fSPeter Chen * If the controller is not OTG capable, but support 761577b232fSPeter Chen * role switch, the defalt role is gadget, and the 762577b232fSPeter Chen * user can switch it through debugfs. 763577b232fSPeter Chen */ 764577b232fSPeter Chen ci->role = CI_ROLE_GADGET; 765577b232fSPeter Chen } 7665f36e231SAlexander Shishkin } else { 7675f36e231SAlexander Shishkin ci->role = ci->roles[CI_ROLE_HOST] 7685f36e231SAlexander Shishkin ? CI_ROLE_HOST 7695f36e231SAlexander Shishkin : CI_ROLE_GADGET; 7705f36e231SAlexander Shishkin } 7715f36e231SAlexander Shishkin 7725a1e1456SPeter Chen /* only update vbus status for peripheral */ 7735a1e1456SPeter Chen if (ci->role == CI_ROLE_GADGET) 7745a1e1456SPeter Chen ci_handle_vbus_change(ci); 7755a1e1456SPeter Chen 7764dcf720cSLi Jun if (!ci_otg_is_fsm_mode(ci)) { 7775f36e231SAlexander Shishkin ret = ci_role_start(ci, ci->role); 7785f36e231SAlexander Shishkin if (ret) { 7794dcf720cSLi Jun dev_err(dev, "can't start %s role\n", 7804dcf720cSLi Jun ci_role(ci)->name); 781cbec6bd5SPeter Chen goto stop; 7825f36e231SAlexander Shishkin } 7834dcf720cSLi Jun } 7845f36e231SAlexander Shishkin 78524c498dfSPeter Chen platform_set_drvdata(pdev, ci); 7864c503dd5SPeter Chen ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, 7874c503dd5SPeter Chen ci->platdata->name, ci); 7885f36e231SAlexander Shishkin if (ret) 7895f36e231SAlexander Shishkin goto stop; 7905f36e231SAlexander Shishkin 7914dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) 7924dcf720cSLi Jun ci_hdrc_otg_fsm_start(ci); 7934dcf720cSLi Jun 794adf0f735SAlexander Shishkin ret = dbg_create_files(ci); 795adf0f735SAlexander Shishkin if (!ret) 796adf0f735SAlexander Shishkin return 0; 7975f36e231SAlexander Shishkin 7985f36e231SAlexander Shishkin stop: 7993f124d23SPeter Chen ci_role_destroy(ci); 800c859aa65SPeter Chen deinit_phy: 8011e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 802e443b333SAlexander Shishkin 803e443b333SAlexander Shishkin return ret; 804e443b333SAlexander Shishkin } 805e443b333SAlexander Shishkin 806fb4e98abSBill Pemberton static int ci_hdrc_remove(struct platform_device *pdev) 807e443b333SAlexander Shishkin { 8088e22978cSAlexander Shishkin struct ci_hdrc *ci = platform_get_drvdata(pdev); 809e443b333SAlexander Shishkin 810adf0f735SAlexander Shishkin dbg_remove_files(ci); 8113f124d23SPeter Chen ci_role_destroy(ci); 812864cf949SPeter Chen ci_hdrc_enter_lpm(ci, true); 8131e5e2d3dSAntoine Tenart ci_usb_phy_exit(ci); 814e443b333SAlexander Shishkin 815e443b333SAlexander Shishkin return 0; 816e443b333SAlexander Shishkin } 817e443b333SAlexander Shishkin 8188076932fSPeter Chen #ifdef CONFIG_PM_SLEEP 8198076932fSPeter Chen static void ci_controller_suspend(struct ci_hdrc *ci) 8208076932fSPeter Chen { 8218076932fSPeter Chen ci_hdrc_enter_lpm(ci, true); 8228076932fSPeter Chen 8238076932fSPeter Chen if (ci->usb_phy) 8248076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 1); 8258076932fSPeter Chen } 8268076932fSPeter Chen 8278076932fSPeter Chen static int ci_controller_resume(struct device *dev) 8288076932fSPeter Chen { 8298076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 8308076932fSPeter Chen 8318076932fSPeter Chen dev_dbg(dev, "at %s\n", __func__); 8328076932fSPeter Chen 8338076932fSPeter Chen ci_hdrc_enter_lpm(ci, false); 8348076932fSPeter Chen 8358076932fSPeter Chen if (ci->usb_phy) { 8368076932fSPeter Chen usb_phy_set_suspend(ci->usb_phy, 0); 8378076932fSPeter Chen usb_phy_set_wakeup(ci->usb_phy, false); 8388076932fSPeter Chen hw_wait_phy_stable(); 8398076932fSPeter Chen } 8408076932fSPeter Chen 8418076932fSPeter Chen return 0; 8428076932fSPeter Chen } 8438076932fSPeter Chen 8448076932fSPeter Chen static int ci_suspend(struct device *dev) 8458076932fSPeter Chen { 8468076932fSPeter Chen struct ci_hdrc *ci = dev_get_drvdata(dev); 8478076932fSPeter Chen 8488076932fSPeter Chen if (ci->wq) 8498076932fSPeter Chen flush_workqueue(ci->wq); 8508076932fSPeter Chen 8518076932fSPeter Chen ci_controller_suspend(ci); 8528076932fSPeter Chen 8538076932fSPeter Chen return 0; 8548076932fSPeter Chen } 8558076932fSPeter Chen 8568076932fSPeter Chen static int ci_resume(struct device *dev) 8578076932fSPeter Chen { 8588076932fSPeter Chen return ci_controller_resume(dev); 8598076932fSPeter Chen } 8608076932fSPeter Chen #endif /* CONFIG_PM_SLEEP */ 8618076932fSPeter Chen 8628076932fSPeter Chen static const struct dev_pm_ops ci_pm_ops = { 8638076932fSPeter Chen SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume) 8648076932fSPeter Chen }; 8655f36e231SAlexander Shishkin static struct platform_driver ci_hdrc_driver = { 8665f36e231SAlexander Shishkin .probe = ci_hdrc_probe, 8677690417dSBill Pemberton .remove = ci_hdrc_remove, 868e443b333SAlexander Shishkin .driver = { 8695f36e231SAlexander Shishkin .name = "ci_hdrc", 8708076932fSPeter Chen .pm = &ci_pm_ops, 871e443b333SAlexander Shishkin }, 872e443b333SAlexander Shishkin }; 873e443b333SAlexander Shishkin 8745f36e231SAlexander Shishkin module_platform_driver(ci_hdrc_driver); 875e443b333SAlexander Shishkin 8765f36e231SAlexander Shishkin MODULE_ALIAS("platform:ci_hdrc"); 877e443b333SAlexander Shishkin MODULE_LICENSE("GPL v2"); 878e443b333SAlexander Shishkin MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); 8795f36e231SAlexander Shishkin MODULE_DESCRIPTION("ChipIdea HDRC Driver"); 880