| /* ========================================================================== |
| * |
| * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, |
| * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless |
| * otherwise expressly agreed to in writing between Synopsys and you. |
| * |
| * The Software IS NOT an item of Licensed Software or Licensed Product under |
| * any End User Software License Agreement or Agreement for Licensed Product |
| * with Synopsys or any supplement thereto. You are permitted to use and |
| * redistribute this Software in source and binary forms, with or without |
| * modification, provided that redistributions of source code must retain this |
| * notice. You may not view, use, disclose, copy or distribute this file or |
| * any information contained herein except pursuant to this license grant from |
| * Synopsys. If you do not agree with this notice, including the disclaimer |
| * below, then you are not authorized to use the Software. |
| * |
| * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * ========================================================================== */ |
| |
| |
| /** @file |
| * The dwc_otg_driver module provides the initialization and cleanup entry |
| * points for the DWC_otg driver. This module will be dynamically installed |
| * after Linux is booted using the insmod command. When the module is |
| * installed, the dwc_otg_driver_init function is called. When the module is |
| * removed (using rmmod), the dwc_otg_driver_cleanup function is called. |
| * |
| * This module also defines a data structure for the dwc_otg_driver, which is |
| * used in conjunction with the standard device structure. These |
| * structures allow the OTG driver to comply with the standard Linux driver |
| * model in which devices and drivers are registered with a bus driver. This |
| * has the benefit that Linux can expose attributes of the driver and device |
| * in its special sysfs file system. Users can then read or write files in |
| * this file system to perform diagnostics on the driver components or the |
| * device. |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/moduleparam.h> |
| #include <linux/init.h> |
| #include <linux/device.h> |
| #include <linux/errno.h> |
| #include <linux/types.h> |
| #include <linux/stat.h> /* permission constants */ |
| #include <linux/platform_device.h> |
| #include <linux/irq.h> |
| #include <linux/io.h> |
| #include <linux/usb/dwc_otg_platform.h> |
| |
| #include "dwc_otg_attr.h" |
| #include "dwc_otg_driver.h" |
| #include "dwc_otg_core_if.h" |
| #include "dwc_otg_cil.h" |
| #include "dwc_otg_pcd.h" |
| #include "dwc_otg_hcd.h" |
| #include "dwc_otg_regs.h" |
| |
| #define DWC_DRIVER_VERSION "2.90a 23-APR-2009 with Bug Fixes from IMG" |
| #define DWC_DRIVER_DESC "HS OTG USB Controller driver" |
| static const char dwc_driver_name[] = "dwc_otg"; |
| |
| /*-------------------------------------------------------------------------*/ |
| /* Encapsulate the module parameter settings */ |
| static struct dwc_otg_core_params dwc_otg_module_params = { |
| .opt = -1, |
| .otg_cap = -1, |
| |
| #if defined(CONFIG_USB_DWC_OTG_BUFFER_DMA) |
| .dma_enable = 1, |
| .dma_desc_enable = 0, |
| #elif defined(CONFIG_USB_DWC_OTG_DESC_DMA) |
| .dma_enable = 1, |
| .dma_desc_enable = 1, |
| #else |
| .dma_enable = 0, |
| .dma_desc_enable = 0, |
| #endif |
| .dma_burst_size = -1, |
| #if defined(CONFIG_USB_DWC_OTG_SPEED_HIGH) |
| .speed = 0, |
| #elif defined(CONFIG_USB_DWC_OTG_SPEED_FULL) |
| .speed = 1, |
| #else |
| .speed = -1, |
| #endif |
| .host_support_fs_ls_low_power = -1, |
| .host_ls_low_power_phy_clk = -1, |
| .enable_dynamic_fifo = -1, |
| .data_fifo_size = -1, |
| .dev_rx_fifo_size = -1, |
| .dev_nperio_tx_fifo_size = -1, |
| .dev_perio_tx_fifo_size = { /* dev_perio_tx_fifo_size_1 */ |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1 |
| }, /* 15 */ |
| .host_rx_fifo_size = -1, |
| .host_nperio_tx_fifo_size = -1, |
| .host_perio_tx_fifo_size = -1, |
| .max_transfer_size = -1, |
| .max_packet_count = -1, |
| #ifdef DWC_SLAVE /*bug prevents slave mode working with >6 channels */ |
| .host_channels = 6, |
| #else |
| .host_channels = -1, |
| #endif |
| .dev_endpoints = -1, |
| .phy_type = -1, |
| .phy_utmi_width = -1, |
| .phy_ulpi_ddr = -1, |
| .phy_ulpi_ext_vbus = -1, |
| .i2c_enable = -1, |
| .ulpi_fs_ls = -1, |
| .ts_dline = -1, |
| .en_multiple_tx_fifo = -1, |
| .dev_tx_fifo_size = { /* dev_tx_fifo_size */ |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 |
| }, /* 15 */ |
| .thr_ctl = -1, |
| .tx_thr_length = -1, |
| .rx_thr_length = -1, |
| .pti_enable = -1, |
| .mpi_enable = -1, |
| .lpm_enable = -1, |
| .ic_usb_cap = -1, |
| .ahb_thr_ratio = -1, |
| }; |
| |
| |
| /** |
| * This function shows the Driver Version. |
| */ |
| static ssize_t version_show(struct device_driver *dev, char *buf) |
| { |
| return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n", |
| DWC_DRIVER_VERSION); |
| } |
| static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); |
| |
| /** |
| * Global Debug Level Mask. |
| */ |
| u32 g_dbg_lvl; /* = DBG_ANY; */ |
| |
| /** |
| * This function shows the driver Debug Level. |
| */ |
| static ssize_t dbg_level_show(struct device_driver *drv, char *buf) |
| { |
| return sprintf(buf, "0x%0x\n", g_dbg_lvl); |
| } |
| |
| |
| /** |
| * This function stores the driver Debug Level. |
| */ |
| static ssize_t dbg_level_store(struct device_driver *drv, const char *buf, |
| size_t _count) |
| { |
| g_dbg_lvl = simple_strtoul(buf, NULL, 16); |
| return _count; |
| } |
| static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show, |
| dbg_level_store); |
| |
| /** |
| * This function is called during module intialization to verify that |
| * the module parameters are in a valid state. |
| */ |
| static int check_parameters(struct dwc_otg_core_if *core_if) |
| { |
| int i; |
| int retval = 0; |
| |
| /* Checks if the parameter is outside of its valid range of values */ |
| #define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \ |
| ((dwc_otg_module_params._param_ < (_low_)) || \ |
| (dwc_otg_module_params._param_ > (_high_))) |
| /* If the parameter has been set by the user, check that the parameter value is |
| * within the value range of values. If not, report a module error. */ |
| #define DWC_OTG_PARAM_ERR(_param_, _low_, _high_, _string_) \ |
| do { \ |
| if (dwc_otg_module_params._param_ != -1) { \ |
| if (DWC_OTG_PARAM_TEST(_param_, (_low_), (_high_))) { \ |
| DWC_ERROR("`%d' invalid for parameter `%s'\n", \ |
| dwc_otg_module_params._param_, _string_); \ |
| dwc_otg_module_params._param_ = \ |
| dwc_param_##_param_##_default; \ |
| retval++; \ |
| } \ |
| } \ |
| } while (0) |
| |
| DWC_OTG_PARAM_ERR(opt, 0, 1, "opt"); |
| DWC_OTG_PARAM_ERR(otg_cap, 0, 2, "otg_cap"); |
| DWC_OTG_PARAM_ERR(dma_enable, 0, 1, "dma_enable"); |
| DWC_OTG_PARAM_ERR(speed, 0, 1, "speed"); |
| DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power, 0, 1, |
| "host_support_fs_ls_low_power"); |
| DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk, 0, 1, |
| "host_ls_low_power_phy_clk"); |
| DWC_OTG_PARAM_ERR(enable_dynamic_fifo, 0, 1, "enable_dynamic_fifo"); |
| DWC_OTG_PARAM_ERR(data_fifo_size, 32, 32768, "data_fifo_size"); |
| DWC_OTG_PARAM_ERR(dev_rx_fifo_size, 16, 32768, "dev_rx_fifo_size"); |
| DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size, 16, 32768, |
| "dev_nperio_tx_fifo_size"); |
| DWC_OTG_PARAM_ERR(host_rx_fifo_size, 16, 32768, "host_rx_fifo_size"); |
| DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size, 16, 32768, |
| "host_nperio_tx_fifo_size"); |
| DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size, 16, 32768, |
| "host_perio_tx_fifo_size"); |
| DWC_OTG_PARAM_ERR(max_transfer_size, 2047, 524288, |
| "max_transfer_size"); |
| DWC_OTG_PARAM_ERR(max_packet_count, 15, 511, "max_packet_count"); |
| DWC_OTG_PARAM_ERR(host_channels, 1, 16, "host_channels"); |
| DWC_OTG_PARAM_ERR(dev_endpoints, 1, 15, "dev_endpoints"); |
| DWC_OTG_PARAM_ERR(phy_type, 0, 2, "phy_type"); |
| DWC_OTG_PARAM_ERR(phy_ulpi_ddr, 0, 1, "phy_ulpi_ddr"); |
| DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus, 0, 1, "phy_ulpi_ext_vbus"); |
| DWC_OTG_PARAM_ERR(i2c_enable, 0, 1, "i2c_enable"); |
| DWC_OTG_PARAM_ERR(ulpi_fs_ls, 0, 1, "ulpi_fs_ls"); |
| DWC_OTG_PARAM_ERR(ts_dline, 0, 1, "ts_dline"); |
| if (dwc_otg_module_params.dma_burst_size != -1) { |
| if (DWC_OTG_PARAM_TEST(dma_burst_size, 1, 1) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 4, 4) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 8, 8) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 16, 16) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 32, 32) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 64, 64) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 128, 128) |
| && DWC_OTG_PARAM_TEST(dma_burst_size, 256, 256)) { |
| DWC_ERROR |
| ("`%d' invalid for parameter `dma_burst_size'\n", |
| dwc_otg_module_params.dma_burst_size); |
| dwc_otg_module_params.dma_burst_size = 32; |
| retval++; |
| } |
| } |
| if (dwc_otg_module_params.phy_utmi_width != -1) { |
| if (DWC_OTG_PARAM_TEST(phy_utmi_width, 8, 8) |
| && DWC_OTG_PARAM_TEST(phy_utmi_width, 16, 16)) { |
| DWC_ERROR("`%d'invalid for parameter 'phy_utmi_width'\n" |
| , dwc_otg_module_params.phy_utmi_width); |
| dwc_otg_module_params.phy_utmi_width = 8; /*fscz 16*/ |
| retval++; |
| } |
| } |
| for (i = 0; i < 15; i++) { |
| /** @todo should be like above */ |
| if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { |
| if (DWC_OTG_PARAM_TEST |
| (dev_perio_tx_fifo_size[i], 4, 768)) { |
| DWC_ERROR("`%d' invalid for parameter `%s_%d'\n" |
| , dwc_otg_module_params.dev_perio_tx_fifo_size[i], |
| "dev_perio_tx_fifo_size", i); |
| dwc_otg_module_params. |
| dev_perio_tx_fifo_size[i] = |
| dwc_param_dev_perio_tx_fifo_size_default; |
| retval++; |
| } |
| } |
| } |
| DWC_OTG_PARAM_ERR(en_multiple_tx_fifo, 0, 1, "en_multiple_tx_fifo"); |
| for (i = 0; i < 15; i++) { |
| /** @todo should be like above */ |
| if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { |
| if (DWC_OTG_PARAM_TEST(dev_tx_fifo_size[i], 4, 768)) { |
| DWC_ERROR("`%d' invalid for parameter `%s_%d'\n" |
| , dwc_otg_module_params.dev_tx_fifo_size[i], |
| "dev_tx_fifo_size", i); |
| dwc_otg_module_params.dev_tx_fifo_size[i] = |
| dwc_param_dev_tx_fifo_size_default; |
| retval++; |
| } |
| } |
| } |
| DWC_OTG_PARAM_ERR(thr_ctl, 0, 7, "thr_ctl"); |
| DWC_OTG_PARAM_ERR(tx_thr_length, 8, 128, "tx_thr_length"); |
| DWC_OTG_PARAM_ERR(rx_thr_length, 8, 128, "rx_thr_length"); |
| |
| /* |
| * At this point, all module parameters that have been set by the user |
| * are valid, and those that have not are left unset. Now set their |
| * default values and/or check the parameters against the hardware |
| * configurations of the OTG core. |
| */ |
| |
| /* This sets the parameter to the default value if it has not been set by the |
| * user */ |
| #define DWC_OTG_PARAM_SET_DEFAULT(_param_) \ |
| ({ \ |
| int changed = 1; \ |
| if (dwc_otg_module_params._param_ == -1) { \ |
| changed = 0; \ |
| dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ |
| } \ |
| changed; \ |
| }) |
| |
| /* This checks the macro against the hardware configuration to see if it is |
| * valid. It is possible that the default value could be invalid. In this |
| * case, it will report a module error if the user touched the parameter. |
| * Otherwise it will adjust the value without any error. */ |
| #define DWC_OTG_PARAM_CHECK_VALID(_param_, _str_, _is_valid_, _set_valid_) \ |
| ({ \ |
| int changed = DWC_OTG_PARAM_SET_DEFAULT(_param_); \ |
| int error = 0; \ |
| if (!(_is_valid_)) { \ |
| if (changed) { \ |
| DWC_ERROR("`%d' invalid for parameter `%s'" \ |
| "Check HW configuration.\n", \ |
| dwc_otg_module_params._param_, _str_); \ |
| error = 1; \ |
| } \ |
| dwc_otg_module_params._param_ = (_set_valid_); \ |
| } \ |
| error; \ |
| }) |
| |
| /* OTG Cap */ |
| retval += DWC_OTG_PARAM_CHECK_VALID(otg_cap, "otg_cap", |
| ({ |
| int valid; |
| valid = 1; |
| switch (dwc_otg_module_params.otg_cap) { |
| |
| case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE: |
| if (core_if->hwcfg2.b.op_mode != |
| DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) |
| valid = 0; |
| break; |
| case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE: |
| if ((core_if->hwcfg2.b.op_mode != |
| DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) |
| && (core_if->hwcfg2.b.op_mode != |
| DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) |
| && (core_if->hwcfg2.b.op_mode != |
| DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) |
| && (core_if->hwcfg2.b.op_mode != |
| DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) |
| |
| valid = 0; |
| |
| break; |
| case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE: |
| /* always valid */ |
| break; |
| } |
| valid; |
| }), |
| |
| (((core_if->hwcfg2.b.op_mode == |
| DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) || |
| (core_if->hwcfg2.b.op_mode == |
| DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || |
| (core_if->hwcfg2.b.op_mode == |
| DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || |
| (core_if->hwcfg2.b.op_mode == |
| DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ? |
| DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : |
| DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)) ; |
| |
| retval += DWC_OTG_PARAM_CHECK_VALID(dma_enable, "dma_enable", |
| ((dwc_otg_module_params.dma_enable == 1) && |
| (core_if->hwcfg2.b.architecture == 0)) ? 0 : 1, |
| 0); |
| retval += DWC_OTG_PARAM_CHECK_VALID(opt, "opt", 1, 0); |
| DWC_OTG_PARAM_SET_DEFAULT(dma_burst_size); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_support_fs_ls_low_power, |
| "host_support_fs_ls_low_power", 1, 0); |
| retval += DWC_OTG_PARAM_CHECK_VALID(enable_dynamic_fifo, |
| "enable_dynamic_fifo", |
| ((dwc_otg_module_params.enable_dynamic_fifo == 0) || |
| (core_if->hwcfg2.b.dynamic_fifo == 1)), 0); |
| retval += DWC_OTG_PARAM_CHECK_VALID(data_fifo_size, "data_fifo_size", |
| (dwc_otg_module_params.data_fifo_size <= |
| core_if->hwcfg3.b.dfifo_depth), |
| core_if->hwcfg3.b.dfifo_depth); |
| retval += DWC_OTG_PARAM_CHECK_VALID(dev_rx_fifo_size, |
| "dev_rx_fifo_size", |
| (dwc_otg_module_params.dev_rx_fifo_size <= |
| dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), |
| dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(dev_nperio_tx_fifo_size, |
| "dev_nperio_tx_fifo_size", |
| (dwc_otg_module_params.dev_nperio_tx_fifo_size <= |
| (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), |
| (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_rx_fifo_size, |
| "host_rx_fifo_size", |
| (dwc_otg_module_params.host_rx_fifo_size <= |
| dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), |
| dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_nperio_tx_fifo_size, |
| "host_nperio_tx_fifo_size", |
| (dwc_otg_module_params.host_nperio_tx_fifo_size <= |
| (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), |
| (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_perio_tx_fifo_size, |
| "host_perio_tx_fifo_size", |
| (dwc_otg_module_params.host_perio_tx_fifo_size <= |
| ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))), |
| ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))); |
| retval += DWC_OTG_PARAM_CHECK_VALID(max_transfer_size, |
| "max_transfer_size", |
| (dwc_otg_module_params.max_transfer_size < |
| (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))), |
| ((1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11)) |
| - 1)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(max_packet_count, |
| "max_packet_count", |
| (dwc_otg_module_params.max_packet_count < |
| (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))), |
| ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) |
| - 1)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_channels, "host_channels", |
| (dwc_otg_module_params.host_channels <= |
| (core_if->hwcfg2.b.num_host_chan + 1)), |
| (core_if->hwcfg2.b.num_host_chan + 1)); |
| retval += DWC_OTG_PARAM_CHECK_VALID(dev_endpoints, "dev_endpoints", |
| (dwc_otg_module_params.dev_endpoints <= |
| (core_if->hwcfg2.b.num_dev_ep)), |
| core_if->hwcfg2.b.num_dev_ep); |
| |
| /* |
| * Define the following to disable the FS PHY Hardware checking. This is for |
| * internal testing only. |
| * |
| * #define NO_FS_PHY_HW_CHECKS |
| */ |
| |
| #ifdef NO_FS_PHY_HW_CHECKS |
| retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, "phy_type", 1, 0); |
| #else |
| retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, "phy_type", ({ |
| int valid = 0; |
| if ((dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_UTMI) && |
| ((core_if->hwcfg2.b.hs_phy_type == 1) || |
| (core_if->hwcfg2.b.hs_phy_type == 3))) { |
| valid = 1; |
| } else if ((dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_ULPI) && |
| ((core_if->hwcfg2.b.hs_phy_type == 2) || |
| (core_if->hwcfg2.b.hs_phy_type == 3))) { |
| valid = 1; |
| } else if ((dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_FS) && |
| (core_if->hwcfg2.b.fs_phy_type == 1)) { |
| valid = 1; |
| } |
| valid; |
| }), |
| ({ |
| int set = DWC_PHY_TYPE_PARAM_FS; |
| if (core_if->hwcfg2.b.hs_phy_type) { |
| if ((core_if->hwcfg2.b.hs_phy_type == 3) || |
| (core_if->hwcfg2.b.hs_phy_type == 1)) |
| set = DWC_PHY_TYPE_PARAM_UTMI; |
| else |
| set = DWC_PHY_TYPE_PARAM_ULPI; |
| } |
| set; |
| })) ; |
| |
| #endif |
| retval += DWC_OTG_PARAM_CHECK_VALID(speed, "speed", |
| (dwc_otg_module_params.speed == 0) && |
| (dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_FS) ? 0 : 1, |
| dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_FS ? 1 : 0); |
| retval += DWC_OTG_PARAM_CHECK_VALID(host_ls_low_power_phy_clk, |
| "host_ls_low_power_phy_clk", |
| ((dwc_otg_module_params.host_ls_low_power_phy_clk == |
| DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) && |
| (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) |
| ? 0 : 1), |
| ((dwc_otg_module_params.phy_type == |
| DWC_PHY_TYPE_PARAM_FS) ? |
| DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : |
| DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)); |
| DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ddr); |
| DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ext_vbus); |
| DWC_OTG_PARAM_SET_DEFAULT(phy_utmi_width); |
| DWC_OTG_PARAM_SET_DEFAULT(ulpi_fs_ls); |
| DWC_OTG_PARAM_SET_DEFAULT(ts_dline); |
| |
| #ifdef NO_FS_PHY_HW_CHECKS |
| retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, "i2c_enable", 1, 0); |
| |
| #else /* */ |
| retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, "i2c_enable", |
| (dwc_otg_module_params.i2c_enable == 1) && |
| (core_if->hwcfg3.b.i2c == 0) ? 0 : 1, 0); |
| #endif |
| |
| for (i = 0; i < 15; i++) { |
| int changed = 1; |
| int error = 0; |
| if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] == -1) { |
| changed = 0; |
| dwc_otg_module_params.dev_perio_tx_fifo_size[i] = |
| dwc_param_dev_perio_tx_fifo_size_default; |
| } |
| if (!(dwc_otg_module_params.dev_perio_tx_fifo_size[i] <= |
| (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { |
| if (changed) { |
| DWC_ERROR("`%d' invalid for parameter " |
| "`dev_perio_fifo_size_%d'." |
| "Check HW configuration.\n", |
| dwc_otg_module_params.dev_perio_tx_fifo_size[i], |
| i); |
| error = 1; |
| } |
| dwc_otg_module_params.dev_perio_tx_fifo_size[i] = |
| dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); |
| } |
| retval += error; |
| } |
| |
| retval += DWC_OTG_PARAM_CHECK_VALID(en_multiple_tx_fifo, |
| "en_multiple_tx_fifo", |
| ((dwc_otg_module_params.en_multiple_tx_fifo == 1) |
| && (core_if->hwcfg4.b.ded_fifo_en == 0)) ? 0 : 1, |
| 0); |
| |
| for (i = 0; i < 15; i++) { |
| int changed = 1; |
| int error = 0; |
| if (dwc_otg_module_params.dev_tx_fifo_size[i] == -1) { |
| changed = 0; |
| dwc_otg_module_params.dev_tx_fifo_size[i] = |
| dwc_param_dev_tx_fifo_size_default; |
| } |
| if (!(dwc_otg_module_params.dev_tx_fifo_size[i] <= |
| (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { |
| if (changed) { |
| DWC_ERROR("%d' invalid for parameter " |
| "`dev_perio_fifo_size_%d'." |
| "Check HW configuration.\n", |
| dwc_otg_module_params.dev_tx_fifo_size[i], |
| i); |
| error = 1; |
| } |
| dwc_otg_module_params.dev_tx_fifo_size[i] = |
| dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); |
| } |
| retval += error; |
| } |
| DWC_OTG_PARAM_SET_DEFAULT(thr_ctl); |
| DWC_OTG_PARAM_SET_DEFAULT(tx_thr_length); |
| DWC_OTG_PARAM_SET_DEFAULT(rx_thr_length); |
| if (dwc_otg_module_params.mpi_enable != -1) { |
| retval += |
| dwc_otg_set_param_mpi_enable(core_if, |
| dwc_otg_module_params. |
| mpi_enable); |
| } else { |
| core_if->core_params->mpi_enable = |
| core_if->hwcfg2.b.multi_proc_int; |
| } |
| |
| |
| if (dwc_otg_module_params.pti_enable != -1) { |
| retval += |
| dwc_otg_set_param_pti_enable(core_if, |
| dwc_otg_module_params. |
| pti_enable); |
| } else |
| DWC_OTG_PARAM_SET_DEFAULT(pti_enable); |
| |
| |
| if (dwc_otg_module_params.lpm_enable != -1) { |
| retval += |
| dwc_otg_set_param_lpm_enable(core_if, |
| dwc_otg_module_params. |
| lpm_enable); |
| } else { |
| core_if->core_params->lpm_enable = |
| core_if->hwcfg3.b.otg_lpm_en; |
| } |
| if (dwc_otg_module_params.ic_usb_cap != -1) { |
| retval += |
| dwc_otg_set_param_ic_usb_cap(core_if, |
| dwc_otg_module_params. |
| ic_usb_cap); |
| } else { |
| core_if->core_params->ic_usb_cap = |
| core_if->hwcfg3.b.otg_enable_ic_usb; |
| |
| } |
| |
| if (dwc_otg_module_params.ahb_thr_ratio != -1) { |
| retval += |
| dwc_otg_set_param_ahb_thr_ratio(core_if, |
| dwc_otg_module_params. |
| ahb_thr_ratio); |
| } else |
| DWC_OTG_PARAM_SET_DEFAULT(ahb_thr_ratio); |
| |
| |
| |
| return retval; |
| } |
| |
| /** |
| * This function is the top level interrupt handler for the Common |
| * (Device and host modes) interrupts. |
| */ |
| static irqreturn_t dwc_otg_common_irq(int irq, void *dev) |
| { |
| struct dwc_otg_device *otg_dev = dev; |
| int32_t retval = IRQ_NONE; |
| |
| retval = dwc_otg_handle_common_intr(otg_dev->core_if); |
| |
| return IRQ_RETVAL(retval); |
| } |
| |
| #ifdef OTG_EXT_CHG_PUMP |
| /** |
| * This function is the interrupt handler for the OverCurrent condition |
| * from the external charge pump (if enabled) |
| */ |
| static irqreturn_t dwc_otg_externalchgpump_irq(int irq, void *dev) |
| { |
| struct dwc_otg_device *otg_dev = dev; |
| int32_t retval = IRQ_NONE; |
| dwc_otg_hcd_t *_dwc_otg_hcd = NULL; |
| |
| DWC_DEBUGPL(DBG_OFF, " ++OTG OverCurrent Detected " |
| "(ExtChgPump Interrupt)++ \n"); |
| |
| if (dwc_otg_is_host_mode(otg_dev->core_if)) { |
| hprt0_data_t hprt0 = {.d32 = 0}; |
| _dwc_otg_hcd = otg_dev->hcd; |
| _dwc_otg_hcd->flags.b.port_over_current_change = 1; |
| |
| hprt0.b.prtpwr = 0; |
| dwc_write_reg32(_dwc_otg_hcd->core_if->host_if->hprt0, |
| hprt0.d32); |
| |
| if (otg_dev->soc_disable_vbus) |
| otg_dev->soc_disable_vbus(); |
| |
| } else { |
| /* Device mode - This int is n/a for device mode */ |
| DWC_ERROR(" DeviceMode: OTG OverCurrent Detected\n"); |
| } |
| |
| retval |= 1; |
| return IRQ_RETVAL(retval); |
| } |
| #endif |
| |
| /** |
| * This function is called when a device is unregistered with the |
| * dwc_otg_driver. This happens, for example, when the rmmod command is |
| * executed. The device may or may not be electrically present. If it is |
| * present, the driver stops device processing. Any resources used on behalf |
| * of this device are freed. |
| * |
| * @param[in] dev |
| */ |
| static int dwc_otg_driver_remove(struct platform_device *pdev) |
| { |
| struct dwc_otg_device *otg_dev = platform_get_drvdata(pdev); |
| DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, (void *)&pdev->dev); |
| if (otg_dev == NULL) { |
| /* Memory allocation for the dwc_otg_device failed. */ |
| return 0; |
| } |
| /* |
| * Free the IRQ |
| */ |
| if (otg_dev->common_irq_installed) |
| free_irq(otg_dev->irq, otg_dev); |
| |
| #ifndef DWC_DEVICE_ONLY |
| if (otg_dev->hcd != NULL) |
| dwc_otg_hcd_remove(&pdev->dev); |
| #endif |
| |
| #ifndef DWC_HOST_ONLY |
| if (otg_dev->pcd != NULL) |
| dwc_otg_pcd_remove(&pdev->dev); |
| |
| #endif |
| if (otg_dev->core_if != NULL) |
| dwc_otg_cil_remove(otg_dev->core_if); |
| |
| /* |
| * Remove the device attributes |
| */ |
| dwc_otg_attr_remove(&pdev->dev); |
| |
| /* |
| * Return the memory. |
| */ |
| if (otg_dev->base != NULL) |
| iounmap(otg_dev->base); |
| |
| if (otg_dev->phys_addr != 0) |
| release_mem_region(otg_dev->phys_addr, otg_dev->base_len); |
| |
| kfree(otg_dev); |
| |
| /* |
| * Clear the drvdata pointer. |
| */ |
| platform_set_drvdata(pdev, NULL); |
| return 0; |
| } |
| |
| #ifdef OTG_PLB_DMA_TASKLET |
| /** |
| * This function is the top level interrupt handler for the Common |
| * (Device and host modes) interrupts. |
| */ |
| static irqreturn_t dwc_otg_plbdma(int irq, void *dev) |
| { |
| struct dwc_otg_device *otg_dev = dev; |
| int32_t retval = IRQ_HANDLED; |
| |
| ppc4xx_clr_dma_status(0); |
| DWC_DEBUGPL(DBG_SP, "%s reset release_later\n", __func__); |
| atomic_set(&release_later, 0); |
| dwc_otg_enable_global_interrupts(otg_dev->core_if); |
| |
| return IRQ_RETVAL(retval); |
| } |
| #endif |
| |
| /** |
| * This function is called when an device is bound to a |
| * dwc_otg_driver. It creates the driver components required to |
| * control the device (CIL, HCD, and PCD) and it initializes the |
| * device. The driver components are stored in a dwc_otg_device |
| * structure. A reference to the dwc_otg_device is saved in the |
| * device. This allows the driver to access the dwc_otg_device |
| * structure on subsequent calls to driver methods for this device. |
| * |
| * @param[in] dev device definition |
| */ |
| static int dwc_otg_driver_probe(struct platform_device *pdev) |
| { |
| int retval = 0; |
| struct dwc_otg_device *dwc_otg_device; |
| struct dwc_otg_board *pdata; |
| int32_t snpsid; |
| struct resource *res; |
| #if 0 |
| union gusbcfg_data usbcfg = {.d32 = 0}; |
| #endif |
| |
| #if defined(OTG_EXT_CHG_PUMP) || defined(OTG_PLB_DMA_TASKLET) |
| int irq; |
| #endif |
| |
| dev_dbg(&pdev->dev, "dwc_otg_driver_probe (%p)\n", pdev); |
| dwc_otg_device = kmalloc(sizeof(struct dwc_otg_device), GFP_KERNEL); |
| if (!dwc_otg_device) { |
| dev_err(&pdev->dev, "kmalloc of dwc_otg_device failed\n"); |
| retval = -ENOMEM; |
| goto fail; |
| } |
| memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); |
| dwc_otg_device->reg_offset = 0xFFFFFFFF; |
| |
| /* |
| * Retrieve the memory and IRQ resources. |
| */ |
| dwc_otg_device->irq = platform_get_irq(pdev, 0); |
| if (dwc_otg_device->irq == 0) { |
| dev_err(&pdev->dev, "no device irq\n"); |
| retval = -ENODEV; |
| goto fail; |
| } |
| dev_dbg(&pdev->dev, "OTG - device irq: %d\n", dwc_otg_device->irq); |
| res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (res == NULL) { |
| dev_err(&pdev->dev, "no CSR address\n"); |
| retval = -ENODEV; |
| goto fail; |
| } |
| dev_dbg(&pdev->dev, "OTG - ioresource_mem start0x%08x: end:0x%08x\n", |
| (unsigned)res->start, (unsigned)res->end); |
| dwc_otg_device->phys_addr = res->start; |
| dwc_otg_device->base_len = res->end - res->start + 1; |
| if (request_mem_region(dwc_otg_device->phys_addr, |
| dwc_otg_device->base_len, |
| dwc_driver_name) == NULL |
| ) { |
| dev_err(&pdev->dev, "request_mem_region failed\n"); |
| retval = -EBUSY; |
| goto fail; |
| } |
| |
| /* |
| * Get the remaining platform data |
| */ |
| pdata = (struct dwc_otg_board *)pdev->dev.platform_data; |
| if (pdata) { |
| dwc_otg_device->soc_enable_vbus = pdata->enable_vbus; |
| dwc_otg_device->soc_disable_vbus = pdata->disable_vbus; |
| dwc_otg_device->soc_vbus_valid = pdata->vbus_valid; |
| } |
| |
| /* |
| * Map the DWC_otg Core memory into virtual address space. |
| */ |
| |
| dwc_otg_device->base = ioremap_nocache(dwc_otg_device->phys_addr, |
| dwc_otg_device->base_len); |
| if (dwc_otg_device->base == NULL) { |
| dev_err(&pdev->dev, "ioremap() failed\n"); |
| retval = -ENOMEM; |
| goto fail; |
| } |
| |
| dev_dbg(&pdev->dev, "mapped base=0x%p\n", dwc_otg_device->base); |
| |
| /* |
| * Attempt to ensure this device is really a DWC_otg Controller. |
| * Read and verify the SNPSID register contents. The value should be |
| * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX". |
| */ |
| snpsid = dwc_read_reg32((u32 __iomem *) |
| ((u8 __iomem *) dwc_otg_device->base + 0x40)); |
| /* |
| * Initialize driver data to point to the global DWC_otg |
| * Device structure. |
| */ |
| platform_set_drvdata(pdev, dwc_otg_device); |
| dev_dbg(&pdev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); |
| dwc_otg_device->core_if = |
| dwc_otg_cil_init(dwc_otg_device->base, |
| &dwc_otg_module_params, |
| dwc_otg_device); |
| if (!dwc_otg_device->core_if) { |
| dev_err(&pdev->dev, "CIL initialization failed!\n"); |
| retval = -ENOMEM; |
| goto fail; |
| } |
| /* |
| * Validate parameter values. |
| */ |
| if (check_parameters(dwc_otg_device->core_if) != 0) { |
| retval = -EINVAL; |
| goto fail; |
| } |
| |
| /* Added for PLB DMA phys virt mapping */ |
| dwc_otg_device->core_if->phys_addr = dwc_otg_device->phys_addr; |
| |
| /* |
| * Create Device Attributes in sysfs |
| */ |
| dwc_otg_attr_create(&pdev->dev); |
| |
| /* |
| * Disable the global interrupt until all the interrupt |
| * handlers are installed. |
| */ |
| dwc_otg_disable_global_interrupts(dwc_otg_device->core_if); |
| |
| /* |
| * Install the interrupt handler for the common interrupts before |
| * enabling common interrupts in core_init below. |
| */ |
| DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", |
| dwc_otg_device->irq); |
| retval = request_irq(dwc_otg_device->irq, |
| dwc_otg_common_irq, |
| IRQF_SHARED, |
| "dwc_otg", |
| dwc_otg_device); |
| |
| if (retval != 0) { |
| DWC_ERROR("request of irq%d failed retval: %d\n", |
| dwc_otg_device->irq, retval); |
| retval = -EBUSY; |
| goto fail; |
| } else { |
| dwc_otg_device->common_irq_installed = 1; |
| } |
| |
| #ifdef CONFIG_MACH_IPMATE |
| set_irq_type(_lmdev->irq, IRQT_LOW); |
| #endif |
| /* |
| * Initialize the DWC_otg core. |
| */ |
| dwc_otg_core_init(dwc_otg_device->core_if); |
| |
| #ifdef OTG_EXT_CHG_PUMP |
| /* configure GPIO to use IRQ2, IRQ=58 (IRQ2) */ |
| irq = platform_get_irq(pdev, 1); |
| retval = request_irq(irq, dwc_otg_externalchgpump_irq, IRQF_SHARED, |
| "dwc_otg_ext_chg_pump", dwc_otg_device); |
| if (retval != 0) { |
| DWC_ERROR("request of irq:2(ExtInt) failed retval: %d\n", |
| retval); |
| retval = -EBUSY; |
| goto fail; |
| } else { |
| printk(KERN_INFO "%s: (ExtChgPump-OverCurrent Detection)" |
| " IRQ2 registered\n", dwc_driver_name); |
| } |
| #endif |
| |
| #ifndef DWC_HOST_ONLY |
| /* |
| * Initialize the PCD |
| */ |
| retval = dwc_otg_pcd_init(&pdev->dev); |
| |
| if (retval != 0) { |
| DWC_ERROR("dwc_otg_pcd_init failed\n"); |
| dwc_otg_device->pcd = NULL; |
| goto fail; |
| } |
| |
| #endif |
| #ifndef DWC_DEVICE_ONLY |
| /* |
| * Initialize the HCD |
| */ |
| #if 0 /* force_host_mode to start*/ |
| usbcfg.d32 = |
| dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs->gusbcfg); |
| usbcfg.b.force_host_mode = 1; |
| dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs->gusbcfg, |
| usbcfg.d32); |
| #endif |
| retval = dwc_otg_hcd_init(&pdev->dev, dwc_otg_device); |
| if (retval != 0) { |
| DWC_ERROR("dwc_otg_hcd_init failed\n"); |
| dwc_otg_device->hcd = NULL; |
| goto fail; |
| } |
| |
| #endif |
| |
| /* |
| * Switch VBUS to normal |
| */ |
| if (dwc_otg_device->soc_vbus_valid) |
| dwc_otg_device->soc_vbus_valid(1); |
| |
| /* |
| * Enable the global interrupt after all the interrupt |
| * handlers are installed. |
| */ |
| dwc_otg_enable_global_interrupts(dwc_otg_device->core_if); |
| #if 0 /* Force device mode to start*/ |
| usbcfg.d32 = |
| dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs->gusbcfg); |
| usbcfg.b.force_host_mode = 0; |
| dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs->gusbcfg, |
| usbcfg.d32); |
| #endif |
| |
| #ifdef OTG_PLB_DMA_TASKLET |
| atomic_set(&release_later, 0); |
| irq = platform_get_irq(pdev, 2); |
| retval = request_irq(irq, dwc_otg_plbdma, IRQF_SHARED, |
| "dwc_otg_plbdma", dwc_otg_device); |
| if (retval != 0) { |
| DWC_ERROR("Request of irq %d failed retval: %d\n", |
| PLB_DMA_CH_INT, retval); |
| retval = -EBUSY; |
| goto fail; |
| } else { |
| DWC_DEBUGPL(DBG_CIL, "%s Irq %d registered\n", dwc_driver_name, |
| PLB_DMA_CH_INT); |
| } |
| #endif |
| return 0; |
| |
| fail: |
| dwc_otg_driver_remove(pdev); |
| return retval; |
| } |
| |
| #ifdef CONFIG_PM_SLEEP |
| static int dwc_otg_suspend(struct device *dev) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| int ret; |
| |
| #ifndef DWC_DEVICE_ONLY |
| ret = dwc_otg_hcd_suspend(otg_dev->hcd); |
| if (ret) |
| return ret; |
| #endif |
| |
| /* |
| * Switch VBUS to invalid |
| */ |
| if (otg_dev->soc_vbus_valid) |
| otg_dev->soc_vbus_valid(0); |
| |
| return 0; |
| } |
| |
| static int dwc_otg_resume(struct device *dev) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| |
| /* |
| * Initialize the DWC_otg core. |
| */ |
| dwc_otg_core_init(otg_dev->core_if); |
| |
| /* |
| * Switch VBUS to normal |
| */ |
| if (otg_dev->soc_vbus_valid) |
| otg_dev->soc_vbus_valid(1); |
| |
| /* |
| * Enable the global interrupt after all the interrupt |
| * handlers are installed. |
| */ |
| dwc_otg_enable_global_interrupts(otg_dev->core_if); |
| |
| #ifndef DWC_DEVICE_ONLY |
| dwc_otg_hcd_resume(otg_dev->hcd); |
| #endif |
| |
| return 0; |
| } |
| #else |
| #define dwc_otg_driver_suspend NULL |
| #define dwc_otg_driver_resume NULL |
| #endif |
| |
| static SIMPLE_DEV_PM_OPS(dwc_otg_pmops, dwc_otg_suspend, dwc_otg_resume); |
| |
| /** |
| * This structure defines the methods to be called by a bus driver |
| * during the lifecycle of a device on that bus. Both drivers and |
| * devices are registered with a bus driver. The bus driver matches |
| * devices to drivers based on information in the device and driver |
| * structures. |
| * |
| * The probe function is called when the bus driver matches a device |
| * to this driver. The remove function is called when a device is |
| * unregistered with the bus driver. |
| */ |
| static struct platform_driver dwc_otg_driver = { |
| .probe = dwc_otg_driver_probe, |
| .remove = dwc_otg_driver_remove, |
| .driver = { |
| .name = (char *)dwc_driver_name, |
| .bus = &platform_bus_type, |
| .pm = &dwc_otg_pmops, |
| }, |
| }; |
| |
| /** |
| * This function is called when the dwc_otg_driver is installed with the |
| * insmod command. It registers the dwc_otg_driver structure with the |
| * appropriate bus driver. This will cause the dwc_otg_driver_probe function |
| * to be called. In addition, the bus driver will automatically expose |
| * attributes defined for the device and driver in the special sysfs file |
| * system. |
| * |
| * @return |
| */ |
| static int __init dwc_otg_driver_init(void) |
| { |
| int retval = 0, ret = 0; |
| printk(KERN_INFO "%s: version %s\n", dwc_driver_name, |
| DWC_DRIVER_VERSION); |
| retval = platform_driver_register(&dwc_otg_driver); |
| if (retval < 0) { |
| printk(KERN_ERR "%s registration failed. retval=%d\n", |
| dwc_driver_name, retval); |
| return retval; |
| } |
| ret = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version); |
| ret = driver_create_file(&dwc_otg_driver.driver, |
| &driver_attr_debuglevel); |
| return retval; |
| } |
| |
| module_init(dwc_otg_driver_init); |
| |
| /** |
| * This function is called when the driver is removed from the kernel |
| * with the rmmod command. The driver unregisters itself with its bus |
| * driver. |
| * |
| */ |
| static void __exit dwc_otg_driver_cleanup(void) |
| { |
| printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n"); |
| driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); |
| driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); |
| platform_driver_unregister(&dwc_otg_driver); |
| printk(KERN_INFO "%s module removed\n", dwc_driver_name); |
| } module_exit(dwc_otg_driver_cleanup); |
| |
| MODULE_DESCRIPTION(DWC_DRIVER_DESC); |
| MODULE_AUTHOR("Synopsys Inc."); |
| MODULE_LICENSE("GPL"); |
| |
| module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); |
| MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); |
| module_param_named(opt, dwc_otg_module_params.opt, int, 0444); |
| MODULE_PARM_DESC(opt, "OPT Mode"); |
| module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); |
| MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); |
| module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int, |
| 0444); |
| MODULE_PARM_DESC(dma_desc_enable, |
| "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled"); |
| module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, |
| 0444); |
| MODULE_PARM_DESC(dma_burst_size, |
| "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); |
| module_param_named(speed, dwc_otg_module_params.speed, int, 0444); |
| MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); |
| module_param_named(host_support_fs_ls_low_power, |
| dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444); |
| MODULE_PARM_DESC(host_support_fs_ls_low_power, |
| "Support Low Power w/FS or LS 0=Support 1=Don't Support"); |
| module_param_named(host_ls_low_power_phy_clk, |
| dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); |
| MODULE_PARM_DESC(host_ls_low_power_phy_clk, |
| "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); |
| module_param_named(enable_dynamic_fifo, |
| dwc_otg_module_params.enable_dynamic_fifo, int, 0444); |
| MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); |
| module_param_named(data_fifo_size, |
| dwc_otg_module_params.data_fifo_size, int, 0444); |
| MODULE_PARM_DESC(data_fifo_size, |
| "Total number of words in the data FIFO memory 32-32768"); |
| module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, |
| int, 0444); |
| MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); |
| module_param_named(dev_nperio_tx_fifo_size, |
| dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); |
| MODULE_PARM_DESC(dev_nperio_tx_fifo_size, |
| "Number of words in the non-periodic Tx FIFO 16-32768"); |
| module_param_named(dev_perio_tx_fifo_size_1, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_2, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_3, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_4, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_5, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_6, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_7, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_8, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_9, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_10, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_11, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, |
| 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_12, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, |
| 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_13, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, |
| 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_14, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, |
| 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(dev_perio_tx_fifo_size_15, |
| dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, |
| 0444); |
| MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, |
| "Number of words in the periodic Tx FIFO 4-768"); |
| module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, |
| int, 0444); |
| MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); |
| module_param_named(host_nperio_tx_fifo_size, |
| dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); |
| MODULE_PARM_DESC(host_nperio_tx_fifo_size, |
| "Number of words in the non-periodic Tx FIFO 16-32768"); |
| module_param_named(host_perio_tx_fifo_size, |
| dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); |
| MODULE_PARM_DESC(host_perio_tx_fifo_size, |
| "Number of words in the host periodic Tx FIFO 16-32768"); |
| module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, |
| int, 0444); |
| |
| /** @todo Set the max to 512K, modify checks */ |
| MODULE_PARM_DESC(max_transfer_size, |
| "The maximum transfer size supported in bytes 2047-65535"); |
| module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, |
| int, 0444); |
| MODULE_PARM_DESC(max_packet_count, |
| "The maximum number of packets in a transfer 15-511"); |
| module_param_named(host_channels, dwc_otg_module_params.host_channels, int, |
| 0444); |
| MODULE_PARM_DESC(host_channels, |
| "The number of host channel registers to use 1-16"); |
| module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, |
| 0444); |
| MODULE_PARM_DESC(dev_endpoints, |
| "The number of endpoints in addition to " |
| "EP0 available for device mode 1-15"); |
| module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); |
| MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); |
| module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, |
| 0444); |
| MODULE_PARM_DESC(phy_utmi_width, |
| "Specifies the UTMI+ Data Width 8 or 16 bits"); |
| module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, |
| 0444); |
| MODULE_PARM_DESC(phy_ulpi_ddr, |
| "ULPI at double or single data rate 0=Single 1=Double"); |
| module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, |
| int, 0444); |
| MODULE_PARM_DESC(phy_ulpi_ext_vbus, |
| "ULPI PHY using internal or external vbus 0=Internal"); |
| module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); |
| MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); |
| module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); |
| MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); |
| module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); |
| MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); |
| module_param_named(debug, g_dbg_lvl, int, 0444); |
| MODULE_PARM_DESC(debug, "0"); |
| module_param_named(en_multiple_tx_fifo, |
| dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); |
| MODULE_PARM_DESC(en_multiple_tx_fifo, |
| "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); |
| module_param_named(dev_tx_fifo_size_1, |
| dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_2, |
| dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_3, |
| dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_4, |
| dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_5, |
| dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_6, |
| dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_7, |
| dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_8, |
| dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_9, |
| dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_10, |
| dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_11, |
| dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_12, |
| dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_13, |
| dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_14, |
| dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(dev_tx_fifo_size_15, |
| dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); |
| MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); |
| module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); |
| MODULE_PARM_DESC(thr_ctl, "Thresholding enable flag bit" |
| "0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- " |
| "bit 0=disabled 1=enabled"); |
| module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, |
| 0444); |
| MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); |
| module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, |
| 0444); |
| MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); |
| |
| module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444); |
| module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444); |
| module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444); |
| MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled"); |
| module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444); |
| MODULE_PARM_DESC(ic_usb_cap, |
| "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled"); |
| module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, |
| 0444); |
| MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio"); |
| |
| |