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 26e443b333SAlexander Shishkin * - CONFIG_USB_GADGET_DEBUG_FILES: 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 45e4ce4ecdSMichael Grzeschik * - Interrupt Traffic 46e443b333SAlexander Shishkin * - GET_STATUS(device) - always reports 0 47e443b333SAlexander Shishkin * - Gadget API (majority of optional features) 48e443b333SAlexander Shishkin * - Suspend & Remote Wakeup 49e443b333SAlexander Shishkin */ 50e443b333SAlexander Shishkin #include <linux/delay.h> 51e443b333SAlexander Shishkin #include <linux/device.h> 52e443b333SAlexander Shishkin #include <linux/dma-mapping.h> 53e443b333SAlexander Shishkin #include <linux/platform_device.h> 54e443b333SAlexander Shishkin #include <linux/module.h> 55fe6e125eSRichard Zhao #include <linux/idr.h> 56e443b333SAlexander Shishkin #include <linux/interrupt.h> 57e443b333SAlexander Shishkin #include <linux/io.h> 58e443b333SAlexander Shishkin #include <linux/kernel.h> 59e443b333SAlexander Shishkin #include <linux/slab.h> 60e443b333SAlexander Shishkin #include <linux/pm_runtime.h> 61e443b333SAlexander Shishkin #include <linux/usb/ch9.h> 62e443b333SAlexander Shishkin #include <linux/usb/gadget.h> 63e443b333SAlexander Shishkin #include <linux/usb/otg.h> 64e443b333SAlexander Shishkin #include <linux/usb/chipidea.h> 6540dcd0e8SMichael Grzeschik #include <linux/usb/of.h> 664f6743d5SMichael Grzeschik #include <linux/of.h> 6740dcd0e8SMichael Grzeschik #include <linux/phy.h> 681542d9c3SPeter Chen #include <linux/regulator/consumer.h> 69e443b333SAlexander Shishkin 70e443b333SAlexander Shishkin #include "ci.h" 71e443b333SAlexander Shishkin #include "udc.h" 72e443b333SAlexander Shishkin #include "bits.h" 73eb70e5abSAlexander Shishkin #include "host.h" 74e443b333SAlexander Shishkin #include "debug.h" 75c10b4f03SPeter Chen #include "otg.h" 764dcf720cSLi Jun #include "otg_fsm.h" 77e443b333SAlexander Shishkin 785f36e231SAlexander Shishkin /* Controller register map */ 79987e7bc3SMarc Kleine-Budde static const u8 ci_regs_nolpm[] = { 80987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 81987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 82987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 83987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0x38U, 84987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 85987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 86987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 87987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 88987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 89987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 90987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 91987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0x64U, 92987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0x68U, 93987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0x6CU, 94987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0x70U, 95987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0x74U, 96987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0x78U, 97987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0x7CU, 98987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0x80U, 99e443b333SAlexander Shishkin }; 100e443b333SAlexander Shishkin 101987e7bc3SMarc Kleine-Budde static const u8 ci_regs_lpm[] = { 102987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 103987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 104987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 105987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0xFCU, 106987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 107987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 108987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 109987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 110987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 111987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 112987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 113987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0xC4U, 114987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0xC8U, 115987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0xD8U, 116987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0xDCU, 117987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0xE0U, 118987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0xE4U, 119987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0xE8U, 120987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0xECU, 121e443b333SAlexander Shishkin }; 122e443b333SAlexander Shishkin 1238e22978cSAlexander Shishkin static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) 124e443b333SAlexander Shishkin { 125e443b333SAlexander Shishkin int i; 126e443b333SAlexander Shishkin 127e443b333SAlexander Shishkin for (i = 0; i < OP_ENDPTCTRL; i++) 1285f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = 1295f36e231SAlexander Shishkin (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + 130e443b333SAlexander Shishkin (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); 131e443b333SAlexander Shishkin 132e443b333SAlexander Shishkin for (; i <= OP_LAST; i++) 1335f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = ci->hw_bank.op + 134e443b333SAlexander Shishkin 4 * (i - OP_ENDPTCTRL) + 135e443b333SAlexander Shishkin (is_lpm 136e443b333SAlexander Shishkin ? ci_regs_lpm[OP_ENDPTCTRL] 137e443b333SAlexander Shishkin : ci_regs_nolpm[OP_ENDPTCTRL]); 138e443b333SAlexander Shishkin 139e443b333SAlexander Shishkin return 0; 140e443b333SAlexander Shishkin } 141e443b333SAlexander Shishkin 142e443b333SAlexander Shishkin /** 14336304b06SLi Jun * hw_read_intr_enable: returns interrupt enable register 14436304b06SLi Jun * 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 * 15536304b06SLi Jun * This function returns register data 15636304b06SLi Jun */ 15736304b06SLi Jun u32 hw_read_intr_status(struct ci_hdrc *ci) 15836304b06SLi Jun { 15936304b06SLi Jun return hw_read(ci, OP_USBSTS, ~0); 16036304b06SLi Jun } 16136304b06SLi Jun 16236304b06SLi Jun /** 163e443b333SAlexander Shishkin * hw_port_test_set: writes port test mode (execute without interruption) 164e443b333SAlexander Shishkin * @mode: new value 165e443b333SAlexander Shishkin * 166e443b333SAlexander Shishkin * This function returns an error code 167e443b333SAlexander Shishkin */ 1688e22978cSAlexander Shishkin int hw_port_test_set(struct ci_hdrc *ci, u8 mode) 169e443b333SAlexander Shishkin { 170e443b333SAlexander Shishkin const u8 TEST_MODE_MAX = 7; 171e443b333SAlexander Shishkin 172e443b333SAlexander Shishkin if (mode > TEST_MODE_MAX) 173e443b333SAlexander Shishkin return -EINVAL; 174e443b333SAlexander Shishkin 175727b4ddbSFelipe Balbi hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC)); 176e443b333SAlexander Shishkin return 0; 177e443b333SAlexander Shishkin } 178e443b333SAlexander Shishkin 179e443b333SAlexander Shishkin /** 180e443b333SAlexander Shishkin * hw_port_test_get: reads port test mode value 181e443b333SAlexander Shishkin * 182e443b333SAlexander Shishkin * This function returns port test mode value 183e443b333SAlexander Shishkin */ 1848e22978cSAlexander Shishkin u8 hw_port_test_get(struct ci_hdrc *ci) 185e443b333SAlexander Shishkin { 186727b4ddbSFelipe Balbi return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); 187e443b333SAlexander Shishkin } 188e443b333SAlexander Shishkin 189864cf949SPeter Chen /* The PHY enters/leaves low power mode */ 190864cf949SPeter Chen static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) 191864cf949SPeter Chen { 192864cf949SPeter Chen enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; 193864cf949SPeter Chen bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); 194864cf949SPeter Chen 195864cf949SPeter Chen if (enable && !lpm) { 196864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 197864cf949SPeter Chen PORTSC_PHCD(ci->hw_bank.lpm)); 198864cf949SPeter Chen } else if (!enable && lpm) { 199864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 200864cf949SPeter Chen 0); 201864cf949SPeter Chen /* 20290893b90SPeter Chen * the PHY needs some time (less 203864cf949SPeter Chen * than 1ms) to leave low power mode. 204864cf949SPeter Chen */ 20590893b90SPeter Chen usleep_range(1000, 1100); 206864cf949SPeter Chen } 207864cf949SPeter Chen } 208864cf949SPeter Chen 2098e22978cSAlexander Shishkin static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) 210e443b333SAlexander Shishkin { 211e443b333SAlexander Shishkin u32 reg; 212e443b333SAlexander Shishkin 213e443b333SAlexander Shishkin /* bank is a module variable */ 2145f36e231SAlexander Shishkin ci->hw_bank.abs = base; 215e443b333SAlexander Shishkin 2165f36e231SAlexander Shishkin ci->hw_bank.cap = ci->hw_bank.abs; 21777c4400fSRichard Zhao ci->hw_bank.cap += ci->platdata->capoffset; 218938d323fSSvetoslav Neykov ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); 219e443b333SAlexander Shishkin 2205f36e231SAlexander Shishkin hw_alloc_regmap(ci, false); 2215f36e231SAlexander Shishkin reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> 222727b4ddbSFelipe Balbi __ffs(HCCPARAMS_LEN); 2235f36e231SAlexander Shishkin ci->hw_bank.lpm = reg; 224aeb2c121SChris Ruehl if (reg) 2255f36e231SAlexander Shishkin hw_alloc_regmap(ci, !!reg); 2265f36e231SAlexander Shishkin ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; 2275f36e231SAlexander Shishkin ci->hw_bank.size += OP_LAST; 2285f36e231SAlexander Shishkin ci->hw_bank.size /= sizeof(u32); 229e443b333SAlexander Shishkin 2305f36e231SAlexander Shishkin reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> 231727b4ddbSFelipe Balbi __ffs(DCCPARAMS_DEN); 2325f36e231SAlexander Shishkin ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 233e443b333SAlexander Shishkin 23409c94e62SRichard Zhao if (ci->hw_ep_max > ENDPT_MAX) 235e443b333SAlexander Shishkin return -ENODEV; 236e443b333SAlexander Shishkin 237864cf949SPeter Chen ci_hdrc_enter_lpm(ci, false); 238864cf949SPeter Chen 239c344b518SPeter Chen /* Disable all interrupts bits */ 240c344b518SPeter Chen hw_write(ci, OP_USBINTR, 0xffffffff, 0); 241c344b518SPeter Chen 242c344b518SPeter Chen /* Clear all interrupts status bits*/ 243c344b518SPeter Chen hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff); 244c344b518SPeter Chen 2455f36e231SAlexander Shishkin dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n", 2465f36e231SAlexander Shishkin ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); 247e443b333SAlexander Shishkin 248e443b333SAlexander Shishkin /* setup lock mode ? */ 249e443b333SAlexander Shishkin 250e443b333SAlexander Shishkin /* ENDPTSETUPSTAT is '0' by default */ 251e443b333SAlexander Shishkin 252e443b333SAlexander Shishkin /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 253e443b333SAlexander Shishkin 254e443b333SAlexander Shishkin return 0; 255e443b333SAlexander Shishkin } 256e443b333SAlexander Shishkin 2578e22978cSAlexander Shishkin static void hw_phymode_configure(struct ci_hdrc *ci) 25840dcd0e8SMichael Grzeschik { 2593b5d3e68SChris Ruehl u32 portsc, lpm, sts = 0; 26040dcd0e8SMichael Grzeschik 26140dcd0e8SMichael Grzeschik switch (ci->platdata->phy_mode) { 26240dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMI: 26340dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI); 26440dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI); 26540dcd0e8SMichael Grzeschik break; 26640dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMIW: 26740dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW; 26840dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW; 26940dcd0e8SMichael Grzeschik break; 27040dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_ULPI: 27140dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_ULPI); 27240dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_ULPI); 27340dcd0e8SMichael Grzeschik break; 27440dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_SERIAL: 27540dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_SERIAL); 27640dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_SERIAL); 27740dcd0e8SMichael Grzeschik sts = 1; 27840dcd0e8SMichael Grzeschik break; 27940dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_HSIC: 28040dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_HSIC); 28140dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_HSIC); 28240dcd0e8SMichael Grzeschik break; 28340dcd0e8SMichael Grzeschik default: 28440dcd0e8SMichael Grzeschik return; 28540dcd0e8SMichael Grzeschik } 28640dcd0e8SMichael Grzeschik 28740dcd0e8SMichael Grzeschik if (ci->hw_bank.lpm) { 28840dcd0e8SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm); 2893b5d3e68SChris Ruehl if (sts) 2903b5d3e68SChris Ruehl hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS); 29140dcd0e8SMichael Grzeschik } else { 29240dcd0e8SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); 2933b5d3e68SChris Ruehl if (sts) 2943b5d3e68SChris Ruehl hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); 29540dcd0e8SMichael Grzeschik } 29640dcd0e8SMichael Grzeschik } 29740dcd0e8SMichael Grzeschik 298e443b333SAlexander Shishkin /** 299d03cccffSPeter Chen * ci_usb_phy_init: initialize phy according to different phy type 300d03cccffSPeter Chen * @ci: the controller 301d03cccffSPeter Chen * 302d03cccffSPeter Chen * This function returns an error code if usb_phy_init has failed 303d03cccffSPeter Chen */ 304d03cccffSPeter Chen static int ci_usb_phy_init(struct ci_hdrc *ci) 305d03cccffSPeter Chen { 306d03cccffSPeter Chen int ret; 307d03cccffSPeter Chen 308d03cccffSPeter Chen switch (ci->platdata->phy_mode) { 309d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMI: 310d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_UTMIW: 311d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_HSIC: 312d03cccffSPeter Chen ret = usb_phy_init(ci->transceiver); 313d03cccffSPeter Chen if (ret) 314d03cccffSPeter Chen return ret; 315d03cccffSPeter Chen hw_phymode_configure(ci); 316d03cccffSPeter Chen break; 317d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_ULPI: 318d03cccffSPeter Chen case USBPHY_INTERFACE_MODE_SERIAL: 319d03cccffSPeter Chen hw_phymode_configure(ci); 320d03cccffSPeter Chen ret = usb_phy_init(ci->transceiver); 321d03cccffSPeter Chen if (ret) 322d03cccffSPeter Chen return ret; 323d03cccffSPeter Chen break; 324d03cccffSPeter Chen default: 325d03cccffSPeter Chen ret = usb_phy_init(ci->transceiver); 326d03cccffSPeter Chen } 327d03cccffSPeter Chen 328d03cccffSPeter Chen return ret; 329d03cccffSPeter Chen } 330d03cccffSPeter Chen 331d03cccffSPeter Chen /** 332e443b333SAlexander Shishkin * hw_device_reset: resets chip (execute without interruption) 333e443b333SAlexander Shishkin * @ci: the controller 334e443b333SAlexander Shishkin * 335e443b333SAlexander Shishkin * This function returns an error code 336e443b333SAlexander Shishkin */ 3378e22978cSAlexander Shishkin int hw_device_reset(struct ci_hdrc *ci, u32 mode) 338e443b333SAlexander Shishkin { 339e443b333SAlexander Shishkin /* should flush & stop before reset */ 340e443b333SAlexander Shishkin hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); 341e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 342e443b333SAlexander Shishkin 343e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); 344e443b333SAlexander Shishkin while (hw_read(ci, OP_USBCMD, USBCMD_RST)) 345e443b333SAlexander Shishkin udelay(10); /* not RTOS friendly */ 346e443b333SAlexander Shishkin 34777c4400fSRichard Zhao if (ci->platdata->notify_event) 34877c4400fSRichard Zhao ci->platdata->notify_event(ci, 3498e22978cSAlexander Shishkin CI_HDRC_CONTROLLER_RESET_EVENT); 350e443b333SAlexander Shishkin 3518e22978cSAlexander Shishkin if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) 352758fc986SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); 353e443b333SAlexander Shishkin 3544f6743d5SMichael Grzeschik if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { 3554f6743d5SMichael Grzeschik if (ci->hw_bank.lpm) 3564f6743d5SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); 3574f6743d5SMichael Grzeschik else 3584f6743d5SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); 3594f6743d5SMichael Grzeschik } 3604f6743d5SMichael Grzeschik 361e443b333SAlexander Shishkin /* USBMODE should be configured step by step */ 362e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 363eb70e5abSAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, mode); 364e443b333SAlexander Shishkin /* HW >= 2.3 */ 365e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); 366e443b333SAlexander Shishkin 367eb70e5abSAlexander Shishkin if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) { 368eb70e5abSAlexander Shishkin pr_err("cannot enter in %s mode", ci_role(ci)->name); 369e443b333SAlexander Shishkin pr_err("lpm = %i", ci->hw_bank.lpm); 370e443b333SAlexander Shishkin return -ENODEV; 371e443b333SAlexander Shishkin } 372e443b333SAlexander Shishkin 373e443b333SAlexander Shishkin return 0; 374e443b333SAlexander Shishkin } 375e443b333SAlexander Shishkin 37622fa8445SPeter Chen /** 37722fa8445SPeter Chen * hw_wait_reg: wait the register value 37822fa8445SPeter Chen * 37922fa8445SPeter Chen * Sometimes, it needs to wait register value before going on. 38022fa8445SPeter Chen * Eg, when switch to device mode, the vbus value should be lower 38122fa8445SPeter Chen * than OTGSC_BSV before connects to host. 38222fa8445SPeter Chen * 38322fa8445SPeter Chen * @ci: the controller 38422fa8445SPeter Chen * @reg: register index 38522fa8445SPeter Chen * @mask: mast bit 38622fa8445SPeter Chen * @value: the bit value to wait 38722fa8445SPeter Chen * @timeout_ms: timeout in millisecond 38822fa8445SPeter Chen * 38922fa8445SPeter Chen * This function returns an error code if timeout 39022fa8445SPeter Chen */ 39122fa8445SPeter Chen int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, 39222fa8445SPeter Chen u32 value, unsigned int timeout_ms) 39322fa8445SPeter Chen { 39422fa8445SPeter Chen unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); 39522fa8445SPeter Chen 39622fa8445SPeter Chen while (hw_read(ci, reg, mask) != value) { 39722fa8445SPeter Chen if (time_after(jiffies, elapse)) { 39822fa8445SPeter Chen dev_err(ci->dev, "timeout waiting for %08x in %d\n", 39922fa8445SPeter Chen mask, reg); 40022fa8445SPeter Chen return -ETIMEDOUT; 40122fa8445SPeter Chen } 40222fa8445SPeter Chen msleep(20); 40322fa8445SPeter Chen } 40422fa8445SPeter Chen 40522fa8445SPeter Chen return 0; 40622fa8445SPeter Chen } 40722fa8445SPeter Chen 4085f36e231SAlexander Shishkin static irqreturn_t ci_irq(int irq, void *data) 4095f36e231SAlexander Shishkin { 4108e22978cSAlexander Shishkin struct ci_hdrc *ci = data; 4115f36e231SAlexander Shishkin irqreturn_t ret = IRQ_NONE; 412b183c19fSRichard Zhao u32 otgsc = 0; 4135f36e231SAlexander Shishkin 4144dcf720cSLi Jun if (ci->is_otg) { 4150c33bf78SLi Jun otgsc = hw_read_otgsc(ci, ~0); 4164dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) { 4174dcf720cSLi Jun ret = ci_otg_fsm_irq(ci); 4184dcf720cSLi Jun if (ret == IRQ_HANDLED) 4194dcf720cSLi Jun return ret; 4204dcf720cSLi Jun } 4214dcf720cSLi Jun } 4225f36e231SAlexander Shishkin 423a107f8c5SPeter Chen /* 424a107f8c5SPeter Chen * Handle id change interrupt, it indicates device/host function 425a107f8c5SPeter Chen * switch. 426a107f8c5SPeter Chen */ 427a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { 428a107f8c5SPeter Chen ci->id_event = true; 4290c33bf78SLi Jun /* Clear ID change irq status */ 4300c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); 431b183c19fSRichard Zhao disable_irq_nosync(ci->irq); 4325f36e231SAlexander Shishkin queue_work(ci->wq, &ci->work); 433a107f8c5SPeter Chen return IRQ_HANDLED; 4345f36e231SAlexander Shishkin } 4355f36e231SAlexander Shishkin 436a107f8c5SPeter Chen /* 437a107f8c5SPeter Chen * Handle vbus change interrupt, it indicates device connection 438a107f8c5SPeter Chen * and disconnection events. 439a107f8c5SPeter Chen */ 440a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { 441a107f8c5SPeter Chen ci->b_sess_valid_event = true; 4420c33bf78SLi Jun /* Clear BSV irq */ 4430c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); 444a107f8c5SPeter Chen disable_irq_nosync(ci->irq); 445a107f8c5SPeter Chen queue_work(ci->wq, &ci->work); 446a107f8c5SPeter Chen return IRQ_HANDLED; 447a107f8c5SPeter Chen } 448a107f8c5SPeter Chen 449a107f8c5SPeter Chen /* Handle device/host interrupt */ 450a107f8c5SPeter Chen if (ci->role != CI_ROLE_END) 451a107f8c5SPeter Chen ret = ci_role(ci)->irq(ci); 452a107f8c5SPeter Chen 453b183c19fSRichard Zhao return ret; 4545f36e231SAlexander Shishkin } 4555f36e231SAlexander Shishkin 4561542d9c3SPeter Chen static int ci_get_platdata(struct device *dev, 4571542d9c3SPeter Chen struct ci_hdrc_platform_data *platdata) 4581542d9c3SPeter Chen { 459c22600c3SPeter Chen if (!platdata->phy_mode) 460c22600c3SPeter Chen platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); 461c22600c3SPeter Chen 462c22600c3SPeter Chen if (!platdata->dr_mode) 463c22600c3SPeter Chen platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); 464c22600c3SPeter Chen 465c22600c3SPeter Chen if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) 466c22600c3SPeter Chen platdata->dr_mode = USB_DR_MODE_OTG; 467c22600c3SPeter Chen 468c2ec3a73SPeter Chen if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { 469c2ec3a73SPeter Chen /* Get the vbus regulator */ 470c2ec3a73SPeter Chen platdata->reg_vbus = devm_regulator_get(dev, "vbus"); 471c2ec3a73SPeter Chen if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { 472c2ec3a73SPeter Chen return -EPROBE_DEFER; 473c2ec3a73SPeter Chen } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { 474c2ec3a73SPeter Chen /* no vbus regualator is needed */ 475c2ec3a73SPeter Chen platdata->reg_vbus = NULL; 476c2ec3a73SPeter Chen } else if (IS_ERR(platdata->reg_vbus)) { 477c2ec3a73SPeter Chen dev_err(dev, "Getting regulator error: %ld\n", 478c2ec3a73SPeter Chen PTR_ERR(platdata->reg_vbus)); 479c2ec3a73SPeter Chen return PTR_ERR(platdata->reg_vbus); 480c2ec3a73SPeter Chen } 481c2ec3a73SPeter Chen } 482c2ec3a73SPeter Chen 4834f6743d5SMichael Grzeschik if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) 4844f6743d5SMichael Grzeschik platdata->flags |= CI_HDRC_FORCE_FULLSPEED; 4854f6743d5SMichael Grzeschik 4861542d9c3SPeter Chen return 0; 4871542d9c3SPeter Chen } 4881542d9c3SPeter Chen 489fe6e125eSRichard Zhao static DEFINE_IDA(ci_ida); 490fe6e125eSRichard Zhao 4918e22978cSAlexander Shishkin struct platform_device *ci_hdrc_add_device(struct device *dev, 492cbc6dc2aSRichard Zhao struct resource *res, int nres, 4938e22978cSAlexander Shishkin struct ci_hdrc_platform_data *platdata) 494cbc6dc2aSRichard Zhao { 495cbc6dc2aSRichard Zhao struct platform_device *pdev; 496fe6e125eSRichard Zhao int id, ret; 497cbc6dc2aSRichard Zhao 4981542d9c3SPeter Chen ret = ci_get_platdata(dev, platdata); 4991542d9c3SPeter Chen if (ret) 5001542d9c3SPeter Chen return ERR_PTR(ret); 5011542d9c3SPeter Chen 502fe6e125eSRichard Zhao id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); 503fe6e125eSRichard Zhao if (id < 0) 504fe6e125eSRichard Zhao return ERR_PTR(id); 505fe6e125eSRichard Zhao 506fe6e125eSRichard Zhao pdev = platform_device_alloc("ci_hdrc", id); 507fe6e125eSRichard Zhao if (!pdev) { 508fe6e125eSRichard Zhao ret = -ENOMEM; 509fe6e125eSRichard Zhao goto put_id; 510fe6e125eSRichard Zhao } 511cbc6dc2aSRichard Zhao 512cbc6dc2aSRichard Zhao pdev->dev.parent = dev; 513cbc6dc2aSRichard Zhao pdev->dev.dma_mask = dev->dma_mask; 514cbc6dc2aSRichard Zhao pdev->dev.dma_parms = dev->dma_parms; 515cbc6dc2aSRichard Zhao dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask); 516cbc6dc2aSRichard Zhao 517cbc6dc2aSRichard Zhao ret = platform_device_add_resources(pdev, res, nres); 518cbc6dc2aSRichard Zhao if (ret) 519cbc6dc2aSRichard Zhao goto err; 520cbc6dc2aSRichard Zhao 521cbc6dc2aSRichard Zhao ret = platform_device_add_data(pdev, platdata, sizeof(*platdata)); 522cbc6dc2aSRichard Zhao if (ret) 523cbc6dc2aSRichard Zhao goto err; 524cbc6dc2aSRichard Zhao 525cbc6dc2aSRichard Zhao ret = platform_device_add(pdev); 526cbc6dc2aSRichard Zhao if (ret) 527cbc6dc2aSRichard Zhao goto err; 528cbc6dc2aSRichard Zhao 529cbc6dc2aSRichard Zhao return pdev; 530cbc6dc2aSRichard Zhao 531cbc6dc2aSRichard Zhao err: 532cbc6dc2aSRichard Zhao platform_device_put(pdev); 533fe6e125eSRichard Zhao put_id: 534fe6e125eSRichard Zhao ida_simple_remove(&ci_ida, id); 535cbc6dc2aSRichard Zhao return ERR_PTR(ret); 536cbc6dc2aSRichard Zhao } 5378e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_add_device); 538cbc6dc2aSRichard Zhao 5398e22978cSAlexander Shishkin void ci_hdrc_remove_device(struct platform_device *pdev) 540cbc6dc2aSRichard Zhao { 54198c35534SLothar Waßmann int id = pdev->id; 542cbc6dc2aSRichard Zhao platform_device_unregister(pdev); 54398c35534SLothar Waßmann ida_simple_remove(&ci_ida, id); 544cbc6dc2aSRichard Zhao } 5458e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); 546cbc6dc2aSRichard Zhao 5473f124d23SPeter Chen static inline void ci_role_destroy(struct ci_hdrc *ci) 5483f124d23SPeter Chen { 5493f124d23SPeter Chen ci_hdrc_gadget_destroy(ci); 5503f124d23SPeter Chen ci_hdrc_host_destroy(ci); 551cbec6bd5SPeter Chen if (ci->is_otg) 552cbec6bd5SPeter Chen ci_hdrc_otg_destroy(ci); 5533f124d23SPeter Chen } 5543f124d23SPeter Chen 555577b232fSPeter Chen static void ci_get_otg_capable(struct ci_hdrc *ci) 556577b232fSPeter Chen { 557577b232fSPeter Chen if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) 558577b232fSPeter Chen ci->is_otg = false; 559577b232fSPeter Chen else 560577b232fSPeter Chen ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, 561577b232fSPeter Chen DCCPARAMS_DC | DCCPARAMS_HC) 562577b232fSPeter Chen == (DCCPARAMS_DC | DCCPARAMS_HC)); 56390893b90SPeter Chen if (ci->is_otg) 564577b232fSPeter Chen dev_dbg(ci->dev, "It is OTG capable controller\n"); 565577b232fSPeter Chen } 566577b232fSPeter Chen 56741ac7b3aSBill Pemberton static int ci_hdrc_probe(struct platform_device *pdev) 568e443b333SAlexander Shishkin { 569e443b333SAlexander Shishkin struct device *dev = &pdev->dev; 5708e22978cSAlexander Shishkin struct ci_hdrc *ci; 571e443b333SAlexander Shishkin struct resource *res; 572e443b333SAlexander Shishkin void __iomem *base; 573e443b333SAlexander Shishkin int ret; 574691962d1SSascha Hauer enum usb_dr_mode dr_mode; 575e443b333SAlexander Shishkin 576fad56745SJingoo Han if (!dev_get_platdata(dev)) { 577e443b333SAlexander Shishkin dev_err(dev, "platform data missing\n"); 578e443b333SAlexander Shishkin return -ENODEV; 579e443b333SAlexander Shishkin } 580e443b333SAlexander Shishkin 581e443b333SAlexander Shishkin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 58219290816SFelipe Balbi base = devm_ioremap_resource(dev, res); 58319290816SFelipe Balbi if (IS_ERR(base)) 58419290816SFelipe Balbi return PTR_ERR(base); 585e443b333SAlexander Shishkin 5865f36e231SAlexander Shishkin ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); 5875f36e231SAlexander Shishkin if (!ci) { 5885f36e231SAlexander Shishkin dev_err(dev, "can't allocate device\n"); 5895f36e231SAlexander Shishkin return -ENOMEM; 5905f36e231SAlexander Shishkin } 591e443b333SAlexander Shishkin 5925f36e231SAlexander Shishkin ci->dev = dev; 593fad56745SJingoo Han ci->platdata = dev_get_platdata(dev); 594ed8f8318SPeter Chen ci->imx28_write_fix = !!(ci->platdata->flags & 595ed8f8318SPeter Chen CI_HDRC_IMX28_WRITE_FIX); 5965f36e231SAlexander Shishkin 5975f36e231SAlexander Shishkin ret = hw_device_init(ci, base); 5985f36e231SAlexander Shishkin if (ret < 0) { 5995f36e231SAlexander Shishkin dev_err(dev, "can't initialize hardware\n"); 6005f36e231SAlexander Shishkin return -ENODEV; 6015f36e231SAlexander Shishkin } 6025f36e231SAlexander Shishkin 603c859aa65SPeter Chen if (ci->platdata->phy) 604c859aa65SPeter Chen ci->transceiver = ci->platdata->phy; 605c859aa65SPeter Chen else 606c859aa65SPeter Chen ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 607c859aa65SPeter Chen 608c859aa65SPeter Chen if (IS_ERR(ci->transceiver)) { 609c859aa65SPeter Chen ret = PTR_ERR(ci->transceiver); 610c859aa65SPeter Chen /* 611c859aa65SPeter Chen * if -ENXIO is returned, it means PHY layer wasn't 612c859aa65SPeter Chen * enabled, so it makes no sense to return -EPROBE_DEFER 613c859aa65SPeter Chen * in that case, since no PHY driver will ever probe. 614c859aa65SPeter Chen */ 615c859aa65SPeter Chen if (ret == -ENXIO) 616c859aa65SPeter Chen return ret; 617c859aa65SPeter Chen 618c859aa65SPeter Chen dev_err(dev, "no usb2 phy configured\n"); 619c859aa65SPeter Chen return -EPROBE_DEFER; 620c859aa65SPeter Chen } 621c859aa65SPeter Chen 622d03cccffSPeter Chen ret = ci_usb_phy_init(ci); 62374475edeSPeter Chen if (ret) { 62474475edeSPeter Chen dev_err(dev, "unable to init phy: %d\n", ret); 62574475edeSPeter Chen return ret; 62690893b90SPeter Chen } else { 62790893b90SPeter Chen /* 62890893b90SPeter Chen * The delay to sync PHY's status, the maximum delay is 62990893b90SPeter Chen * 2ms since the otgsc uses 1ms timer to debounce the 63090893b90SPeter Chen * PHY's input 63190893b90SPeter Chen */ 63290893b90SPeter Chen usleep_range(2000, 2500); 63374475edeSPeter Chen } 63474475edeSPeter Chen 635eb70e5abSAlexander Shishkin ci->hw_bank.phys = res->start; 636eb70e5abSAlexander Shishkin 6375f36e231SAlexander Shishkin ci->irq = platform_get_irq(pdev, 0); 6385f36e231SAlexander Shishkin if (ci->irq < 0) { 639e443b333SAlexander Shishkin dev_err(dev, "missing IRQ\n"); 64042d18212SFabio Estevam ret = ci->irq; 641c859aa65SPeter Chen goto deinit_phy; 642e443b333SAlexander Shishkin } 643e443b333SAlexander Shishkin 644577b232fSPeter Chen ci_get_otg_capable(ci); 645577b232fSPeter Chen 646691962d1SSascha Hauer dr_mode = ci->platdata->dr_mode; 6475f36e231SAlexander Shishkin /* initialize role(s) before the interrupt is requested */ 648691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 649eb70e5abSAlexander Shishkin ret = ci_hdrc_host_init(ci); 650eb70e5abSAlexander Shishkin if (ret) 651eb70e5abSAlexander Shishkin dev_info(dev, "doesn't support host\n"); 652691962d1SSascha Hauer } 653eb70e5abSAlexander Shishkin 654691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 6555f36e231SAlexander Shishkin ret = ci_hdrc_gadget_init(ci); 656e443b333SAlexander Shishkin if (ret) 6575f36e231SAlexander Shishkin dev_info(dev, "doesn't support gadget\n"); 658691962d1SSascha Hauer } 6595f36e231SAlexander Shishkin 6605f36e231SAlexander Shishkin if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { 6615f36e231SAlexander Shishkin dev_err(dev, "no supported roles\n"); 66274475edeSPeter Chen ret = -ENODEV; 663c859aa65SPeter Chen goto deinit_phy; 664cbec6bd5SPeter Chen } 665cbec6bd5SPeter Chen 666cbec6bd5SPeter Chen if (ci->is_otg) { 66790893b90SPeter Chen /* Disable and clear all OTG irq */ 66890893b90SPeter Chen hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, 66990893b90SPeter Chen OTGSC_INT_STATUS_BITS); 670cbec6bd5SPeter Chen ret = ci_hdrc_otg_init(ci); 671cbec6bd5SPeter Chen if (ret) { 672cbec6bd5SPeter Chen dev_err(dev, "init otg fails, ret = %d\n", ret); 673cbec6bd5SPeter Chen goto stop; 674cbec6bd5SPeter Chen } 6755f36e231SAlexander Shishkin } 6765f36e231SAlexander Shishkin 6775f36e231SAlexander Shishkin if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { 678577b232fSPeter Chen if (ci->is_otg) { 6795f36e231SAlexander Shishkin ci->role = ci_otg_role(ci); 6800c33bf78SLi Jun /* Enable ID change irq */ 6810c33bf78SLi Jun hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE); 682577b232fSPeter Chen } else { 683577b232fSPeter Chen /* 684577b232fSPeter Chen * If the controller is not OTG capable, but support 685577b232fSPeter Chen * role switch, the defalt role is gadget, and the 686577b232fSPeter Chen * user can switch it through debugfs. 687577b232fSPeter Chen */ 688577b232fSPeter Chen ci->role = CI_ROLE_GADGET; 689577b232fSPeter Chen } 6905f36e231SAlexander Shishkin } else { 6915f36e231SAlexander Shishkin ci->role = ci->roles[CI_ROLE_HOST] 6925f36e231SAlexander Shishkin ? CI_ROLE_HOST 6935f36e231SAlexander Shishkin : CI_ROLE_GADGET; 6945f36e231SAlexander Shishkin } 6955f36e231SAlexander Shishkin 6965a1e1456SPeter Chen /* only update vbus status for peripheral */ 6975a1e1456SPeter Chen if (ci->role == CI_ROLE_GADGET) 6985a1e1456SPeter Chen ci_handle_vbus_change(ci); 6995a1e1456SPeter Chen 7004dcf720cSLi Jun if (!ci_otg_is_fsm_mode(ci)) { 7015f36e231SAlexander Shishkin ret = ci_role_start(ci, ci->role); 7025f36e231SAlexander Shishkin if (ret) { 7034dcf720cSLi Jun dev_err(dev, "can't start %s role\n", 7044dcf720cSLi Jun ci_role(ci)->name); 705cbec6bd5SPeter Chen goto stop; 7065f36e231SAlexander Shishkin } 7074dcf720cSLi Jun } 7085f36e231SAlexander Shishkin 7095f36e231SAlexander Shishkin platform_set_drvdata(pdev, ci); 71077c4400fSRichard Zhao ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, 7115f36e231SAlexander Shishkin ci); 7125f36e231SAlexander Shishkin if (ret) 7135f36e231SAlexander Shishkin goto stop; 7145f36e231SAlexander Shishkin 7154dcf720cSLi Jun if (ci_otg_is_fsm_mode(ci)) 7164dcf720cSLi Jun ci_hdrc_otg_fsm_start(ci); 7174dcf720cSLi Jun 718adf0f735SAlexander Shishkin ret = dbg_create_files(ci); 719adf0f735SAlexander Shishkin if (!ret) 720adf0f735SAlexander Shishkin return 0; 7215f36e231SAlexander Shishkin 722adf0f735SAlexander Shishkin free_irq(ci->irq, ci); 7235f36e231SAlexander Shishkin stop: 7243f124d23SPeter Chen ci_role_destroy(ci); 725c859aa65SPeter Chen deinit_phy: 726c859aa65SPeter Chen usb_phy_shutdown(ci->transceiver); 727e443b333SAlexander Shishkin 728e443b333SAlexander Shishkin return ret; 729e443b333SAlexander Shishkin } 730e443b333SAlexander Shishkin 731fb4e98abSBill Pemberton static int ci_hdrc_remove(struct platform_device *pdev) 732e443b333SAlexander Shishkin { 7338e22978cSAlexander Shishkin struct ci_hdrc *ci = platform_get_drvdata(pdev); 734e443b333SAlexander Shishkin 735adf0f735SAlexander Shishkin dbg_remove_files(ci); 7365f36e231SAlexander Shishkin free_irq(ci->irq, ci); 7373f124d23SPeter Chen ci_role_destroy(ci); 738864cf949SPeter Chen ci_hdrc_enter_lpm(ci, true); 739c859aa65SPeter Chen usb_phy_shutdown(ci->transceiver); 740c859aa65SPeter Chen kfree(ci->hw_bank.regmap); 741e443b333SAlexander Shishkin 742e443b333SAlexander Shishkin return 0; 743e443b333SAlexander Shishkin } 744e443b333SAlexander Shishkin 7455f36e231SAlexander Shishkin static struct platform_driver ci_hdrc_driver = { 7465f36e231SAlexander Shishkin .probe = ci_hdrc_probe, 7477690417dSBill Pemberton .remove = ci_hdrc_remove, 748e443b333SAlexander Shishkin .driver = { 7495f36e231SAlexander Shishkin .name = "ci_hdrc", 7507cf2f861SAlexander Shiyan .owner = THIS_MODULE, 751e443b333SAlexander Shishkin }, 752e443b333SAlexander Shishkin }; 753e443b333SAlexander Shishkin 7545f36e231SAlexander Shishkin module_platform_driver(ci_hdrc_driver); 755e443b333SAlexander Shishkin 7565f36e231SAlexander Shishkin MODULE_ALIAS("platform:ci_hdrc"); 757e443b333SAlexander Shishkin MODULE_LICENSE("GPL v2"); 758e443b333SAlexander Shishkin MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); 7595f36e231SAlexander Shishkin MODULE_DESCRIPTION("ChipIdea HDRC Driver"); 760