📄 dwc_otg_driver.c
字号:
/* ========================================================================== * * 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 ARM lm_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/version.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <linux/proc_fs.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)# include <linux/irq.h>#endif#include <asm/io.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)# include <asm/irq.h>#endif#include <asm/sizes.h>#include <asm/arch/regs-s3c6400-clock.h>#include "dwc_otg_plat.h"#include "dwc_otg_attr.h"#include "dwc_otg_driver.h"#include "dwc_otg_cil.h"#include "dwc_otg_pcd.h"#include "dwc_otg_hcd.h"#define DWC_DRIVER_VERSION "2.70a 22-AUG-2007"#define DWC_DRIVER_DESC "HS OTG USB Controller driver"static const char dwc_driver_name[] = "dwc_otg";/*-------------------------------------------------------------------------*//* Encapsulate the module parameter settings */static dwc_otg_core_params_t dwc_otg_module_params = { .opt = -1, .otg_cap = -1, .dma_enable = -1, .dma_desc_enable = -1, .dma_burst_size = -1, .speed = -1, .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, .host_channels = -1, .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,};#if 0/** * 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);#endif/** * Global Debug Level Mask. */uint32_t g_dbg_lvl = 0; /* OFF */#if 0/** * 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);#endif/** * This function is called during module intialization to verify that * the module parameters are in a valid state. */static int check_parameters(dwc_otg_core_if_t * 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(dma_desc_enable, 0, 1, "dma_desc_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 = 16; retval++; } } for (i = 0; i < 15; i++) { /** @todo should be like above */ //DWC_OTG_PARAM_ERR(dev_perio_tx_fifo_size[i],4,768,"dev_perio_tx_fifo_size"); 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 */ //DWC_OTG_PARAM_ERR(dev_tx_fifo_size[i],4,768,"dev_tx_fifo_size"); 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 agains 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -