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 45e443b333SAlexander Shishkin * - OTG 46e4ce4ecdSMichael Grzeschik * - Interrupt Traffic 47e443b333SAlexander Shishkin * - GET_STATUS(device) - always reports 0 48e443b333SAlexander Shishkin * - Gadget API (majority of optional features) 49e443b333SAlexander Shishkin * - Suspend & Remote Wakeup 50e443b333SAlexander Shishkin */ 51e443b333SAlexander Shishkin #include <linux/delay.h> 52e443b333SAlexander Shishkin #include <linux/device.h> 53e443b333SAlexander Shishkin #include <linux/dma-mapping.h> 54e443b333SAlexander Shishkin #include <linux/platform_device.h> 55e443b333SAlexander Shishkin #include <linux/module.h> 56fe6e125eSRichard Zhao #include <linux/idr.h> 57e443b333SAlexander Shishkin #include <linux/interrupt.h> 58e443b333SAlexander Shishkin #include <linux/io.h> 59e443b333SAlexander Shishkin #include <linux/kernel.h> 60e443b333SAlexander Shishkin #include <linux/slab.h> 61e443b333SAlexander Shishkin #include <linux/pm_runtime.h> 62e443b333SAlexander Shishkin #include <linux/usb/ch9.h> 63e443b333SAlexander Shishkin #include <linux/usb/gadget.h> 64e443b333SAlexander Shishkin #include <linux/usb/otg.h> 65e443b333SAlexander Shishkin #include <linux/usb/chipidea.h> 6640dcd0e8SMichael Grzeschik #include <linux/usb/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" 76e443b333SAlexander Shishkin 775f36e231SAlexander Shishkin /* Controller register map */ 78987e7bc3SMarc Kleine-Budde static const u8 ci_regs_nolpm[] = { 79987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 80987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 81987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 82987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0x38U, 83987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 84987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 85987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 86987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 87987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 88987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 89987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 90987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0x64U, 91987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0x68U, 92987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0x6CU, 93987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0x70U, 94987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0x74U, 95987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0x78U, 96987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0x7CU, 97987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0x80U, 98e443b333SAlexander Shishkin }; 99e443b333SAlexander Shishkin 100987e7bc3SMarc Kleine-Budde static const u8 ci_regs_lpm[] = { 101987e7bc3SMarc Kleine-Budde [CAP_CAPLENGTH] = 0x00U, 102987e7bc3SMarc Kleine-Budde [CAP_HCCPARAMS] = 0x08U, 103987e7bc3SMarc Kleine-Budde [CAP_DCCPARAMS] = 0x24U, 104987e7bc3SMarc Kleine-Budde [CAP_TESTMODE] = 0xFCU, 105987e7bc3SMarc Kleine-Budde [OP_USBCMD] = 0x00U, 106987e7bc3SMarc Kleine-Budde [OP_USBSTS] = 0x04U, 107987e7bc3SMarc Kleine-Budde [OP_USBINTR] = 0x08U, 108987e7bc3SMarc Kleine-Budde [OP_DEVICEADDR] = 0x14U, 109987e7bc3SMarc Kleine-Budde [OP_ENDPTLISTADDR] = 0x18U, 110987e7bc3SMarc Kleine-Budde [OP_PORTSC] = 0x44U, 111987e7bc3SMarc Kleine-Budde [OP_DEVLC] = 0x84U, 112987e7bc3SMarc Kleine-Budde [OP_OTGSC] = 0xC4U, 113987e7bc3SMarc Kleine-Budde [OP_USBMODE] = 0xC8U, 114987e7bc3SMarc Kleine-Budde [OP_ENDPTSETUPSTAT] = 0xD8U, 115987e7bc3SMarc Kleine-Budde [OP_ENDPTPRIME] = 0xDCU, 116987e7bc3SMarc Kleine-Budde [OP_ENDPTFLUSH] = 0xE0U, 117987e7bc3SMarc Kleine-Budde [OP_ENDPTSTAT] = 0xE4U, 118987e7bc3SMarc Kleine-Budde [OP_ENDPTCOMPLETE] = 0xE8U, 119987e7bc3SMarc Kleine-Budde [OP_ENDPTCTRL] = 0xECU, 120e443b333SAlexander Shishkin }; 121e443b333SAlexander Shishkin 1228e22978cSAlexander Shishkin static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) 123e443b333SAlexander Shishkin { 124e443b333SAlexander Shishkin int i; 125e443b333SAlexander Shishkin 126e443b333SAlexander Shishkin for (i = 0; i < OP_ENDPTCTRL; i++) 1275f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = 1285f36e231SAlexander Shishkin (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + 129e443b333SAlexander Shishkin (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); 130e443b333SAlexander Shishkin 131e443b333SAlexander Shishkin for (; i <= OP_LAST; i++) 1325f36e231SAlexander Shishkin ci->hw_bank.regmap[i] = ci->hw_bank.op + 133e443b333SAlexander Shishkin 4 * (i - OP_ENDPTCTRL) + 134e443b333SAlexander Shishkin (is_lpm 135e443b333SAlexander Shishkin ? ci_regs_lpm[OP_ENDPTCTRL] 136e443b333SAlexander Shishkin : ci_regs_nolpm[OP_ENDPTCTRL]); 137e443b333SAlexander Shishkin 138e443b333SAlexander Shishkin return 0; 139e443b333SAlexander Shishkin } 140e443b333SAlexander Shishkin 141e443b333SAlexander Shishkin /** 142e443b333SAlexander Shishkin * hw_port_test_set: writes port test mode (execute without interruption) 143e443b333SAlexander Shishkin * @mode: new value 144e443b333SAlexander Shishkin * 145e443b333SAlexander Shishkin * This function returns an error code 146e443b333SAlexander Shishkin */ 1478e22978cSAlexander Shishkin int hw_port_test_set(struct ci_hdrc *ci, u8 mode) 148e443b333SAlexander Shishkin { 149e443b333SAlexander Shishkin const u8 TEST_MODE_MAX = 7; 150e443b333SAlexander Shishkin 151e443b333SAlexander Shishkin if (mode > TEST_MODE_MAX) 152e443b333SAlexander Shishkin return -EINVAL; 153e443b333SAlexander Shishkin 154727b4ddbSFelipe Balbi hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC)); 155e443b333SAlexander Shishkin return 0; 156e443b333SAlexander Shishkin } 157e443b333SAlexander Shishkin 158e443b333SAlexander Shishkin /** 159e443b333SAlexander Shishkin * hw_port_test_get: reads port test mode value 160e443b333SAlexander Shishkin * 161e443b333SAlexander Shishkin * This function returns port test mode value 162e443b333SAlexander Shishkin */ 1638e22978cSAlexander Shishkin u8 hw_port_test_get(struct ci_hdrc *ci) 164e443b333SAlexander Shishkin { 165727b4ddbSFelipe Balbi return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); 166e443b333SAlexander Shishkin } 167e443b333SAlexander Shishkin 168864cf949SPeter Chen /* The PHY enters/leaves low power mode */ 169864cf949SPeter Chen static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) 170864cf949SPeter Chen { 171864cf949SPeter Chen enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; 172864cf949SPeter Chen bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); 173864cf949SPeter Chen 174864cf949SPeter Chen if (enable && !lpm) { 175864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 176864cf949SPeter Chen PORTSC_PHCD(ci->hw_bank.lpm)); 177864cf949SPeter Chen } else if (!enable && lpm) { 178864cf949SPeter Chen hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), 179864cf949SPeter Chen 0); 180864cf949SPeter Chen /* 181864cf949SPeter Chen * The controller needs at least 1ms to reflect 182864cf949SPeter Chen * PHY's status, the PHY also needs some time (less 183864cf949SPeter Chen * than 1ms) to leave low power mode. 184864cf949SPeter Chen */ 185864cf949SPeter Chen usleep_range(1500, 2000); 186864cf949SPeter Chen } 187864cf949SPeter Chen } 188864cf949SPeter Chen 1898e22978cSAlexander Shishkin static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) 190e443b333SAlexander Shishkin { 191e443b333SAlexander Shishkin u32 reg; 192e443b333SAlexander Shishkin 193e443b333SAlexander Shishkin /* bank is a module variable */ 1945f36e231SAlexander Shishkin ci->hw_bank.abs = base; 195e443b333SAlexander Shishkin 1965f36e231SAlexander Shishkin ci->hw_bank.cap = ci->hw_bank.abs; 19777c4400fSRichard Zhao ci->hw_bank.cap += ci->platdata->capoffset; 198938d323fSSvetoslav Neykov ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); 199e443b333SAlexander Shishkin 2005f36e231SAlexander Shishkin hw_alloc_regmap(ci, false); 2015f36e231SAlexander Shishkin reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> 202727b4ddbSFelipe Balbi __ffs(HCCPARAMS_LEN); 2035f36e231SAlexander Shishkin ci->hw_bank.lpm = reg; 204aeb2c121SChris Ruehl if (reg) 2055f36e231SAlexander Shishkin hw_alloc_regmap(ci, !!reg); 2065f36e231SAlexander Shishkin ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; 2075f36e231SAlexander Shishkin ci->hw_bank.size += OP_LAST; 2085f36e231SAlexander Shishkin ci->hw_bank.size /= sizeof(u32); 209e443b333SAlexander Shishkin 2105f36e231SAlexander Shishkin reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> 211727b4ddbSFelipe Balbi __ffs(DCCPARAMS_DEN); 2125f36e231SAlexander Shishkin ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ 213e443b333SAlexander Shishkin 21409c94e62SRichard Zhao if (ci->hw_ep_max > ENDPT_MAX) 215e443b333SAlexander Shishkin return -ENODEV; 216e443b333SAlexander Shishkin 217864cf949SPeter Chen ci_hdrc_enter_lpm(ci, false); 218864cf949SPeter Chen 219c344b518SPeter Chen /* Disable all interrupts bits */ 220c344b518SPeter Chen hw_write(ci, OP_USBINTR, 0xffffffff, 0); 221c344b518SPeter Chen 222c344b518SPeter Chen /* Clear all interrupts status bits*/ 223c344b518SPeter Chen hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff); 224c344b518SPeter Chen 2255f36e231SAlexander Shishkin dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n", 2265f36e231SAlexander Shishkin ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); 227e443b333SAlexander Shishkin 228e443b333SAlexander Shishkin /* setup lock mode ? */ 229e443b333SAlexander Shishkin 230e443b333SAlexander Shishkin /* ENDPTSETUPSTAT is '0' by default */ 231e443b333SAlexander Shishkin 232e443b333SAlexander Shishkin /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ 233e443b333SAlexander Shishkin 234e443b333SAlexander Shishkin return 0; 235e443b333SAlexander Shishkin } 236e443b333SAlexander Shishkin 2378e22978cSAlexander Shishkin static void hw_phymode_configure(struct ci_hdrc *ci) 23840dcd0e8SMichael Grzeschik { 2393b5d3e68SChris Ruehl u32 portsc, lpm, sts = 0; 24040dcd0e8SMichael Grzeschik 24140dcd0e8SMichael Grzeschik switch (ci->platdata->phy_mode) { 24240dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMI: 24340dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI); 24440dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI); 24540dcd0e8SMichael Grzeschik break; 24640dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_UTMIW: 24740dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW; 24840dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW; 24940dcd0e8SMichael Grzeschik break; 25040dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_ULPI: 25140dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_ULPI); 25240dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_ULPI); 25340dcd0e8SMichael Grzeschik break; 25440dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_SERIAL: 25540dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_SERIAL); 25640dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_SERIAL); 25740dcd0e8SMichael Grzeschik sts = 1; 25840dcd0e8SMichael Grzeschik break; 25940dcd0e8SMichael Grzeschik case USBPHY_INTERFACE_MODE_HSIC: 26040dcd0e8SMichael Grzeschik portsc = PORTSC_PTS(PTS_HSIC); 26140dcd0e8SMichael Grzeschik lpm = DEVLC_PTS(PTS_HSIC); 26240dcd0e8SMichael Grzeschik break; 26340dcd0e8SMichael Grzeschik default: 26440dcd0e8SMichael Grzeschik return; 26540dcd0e8SMichael Grzeschik } 26640dcd0e8SMichael Grzeschik 26740dcd0e8SMichael Grzeschik if (ci->hw_bank.lpm) { 26840dcd0e8SMichael Grzeschik hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm); 2693b5d3e68SChris Ruehl if (sts) 2703b5d3e68SChris Ruehl hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS); 27140dcd0e8SMichael Grzeschik } else { 27240dcd0e8SMichael Grzeschik hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); 2733b5d3e68SChris Ruehl if (sts) 2743b5d3e68SChris Ruehl hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); 27540dcd0e8SMichael Grzeschik } 27640dcd0e8SMichael Grzeschik } 27740dcd0e8SMichael Grzeschik 278e443b333SAlexander Shishkin /** 279e443b333SAlexander Shishkin * hw_device_reset: resets chip (execute without interruption) 280e443b333SAlexander Shishkin * @ci: the controller 281e443b333SAlexander Shishkin * 282e443b333SAlexander Shishkin * This function returns an error code 283e443b333SAlexander Shishkin */ 2848e22978cSAlexander Shishkin int hw_device_reset(struct ci_hdrc *ci, u32 mode) 285e443b333SAlexander Shishkin { 286e443b333SAlexander Shishkin /* should flush & stop before reset */ 287e443b333SAlexander Shishkin hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); 288e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RS, 0); 289e443b333SAlexander Shishkin 290e443b333SAlexander Shishkin hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); 291e443b333SAlexander Shishkin while (hw_read(ci, OP_USBCMD, USBCMD_RST)) 292e443b333SAlexander Shishkin udelay(10); /* not RTOS friendly */ 293e443b333SAlexander Shishkin 29477c4400fSRichard Zhao if (ci->platdata->notify_event) 29577c4400fSRichard Zhao ci->platdata->notify_event(ci, 2968e22978cSAlexander Shishkin CI_HDRC_CONTROLLER_RESET_EVENT); 297e443b333SAlexander Shishkin 2988e22978cSAlexander Shishkin if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) 299758fc986SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); 300e443b333SAlexander Shishkin 301e443b333SAlexander Shishkin /* USBMODE should be configured step by step */ 302e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 303eb70e5abSAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_CM, mode); 304e443b333SAlexander Shishkin /* HW >= 2.3 */ 305e443b333SAlexander Shishkin hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); 306e443b333SAlexander Shishkin 307eb70e5abSAlexander Shishkin if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) { 308eb70e5abSAlexander Shishkin pr_err("cannot enter in %s mode", ci_role(ci)->name); 309e443b333SAlexander Shishkin pr_err("lpm = %i", ci->hw_bank.lpm); 310e443b333SAlexander Shishkin return -ENODEV; 311e443b333SAlexander Shishkin } 312e443b333SAlexander Shishkin 313e443b333SAlexander Shishkin return 0; 314e443b333SAlexander Shishkin } 315e443b333SAlexander Shishkin 31622fa8445SPeter Chen /** 31722fa8445SPeter Chen * hw_wait_reg: wait the register value 31822fa8445SPeter Chen * 31922fa8445SPeter Chen * Sometimes, it needs to wait register value before going on. 32022fa8445SPeter Chen * Eg, when switch to device mode, the vbus value should be lower 32122fa8445SPeter Chen * than OTGSC_BSV before connects to host. 32222fa8445SPeter Chen * 32322fa8445SPeter Chen * @ci: the controller 32422fa8445SPeter Chen * @reg: register index 32522fa8445SPeter Chen * @mask: mast bit 32622fa8445SPeter Chen * @value: the bit value to wait 32722fa8445SPeter Chen * @timeout_ms: timeout in millisecond 32822fa8445SPeter Chen * 32922fa8445SPeter Chen * This function returns an error code if timeout 33022fa8445SPeter Chen */ 33122fa8445SPeter Chen int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, 33222fa8445SPeter Chen u32 value, unsigned int timeout_ms) 33322fa8445SPeter Chen { 33422fa8445SPeter Chen unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); 33522fa8445SPeter Chen 33622fa8445SPeter Chen while (hw_read(ci, reg, mask) != value) { 33722fa8445SPeter Chen if (time_after(jiffies, elapse)) { 33822fa8445SPeter Chen dev_err(ci->dev, "timeout waiting for %08x in %d\n", 33922fa8445SPeter Chen mask, reg); 34022fa8445SPeter Chen return -ETIMEDOUT; 34122fa8445SPeter Chen } 34222fa8445SPeter Chen msleep(20); 34322fa8445SPeter Chen } 34422fa8445SPeter Chen 34522fa8445SPeter Chen return 0; 34622fa8445SPeter Chen } 34722fa8445SPeter Chen 3485f36e231SAlexander Shishkin static irqreturn_t ci_irq(int irq, void *data) 3495f36e231SAlexander Shishkin { 3508e22978cSAlexander Shishkin struct ci_hdrc *ci = data; 3515f36e231SAlexander Shishkin irqreturn_t ret = IRQ_NONE; 352b183c19fSRichard Zhao u32 otgsc = 0; 3535f36e231SAlexander Shishkin 354b183c19fSRichard Zhao if (ci->is_otg) 355b183c19fSRichard Zhao otgsc = hw_read(ci, OP_OTGSC, ~0); 3565f36e231SAlexander Shishkin 357a107f8c5SPeter Chen /* 358a107f8c5SPeter Chen * Handle id change interrupt, it indicates device/host function 359a107f8c5SPeter Chen * switch. 360a107f8c5SPeter Chen */ 361a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { 362a107f8c5SPeter Chen ci->id_event = true; 363a107f8c5SPeter Chen ci_clear_otg_interrupt(ci, OTGSC_IDIS); 364b183c19fSRichard Zhao disable_irq_nosync(ci->irq); 3655f36e231SAlexander Shishkin queue_work(ci->wq, &ci->work); 366a107f8c5SPeter Chen return IRQ_HANDLED; 3675f36e231SAlexander Shishkin } 3685f36e231SAlexander Shishkin 369a107f8c5SPeter Chen /* 370a107f8c5SPeter Chen * Handle vbus change interrupt, it indicates device connection 371a107f8c5SPeter Chen * and disconnection events. 372a107f8c5SPeter Chen */ 373a107f8c5SPeter Chen if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) { 374a107f8c5SPeter Chen ci->b_sess_valid_event = true; 375a107f8c5SPeter Chen ci_clear_otg_interrupt(ci, OTGSC_BSVIS); 376a107f8c5SPeter Chen disable_irq_nosync(ci->irq); 377a107f8c5SPeter Chen queue_work(ci->wq, &ci->work); 378a107f8c5SPeter Chen return IRQ_HANDLED; 379a107f8c5SPeter Chen } 380a107f8c5SPeter Chen 381a107f8c5SPeter Chen /* Handle device/host interrupt */ 382a107f8c5SPeter Chen if (ci->role != CI_ROLE_END) 383a107f8c5SPeter Chen ret = ci_role(ci)->irq(ci); 384a107f8c5SPeter Chen 385b183c19fSRichard Zhao return ret; 3865f36e231SAlexander Shishkin } 3875f36e231SAlexander Shishkin 3881542d9c3SPeter Chen static int ci_get_platdata(struct device *dev, 3891542d9c3SPeter Chen struct ci_hdrc_platform_data *platdata) 3901542d9c3SPeter Chen { 391c22600c3SPeter Chen if (!platdata->phy_mode) 392c22600c3SPeter Chen platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); 393c22600c3SPeter Chen 394c22600c3SPeter Chen if (!platdata->dr_mode) 395c22600c3SPeter Chen platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); 396c22600c3SPeter Chen 397c22600c3SPeter Chen if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) 398c22600c3SPeter Chen platdata->dr_mode = USB_DR_MODE_OTG; 399c22600c3SPeter Chen 400c2ec3a73SPeter Chen if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { 401c2ec3a73SPeter Chen /* Get the vbus regulator */ 402c2ec3a73SPeter Chen platdata->reg_vbus = devm_regulator_get(dev, "vbus"); 403c2ec3a73SPeter Chen if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { 404c2ec3a73SPeter Chen return -EPROBE_DEFER; 405c2ec3a73SPeter Chen } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { 406c2ec3a73SPeter Chen /* no vbus regualator is needed */ 407c2ec3a73SPeter Chen platdata->reg_vbus = NULL; 408c2ec3a73SPeter Chen } else if (IS_ERR(platdata->reg_vbus)) { 409c2ec3a73SPeter Chen dev_err(dev, "Getting regulator error: %ld\n", 410c2ec3a73SPeter Chen PTR_ERR(platdata->reg_vbus)); 411c2ec3a73SPeter Chen return PTR_ERR(platdata->reg_vbus); 412c2ec3a73SPeter Chen } 413c2ec3a73SPeter Chen } 414c2ec3a73SPeter Chen 4151542d9c3SPeter Chen return 0; 4161542d9c3SPeter Chen } 4171542d9c3SPeter Chen 418fe6e125eSRichard Zhao static DEFINE_IDA(ci_ida); 419fe6e125eSRichard Zhao 4208e22978cSAlexander Shishkin struct platform_device *ci_hdrc_add_device(struct device *dev, 421cbc6dc2aSRichard Zhao struct resource *res, int nres, 4228e22978cSAlexander Shishkin struct ci_hdrc_platform_data *platdata) 423cbc6dc2aSRichard Zhao { 424cbc6dc2aSRichard Zhao struct platform_device *pdev; 425fe6e125eSRichard Zhao int id, ret; 426cbc6dc2aSRichard Zhao 4271542d9c3SPeter Chen ret = ci_get_platdata(dev, platdata); 4281542d9c3SPeter Chen if (ret) 4291542d9c3SPeter Chen return ERR_PTR(ret); 4301542d9c3SPeter Chen 431fe6e125eSRichard Zhao id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); 432fe6e125eSRichard Zhao if (id < 0) 433fe6e125eSRichard Zhao return ERR_PTR(id); 434fe6e125eSRichard Zhao 435fe6e125eSRichard Zhao pdev = platform_device_alloc("ci_hdrc", id); 436fe6e125eSRichard Zhao if (!pdev) { 437fe6e125eSRichard Zhao ret = -ENOMEM; 438fe6e125eSRichard Zhao goto put_id; 439fe6e125eSRichard Zhao } 440cbc6dc2aSRichard Zhao 441cbc6dc2aSRichard Zhao pdev->dev.parent = dev; 442cbc6dc2aSRichard Zhao pdev->dev.dma_mask = dev->dma_mask; 443cbc6dc2aSRichard Zhao pdev->dev.dma_parms = dev->dma_parms; 444cbc6dc2aSRichard Zhao dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask); 445cbc6dc2aSRichard Zhao 446cbc6dc2aSRichard Zhao ret = platform_device_add_resources(pdev, res, nres); 447cbc6dc2aSRichard Zhao if (ret) 448cbc6dc2aSRichard Zhao goto err; 449cbc6dc2aSRichard Zhao 450cbc6dc2aSRichard Zhao ret = platform_device_add_data(pdev, platdata, sizeof(*platdata)); 451cbc6dc2aSRichard Zhao if (ret) 452cbc6dc2aSRichard Zhao goto err; 453cbc6dc2aSRichard Zhao 454cbc6dc2aSRichard Zhao ret = platform_device_add(pdev); 455cbc6dc2aSRichard Zhao if (ret) 456cbc6dc2aSRichard Zhao goto err; 457cbc6dc2aSRichard Zhao 458cbc6dc2aSRichard Zhao return pdev; 459cbc6dc2aSRichard Zhao 460cbc6dc2aSRichard Zhao err: 461cbc6dc2aSRichard Zhao platform_device_put(pdev); 462fe6e125eSRichard Zhao put_id: 463fe6e125eSRichard Zhao ida_simple_remove(&ci_ida, id); 464cbc6dc2aSRichard Zhao return ERR_PTR(ret); 465cbc6dc2aSRichard Zhao } 4668e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_add_device); 467cbc6dc2aSRichard Zhao 4688e22978cSAlexander Shishkin void ci_hdrc_remove_device(struct platform_device *pdev) 469cbc6dc2aSRichard Zhao { 47098c35534SLothar Waßmann int id = pdev->id; 471cbc6dc2aSRichard Zhao platform_device_unregister(pdev); 47298c35534SLothar Waßmann ida_simple_remove(&ci_ida, id); 473cbc6dc2aSRichard Zhao } 4748e22978cSAlexander Shishkin EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); 475cbc6dc2aSRichard Zhao 4763f124d23SPeter Chen static inline void ci_role_destroy(struct ci_hdrc *ci) 4773f124d23SPeter Chen { 4783f124d23SPeter Chen ci_hdrc_gadget_destroy(ci); 4793f124d23SPeter Chen ci_hdrc_host_destroy(ci); 480cbec6bd5SPeter Chen if (ci->is_otg) 481cbec6bd5SPeter Chen ci_hdrc_otg_destroy(ci); 4823f124d23SPeter Chen } 4833f124d23SPeter Chen 484577b232fSPeter Chen static void ci_get_otg_capable(struct ci_hdrc *ci) 485577b232fSPeter Chen { 486577b232fSPeter Chen if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) 487577b232fSPeter Chen ci->is_otg = false; 488577b232fSPeter Chen else 489577b232fSPeter Chen ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, 490577b232fSPeter Chen DCCPARAMS_DC | DCCPARAMS_HC) 491577b232fSPeter Chen == (DCCPARAMS_DC | DCCPARAMS_HC)); 492c344b518SPeter Chen if (ci->is_otg) { 493577b232fSPeter Chen dev_dbg(ci->dev, "It is OTG capable controller\n"); 494c344b518SPeter Chen ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); 495c344b518SPeter Chen ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); 496c344b518SPeter Chen } 497577b232fSPeter Chen } 498577b232fSPeter Chen 49941ac7b3aSBill Pemberton static int ci_hdrc_probe(struct platform_device *pdev) 500e443b333SAlexander Shishkin { 501e443b333SAlexander Shishkin struct device *dev = &pdev->dev; 5028e22978cSAlexander Shishkin struct ci_hdrc *ci; 503e443b333SAlexander Shishkin struct resource *res; 504e443b333SAlexander Shishkin void __iomem *base; 505e443b333SAlexander Shishkin int ret; 506691962d1SSascha Hauer enum usb_dr_mode dr_mode; 507e443b333SAlexander Shishkin 508fad56745SJingoo Han if (!dev_get_platdata(dev)) { 509e443b333SAlexander Shishkin dev_err(dev, "platform data missing\n"); 510e443b333SAlexander Shishkin return -ENODEV; 511e443b333SAlexander Shishkin } 512e443b333SAlexander Shishkin 513e443b333SAlexander Shishkin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 51419290816SFelipe Balbi base = devm_ioremap_resource(dev, res); 51519290816SFelipe Balbi if (IS_ERR(base)) 51619290816SFelipe Balbi return PTR_ERR(base); 517e443b333SAlexander Shishkin 5185f36e231SAlexander Shishkin ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); 5195f36e231SAlexander Shishkin if (!ci) { 5205f36e231SAlexander Shishkin dev_err(dev, "can't allocate device\n"); 5215f36e231SAlexander Shishkin return -ENOMEM; 5225f36e231SAlexander Shishkin } 523e443b333SAlexander Shishkin 5245f36e231SAlexander Shishkin ci->dev = dev; 525fad56745SJingoo Han ci->platdata = dev_get_platdata(dev); 526ed8f8318SPeter Chen ci->imx28_write_fix = !!(ci->platdata->flags & 527ed8f8318SPeter Chen CI_HDRC_IMX28_WRITE_FIX); 5285f36e231SAlexander Shishkin 5295f36e231SAlexander Shishkin ret = hw_device_init(ci, base); 5305f36e231SAlexander Shishkin if (ret < 0) { 5315f36e231SAlexander Shishkin dev_err(dev, "can't initialize hardware\n"); 5325f36e231SAlexander Shishkin return -ENODEV; 5335f36e231SAlexander Shishkin } 5345f36e231SAlexander Shishkin 535cd0b42c2SChris Ruehl hw_phymode_configure(ci); 536cd0b42c2SChris Ruehl 537c859aa65SPeter Chen if (ci->platdata->phy) 538c859aa65SPeter Chen ci->transceiver = ci->platdata->phy; 539c859aa65SPeter Chen else 540c859aa65SPeter Chen ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 541c859aa65SPeter Chen 542c859aa65SPeter Chen if (IS_ERR(ci->transceiver)) { 543c859aa65SPeter Chen ret = PTR_ERR(ci->transceiver); 544c859aa65SPeter Chen /* 545c859aa65SPeter Chen * if -ENXIO is returned, it means PHY layer wasn't 546c859aa65SPeter Chen * enabled, so it makes no sense to return -EPROBE_DEFER 547c859aa65SPeter Chen * in that case, since no PHY driver will ever probe. 548c859aa65SPeter Chen */ 549c859aa65SPeter Chen if (ret == -ENXIO) 550c859aa65SPeter Chen return ret; 551c859aa65SPeter Chen 552c859aa65SPeter Chen dev_err(dev, "no usb2 phy configured\n"); 553c859aa65SPeter Chen return -EPROBE_DEFER; 554c859aa65SPeter Chen } 555c859aa65SPeter Chen 556c859aa65SPeter Chen ret = usb_phy_init(ci->transceiver); 55774475edeSPeter Chen if (ret) { 55874475edeSPeter Chen dev_err(dev, "unable to init phy: %d\n", ret); 55974475edeSPeter Chen return ret; 56074475edeSPeter Chen } 56174475edeSPeter Chen 562eb70e5abSAlexander Shishkin ci->hw_bank.phys = res->start; 563eb70e5abSAlexander Shishkin 5645f36e231SAlexander Shishkin ci->irq = platform_get_irq(pdev, 0); 5655f36e231SAlexander Shishkin if (ci->irq < 0) { 566e443b333SAlexander Shishkin dev_err(dev, "missing IRQ\n"); 56774475edeSPeter Chen ret = -ENODEV; 568c859aa65SPeter Chen goto deinit_phy; 569e443b333SAlexander Shishkin } 570e443b333SAlexander Shishkin 571577b232fSPeter Chen ci_get_otg_capable(ci); 572577b232fSPeter Chen 573691962d1SSascha Hauer dr_mode = ci->platdata->dr_mode; 5745f36e231SAlexander Shishkin /* initialize role(s) before the interrupt is requested */ 575691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 576eb70e5abSAlexander Shishkin ret = ci_hdrc_host_init(ci); 577eb70e5abSAlexander Shishkin if (ret) 578eb70e5abSAlexander Shishkin dev_info(dev, "doesn't support host\n"); 579691962d1SSascha Hauer } 580eb70e5abSAlexander Shishkin 581691962d1SSascha Hauer if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 5825f36e231SAlexander Shishkin ret = ci_hdrc_gadget_init(ci); 583e443b333SAlexander Shishkin if (ret) 5845f36e231SAlexander Shishkin dev_info(dev, "doesn't support gadget\n"); 585691962d1SSascha Hauer } 5865f36e231SAlexander Shishkin 5875f36e231SAlexander Shishkin if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { 5885f36e231SAlexander Shishkin dev_err(dev, "no supported roles\n"); 58974475edeSPeter Chen ret = -ENODEV; 590c859aa65SPeter Chen goto deinit_phy; 591cbec6bd5SPeter Chen } 592cbec6bd5SPeter Chen 593cbec6bd5SPeter Chen if (ci->is_otg) { 594cbec6bd5SPeter Chen ret = ci_hdrc_otg_init(ci); 595cbec6bd5SPeter Chen if (ret) { 596cbec6bd5SPeter Chen dev_err(dev, "init otg fails, ret = %d\n", ret); 597cbec6bd5SPeter Chen goto stop; 598cbec6bd5SPeter Chen } 5995f36e231SAlexander Shishkin } 6005f36e231SAlexander Shishkin 6015f36e231SAlexander Shishkin if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { 602577b232fSPeter Chen if (ci->is_otg) { 603577b232fSPeter Chen /* 604577b232fSPeter Chen * ID pin needs 1ms debouce time, 605577b232fSPeter Chen * we delay 2ms for safe. 606577b232fSPeter Chen */ 60786ad01a9SRichard Zhao mdelay(2); 6085f36e231SAlexander Shishkin ci->role = ci_otg_role(ci); 609cbec6bd5SPeter Chen ci_enable_otg_interrupt(ci, OTGSC_IDIE); 610577b232fSPeter Chen } else { 611577b232fSPeter Chen /* 612577b232fSPeter Chen * If the controller is not OTG capable, but support 613577b232fSPeter Chen * role switch, the defalt role is gadget, and the 614577b232fSPeter Chen * user can switch it through debugfs. 615577b232fSPeter Chen */ 616577b232fSPeter Chen ci->role = CI_ROLE_GADGET; 617577b232fSPeter Chen } 6185f36e231SAlexander Shishkin } else { 6195f36e231SAlexander Shishkin ci->role = ci->roles[CI_ROLE_HOST] 6205f36e231SAlexander Shishkin ? CI_ROLE_HOST 6215f36e231SAlexander Shishkin : CI_ROLE_GADGET; 6225f36e231SAlexander Shishkin } 6235f36e231SAlexander Shishkin 6245a1e1456SPeter Chen /* only update vbus status for peripheral */ 6255a1e1456SPeter Chen if (ci->role == CI_ROLE_GADGET) 6265a1e1456SPeter Chen ci_handle_vbus_change(ci); 6275a1e1456SPeter Chen 6285f36e231SAlexander Shishkin ret = ci_role_start(ci, ci->role); 6295f36e231SAlexander Shishkin if (ret) { 6305f36e231SAlexander Shishkin dev_err(dev, "can't start %s role\n", ci_role(ci)->name); 631cbec6bd5SPeter Chen goto stop; 6325f36e231SAlexander Shishkin } 6335f36e231SAlexander Shishkin 6345f36e231SAlexander Shishkin platform_set_drvdata(pdev, ci); 63577c4400fSRichard Zhao ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, 6365f36e231SAlexander Shishkin ci); 6375f36e231SAlexander Shishkin if (ret) 6385f36e231SAlexander Shishkin goto stop; 6395f36e231SAlexander Shishkin 640adf0f735SAlexander Shishkin ret = dbg_create_files(ci); 641adf0f735SAlexander Shishkin if (!ret) 642adf0f735SAlexander Shishkin return 0; 6435f36e231SAlexander Shishkin 644adf0f735SAlexander Shishkin free_irq(ci->irq, ci); 6455f36e231SAlexander Shishkin stop: 6463f124d23SPeter Chen ci_role_destroy(ci); 647c859aa65SPeter Chen deinit_phy: 648c859aa65SPeter Chen usb_phy_shutdown(ci->transceiver); 649e443b333SAlexander Shishkin 650e443b333SAlexander Shishkin return ret; 651e443b333SAlexander Shishkin } 652e443b333SAlexander Shishkin 653fb4e98abSBill Pemberton static int ci_hdrc_remove(struct platform_device *pdev) 654e443b333SAlexander Shishkin { 6558e22978cSAlexander Shishkin struct ci_hdrc *ci = platform_get_drvdata(pdev); 656e443b333SAlexander Shishkin 657adf0f735SAlexander Shishkin dbg_remove_files(ci); 6585f36e231SAlexander Shishkin free_irq(ci->irq, ci); 6593f124d23SPeter Chen ci_role_destroy(ci); 660864cf949SPeter Chen ci_hdrc_enter_lpm(ci, true); 661c859aa65SPeter Chen usb_phy_shutdown(ci->transceiver); 662c859aa65SPeter Chen kfree(ci->hw_bank.regmap); 663e443b333SAlexander Shishkin 664e443b333SAlexander Shishkin return 0; 665e443b333SAlexander Shishkin } 666e443b333SAlexander Shishkin 6675f36e231SAlexander Shishkin static struct platform_driver ci_hdrc_driver = { 6685f36e231SAlexander Shishkin .probe = ci_hdrc_probe, 6697690417dSBill Pemberton .remove = ci_hdrc_remove, 670e443b333SAlexander Shishkin .driver = { 6715f36e231SAlexander Shishkin .name = "ci_hdrc", 672e443b333SAlexander Shishkin }, 673e443b333SAlexander Shishkin }; 674e443b333SAlexander Shishkin 6755f36e231SAlexander Shishkin module_platform_driver(ci_hdrc_driver); 676e443b333SAlexander Shishkin 6775f36e231SAlexander Shishkin MODULE_ALIAS("platform:ci_hdrc"); 678e443b333SAlexander Shishkin MODULE_LICENSE("GPL v2"); 679e443b333SAlexander Shishkin MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); 6805f36e231SAlexander Shishkin MODULE_DESCRIPTION("ChipIdea HDRC Driver"); 681