| /* ========================================================================== |
| * |
| * 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 diagnostic interface will provide access to the controller for |
| * bringing up the hardware and testing. The Linux driver attributes |
| * feature will be used to provide the Linux Diagnostic |
| * Interface. These attributes are accessed through sysfs. |
| */ |
| |
| /** @page "Linux Module Attributes" |
| * |
| * The Linux module attributes feature is used to provide the Linux |
| * Diagnostic Interface. These attributes are accessed through sysfs. |
| * The diagnostic interface will provide access to the controller for |
| * bringing up the hardware and testing. |
| * |
| * Example usage: |
| * To get the current mode: |
| * cat /sys/devices/lm0/mode |
| * |
| * To power down the USB: |
| * echo 0 > /sys/devices/lm0/buspower |
| */ |
| |
| #include <linux/kernel.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/io.h> |
| |
| #include "dwc_otg_attr.h" |
| #include "dwc_otg_driver.h" |
| #include "dwc_otg_pcd.h" |
| #include "dwc_otg_hcd.h" |
| |
| /* |
| * MACROs for defining sysfs attribute |
| */ |
| #define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| static ssize_t _otg_attr_name_##_show(struct device *dev, \ |
| struct device_attribute *attr, \ |
| char *buf) \ |
| { \ |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev);\ |
| u32 val; \ |
| val = dwc_read_reg32(_addr_); \ |
| val = (val & (_mask_)) >> _shift_; \ |
| return sprintf(buf, "%s = 0x%x\n", _string_, val); \ |
| } |
| |
| #define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| static ssize_t _otg_attr_name_##_store(struct device *dev, \ |
| struct device_attribute *attr, \ |
| const char *buf, size_t count) \ |
| { \ |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev);\ |
| u32 set = simple_strtoul(buf, NULL, 16); \ |
| u32 clear = set; \ |
| clear = ((~clear) << _shift_) & _mask_; \ |
| set = (set << _shift_) & _mask_; \ |
| dev_dbg(dev, "Storing Address=0x%p Set=0x%08x Clear=0x%08x\n", \ |
| _addr_, set, clear); \ |
| dwc_modify_reg32(_addr_, clear, set); \ |
| return count; \ |
| } |
| |
| #define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| DEVICE_ATTR(_otg_attr_name_, 0644, \ |
| _otg_attr_name_##_show, _otg_attr_name_##_store); |
| |
| #define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_, \ |
| _addr_, \ |
| _mask_, \ |
| _shift_, \ |
| _string_) \ |
| DEVICE_ATTR(_otg_attr_name_, 0444, _otg_attr_name_##_show, NULL); |
| |
| /* |
| * MACROs for defining sysfs attribute for 32-bit registers |
| */ |
| #define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \ |
| static ssize_t _otg_attr_name_##_show(struct device *dev, \ |
| struct device_attribute *attr, char *buf) \ |
| { \ |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev);\ |
| u32 val; \ |
| val = dwc_read_reg32(_addr_); \ |
| return sprintf(buf, "%s = 0x%08x\n", _string_, val); \ |
| } |
| #define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_, _addr_, _string_) \ |
| static ssize_t _otg_attr_name_##_store(struct device *dev, \ |
| struct device_attribute *attr, \ |
| const char *buf, size_t count) \ |
| { \ |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev);\ |
| u32 val = simple_strtoul(buf, NULL, 16); \ |
| dev_dbg(dev, "Storing Address=0x%p Val=0x%08x\n", \ |
| _addr_, val); \ |
| dwc_write_reg32(_addr_, val); \ |
| return count; \ |
| } |
| |
| #define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_, _addr_, _string_) \ |
| DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \ |
| DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_, _addr_, _string_) \ |
| DEVICE_ATTR(_otg_attr_name_, 0644, _otg_attr_name_##_show, \ |
| _otg_attr_name_##_store); |
| |
| #define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_, _addr_, _string_) \ |
| DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \ |
| DEVICE_ATTR(_otg_attr_name_, 0444, _otg_attr_name_##_show, NULL); |
| |
| |
| /** @name Functions for Show/Store of Attributes */ |
| /**@{*/ |
| |
| /** |
| * Show the register offset of the Register Access. |
| */ |
| static ssize_t |
| regoffset_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| return snprintf(buf, sizeof("0xFFFFFFFF\n")+1, "0x%08x\n", |
| otg_dev->reg_offset); |
| } |
| |
| /** |
| * Set the register offset for the next Register Access Read/Write |
| */ |
| #define SZ_256K 0x00040000 |
| static ssize_t regoffset_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, |
| size_t count) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 offset = simple_strtoul(buf, NULL, 16); |
| if (offset < SZ_256K) |
| otg_dev->reg_offset = offset; |
| else |
| dev_err(dev, "invalid offset\n"); |
| |
| return count; |
| } |
| DEVICE_ATTR(regoffset, S_IRUGO|S_IWUSR, regoffset_show, regoffset_store); |
| |
| /** |
| * Show the value of the register at the offset in the reg_offset |
| * attribute. |
| */ |
| static ssize_t |
| regvalue_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 val; |
| u32 __iomem *addr; |
| |
| if (otg_dev->reg_offset != 0xFFFFFFFF && otg_dev->base) { |
| /* Calculate the address */ |
| addr = (u32 __iomem *)(otg_dev->reg_offset + |
| (u8 __iomem *)otg_dev->base); |
| val = dwc_read_reg32(addr); |
| return snprintf(buf, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1, |
| "Reg@0x%06x = 0x%08x\n", |
| otg_dev->reg_offset, val); |
| } else { |
| dev_err(dev, "Invalid offset (0x%0x)\n", |
| otg_dev->reg_offset); |
| return sprintf(buf, "invalid offset\n"); |
| } |
| } |
| |
| /** |
| * Store the value in the register at the offset in the reg_offset |
| * attribute. |
| * |
| */ |
| static ssize_t |
| regvalue_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 __iomem *addr; |
| u32 val = simple_strtoul(buf, NULL, 16); |
| if (otg_dev->reg_offset != 0xFFFFFFFF && otg_dev->base) { |
| /* Calculate the address */ |
| addr = (u32 __iomem *)(otg_dev->reg_offset + |
| (u8 __iomem *)otg_dev->base); |
| dwc_write_reg32(addr, val); |
| } else |
| dev_err(dev, "Invalid Register Offset (0x%08x)\n", |
| otg_dev->reg_offset); |
| |
| return count; |
| } |
| DEVICE_ATTR(regvalue, S_IRUGO|S_IWUSR, regvalue_show, regvalue_store); |
| |
| /* |
| * Attributes |
| */ |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, |
| &(otg_dev->core_if->core_global_regs->gotgctl), |
| (1<<20), 20, "Mode"); |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, |
| &(otg_dev->core_if->core_global_regs->gusbcfg), |
| (1<<9), 9, "Mode"); |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, |
| &(otg_dev->core_if->core_global_regs->gusbcfg), |
| (1<<8), 8, "Mode"); |
| |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, |
| otg_dev->core_if->host_if->hprt0, |
| 0x01, 0, "Bus Connected"); |
| |
| DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, |
| &(otg_dev->core_if->core_global_regs->gotgctl), |
| "GOTGCTL"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg, |
| &(otg_dev->core_if->core_global_regs->gusbcfg), |
| "GUSBCFG"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz, |
| &(otg_dev->core_if->core_global_regs->grxfsiz), |
| "GRXFSIZ"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz, |
| &(otg_dev->core_if->core_global_regs->gnptxfsiz), |
| "GNPTXFSIZ"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl, |
| &(otg_dev->core_if->core_global_regs->gpvndctl), |
| "GPVNDCTL"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio, |
| &(otg_dev->core_if->core_global_regs->ggpio), |
| "GGPIO"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(guid, |
| &(otg_dev->core_if->core_global_regs->guid), |
| "GUID"); |
| DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid, |
| &(otg_dev->core_if->core_global_regs->gsnpsid), |
| "GSNPSID"); |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, |
| &(otg_dev->core_if->dev_if->dev_global_regs->dcfg), |
| 0x3, 0, "Device Speed"); |
| DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, |
| &(otg_dev->core_if->dev_if->dev_global_regs->dsts), |
| 0x6, 1, "Device Enumeration Speed"); |
| |
| DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz, |
| &(otg_dev->core_if->core_global_regs->hptxfsiz), |
| "HPTXFSIZ"); |
| DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, |
| otg_dev->core_if->host_if->hprt0, |
| "HPRT0"); |
| |
| |
| /** |
| * @todo Add code to initiate the HNP. |
| */ |
| /** |
| * Show the HNP status bit |
| */ |
| static ssize_t |
| hnp_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| union gotgctl_data val; |
| val.d32 = |
| dwc_read_reg32(&(otg_dev->core_if->core_global_regs->gotgctl)); |
| return sprintf(buf, "HstNegScs = 0x%x\n", val.b.hstnegscs); |
| } |
| |
| /** |
| * Set the HNP Request bit |
| */ |
| static ssize_t |
| hnp_store(struct device *dev, struct device_attribute *attr, const char *buf, |
| size_t count) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 in = simple_strtoul(buf, NULL, 16); |
| u32 __iomem *addr = &(otg_dev->core_if->core_global_regs->gotgctl); |
| union gotgctl_data mem; |
| |
| mem.d32 = dwc_read_reg32(addr); |
| mem.b.hnpreq = in; |
| dev_dbg(dev, "Storing Address=0x%p Data=0x%08x\n", |
| addr, mem.d32); |
| dwc_write_reg32(addr, mem.d32); |
| return count; |
| } |
| DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store); |
| |
| /** |
| * @todo Add code to initiate the SRP. |
| */ |
| /** |
| * Show the SRP status bit |
| */ |
| static ssize_t |
| srp_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| #ifndef DWC_HOST_ONLY |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| union gotgctl_data val; |
| val.d32 = |
| dwc_read_reg32(&(otg_dev->core_if->core_global_regs->gotgctl)); |
| return sprintf(buf, "SesReqScs = 0x%x\n", val.b.sesreqscs); |
| #else |
| return sprintf(buf, "Host Only Mode!\n"); |
| #endif |
| } |
| |
| /** |
| * Set the SRP Request bit |
| */ |
| static ssize_t |
| srp_store(struct device *dev, struct device_attribute *attr, const char *buf, |
| size_t count) |
| { |
| #ifndef DWC_HOST_ONLY |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| dwc_otg_pcd_initiate_srp(otg_dev->pcd); |
| #endif |
| return count; |
| } |
| DEVICE_ATTR(srp, 0644, srp_show, srp_store); |
| |
| /** |
| * @todo Need to do more for power on/off? |
| */ |
| /** |
| * Show the Bus Power status |
| */ |
| static ssize_t |
| buspower_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| union hprt0_data val; |
| val.d32 = dwc_read_reg32(otg_dev->core_if->host_if->hprt0); |
| return sprintf(buf, "Bus Power = 0x%x\n", val.b.prtpwr); |
| } |
| |
| |
| /** |
| * Set the Bus Power status |
| */ |
| static ssize_t |
| buspower_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 on = simple_strtoul(buf, NULL, 16); |
| u32 __iomem *addr = otg_dev->core_if->host_if->hprt0; |
| union hprt0_data mem; |
| |
| mem.d32 = dwc_read_reg32(addr); |
| mem.b.prtpwr = on; |
| |
| dwc_write_reg32(addr, mem.d32); |
| |
| return count; |
| } |
| DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store); |
| |
| /** |
| * @todo Need to do more for suspend? |
| */ |
| /** |
| * Show the Bus Suspend status |
| */ |
| static ssize_t |
| bussuspend_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| union hprt0_data val; |
| val.d32 = dwc_read_reg32(otg_dev->core_if->host_if->hprt0); |
| return sprintf(buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); |
| } |
| |
| /** |
| * Set the Bus Suspend status |
| */ |
| static ssize_t |
| bussuspend_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 in = simple_strtoul(buf, NULL, 16); |
| u32 __iomem *addr = otg_dev->core_if->host_if->hprt0; |
| union hprt0_data mem; |
| mem.d32 = dwc_read_reg32(addr); |
| mem.b.prtsusp = in; |
| dev_dbg(dev, "Storing Address=0x%p Data=0x%08x\n", |
| addr, mem.d32); |
| dwc_write_reg32(addr, mem.d32); |
| return count; |
| } |
| DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store); |
| |
| /** |
| * Show the status of Remote Wakeup. |
| */ |
| static ssize_t |
| remote_wakeup_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| #ifndef DWC_HOST_ONLY |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| union dctl_data val; |
| val.d32 = |
| dwc_read_reg32(&otg_dev->core_if->dev_if->dev_global_regs->dctl); |
| return sprintf(buf, "Remote Wakeup = %d Enabled = %d\n", |
| val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable); |
| #else |
| return sprintf(buf, "Host Only Mode!\n"); |
| #endif |
| } |
| |
| /** |
| * Initiate a remote wakeup of the host. The Device control register |
| * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable |
| * flag is set. |
| * |
| */ |
| static ssize_t |
| remote_wakeup_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| #ifndef DWC_HOST_ONLY |
| u32 val = simple_strtoul(buf, NULL, 16); |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| if (val&1) |
| dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1); |
| else |
| dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0); |
| #endif |
| return count; |
| } |
| static DEVICE_ATTR(remote_wakeup, S_IRUGO|S_IWUSR, remote_wakeup_show, |
| remote_wakeup_store); |
| |
| /** |
| * Dump global registers and either host or device registers (depending on the |
| * current mode of the core). |
| */ |
| static ssize_t |
| regdump_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| printk(KERN_DEBUG"%s otg_dev=0x%p\n", __func__, otg_dev); |
| dwc_otg_dump_global_registers(otg_dev->core_if); |
| if (dwc_otg_is_host_mode(otg_dev->core_if)) |
| dwc_otg_dump_host_registers(otg_dev->core_if); |
| else |
| dwc_otg_dump_dev_registers(otg_dev->core_if); |
| |
| return sprintf(buf, "Register Dump\n"); |
| } |
| static DEVICE_ATTR(regdump, S_IRUGO, regdump_show, NULL); |
| |
| /** |
| * Dump the current hcd state. |
| */ |
| static ssize_t |
| hcddump_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| #ifndef DWC_DEVICE_ONLY |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| dwc_otg_hcd_dump_state(otg_dev->hcd); |
| #endif |
| return sprintf(buf, "HCD Dump\n"); |
| } |
| static DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, NULL); |
| |
| /** |
| * Dump the average frame remaining at SOF. This can be used to |
| * determine average interrupt latency. Frame remaining is also shown for |
| * start transfer and two additional sample points. |
| */ |
| static ssize_t |
| hcd_frrem_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| #ifndef DWC_DEVICE_ONLY |
| /* |
| * struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| * TODO: expose this method from hcd: |
| * dwc_otg_hcd_dump_frrem(otg_dev->hcd); |
| */ |
| #endif |
| return sprintf(buf, "HCD Dump Frame Remaining\n"); |
| } |
| static DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, NULL); |
| |
| /** |
| * Displays the time required to read the GNPTXFSIZ register many times (the |
| * output shows the number of times the register is read). |
| */ |
| #define RW_REG_COUNT 10000000 |
| #define MSEC_PER_JIFFIE (1000/HZ) |
| static ssize_t |
| rd_reg_test_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| int i; |
| int time; |
| int start_jiffies; |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| |
| printk(KERN_DEBUG"HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", |
| HZ, MSEC_PER_JIFFIE, loops_per_jiffy); |
| start_jiffies = jiffies; |
| for (i = 0; i < RW_REG_COUNT; i++) |
| dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); |
| |
| time = jiffies - start_jiffies; |
| return sprintf(buf, "Time to read GNPTXFSIZ reg %d times:" |
| " %d msecs (%d jiffies)\n", |
| RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); |
| } |
| |
| static DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, NULL); |
| |
| /** |
| * Displays the time required to write the GNPTXFSIZ register many times (the |
| * output shows the number of times the register is written). |
| */ |
| static ssize_t |
| wr_reg_test_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| int i; |
| int time; |
| int start_jiffies; |
| struct dwc_otg_device *otg_dev = dev_get_drvdata(dev); |
| u32 reg_val; |
| |
| printk(KERN_DEBUG"HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", |
| HZ, MSEC_PER_JIFFIE, loops_per_jiffy); |
| reg_val = |
| dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); |
| start_jiffies = jiffies; |
| for (i = 0; i < RW_REG_COUNT; i++) |
| dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, |
| reg_val); |
| |
| time = jiffies - start_jiffies; |
| return sprintf(buf, "Time to write GNPTXFSIZ reg %d times:" |
| " %d msecs (%d jiffies)\n", |
| RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); |
| } |
| static DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, NULL); |
| |
| /** |
| * Create the device files |
| */ |
| void dwc_otg_attr_create(struct device *dev) |
| { |
| int ret_val = 0; |
| ret_val = device_create_file(dev, &dev_attr_regoffset); |
| ret_val = device_create_file(dev, &dev_attr_regvalue); |
| ret_val = device_create_file(dev, &dev_attr_mode); |
| ret_val = device_create_file(dev, &dev_attr_hnpcapable); |
| ret_val = device_create_file(dev, &dev_attr_srpcapable); |
| ret_val = device_create_file(dev, &dev_attr_hnp); |
| ret_val = device_create_file(dev, &dev_attr_srp); |
| ret_val = device_create_file(dev, &dev_attr_buspower); |
| ret_val = device_create_file(dev, &dev_attr_bussuspend); |
| ret_val = device_create_file(dev, &dev_attr_busconnected); |
| ret_val = device_create_file(dev, &dev_attr_gotgctl); |
| ret_val = device_create_file(dev, &dev_attr_gusbcfg); |
| ret_val = device_create_file(dev, &dev_attr_grxfsiz); |
| ret_val = device_create_file(dev, &dev_attr_gnptxfsiz); |
| ret_val = device_create_file(dev, &dev_attr_gpvndctl); |
| ret_val = device_create_file(dev, &dev_attr_ggpio); |
| ret_val = device_create_file(dev, &dev_attr_guid); |
| ret_val = device_create_file(dev, &dev_attr_gsnpsid); |
| ret_val = device_create_file(dev, &dev_attr_devspeed); |
| ret_val = device_create_file(dev, &dev_attr_enumspeed); |
| ret_val = device_create_file(dev, &dev_attr_hptxfsiz); |
| ret_val = device_create_file(dev, &dev_attr_hprt0); |
| ret_val = device_create_file(dev, &dev_attr_remote_wakeup); |
| ret_val = device_create_file(dev, &dev_attr_regdump); |
| ret_val = device_create_file(dev, &dev_attr_hcddump); |
| ret_val = device_create_file(dev, &dev_attr_hcd_frrem); |
| ret_val = device_create_file(dev, &dev_attr_rd_reg_test); |
| ret_val = device_create_file(dev, &dev_attr_wr_reg_test); |
| } |
| |
| /** |
| * Remove the device files |
| */ |
| void dwc_otg_attr_remove(struct device *dev) |
| { |
| device_remove_file(dev, &dev_attr_regoffset); |
| device_remove_file(dev, &dev_attr_regvalue); |
| device_remove_file(dev, &dev_attr_mode); |
| device_remove_file(dev, &dev_attr_hnpcapable); |
| device_remove_file(dev, &dev_attr_srpcapable); |
| device_remove_file(dev, &dev_attr_hnp); |
| device_remove_file(dev, &dev_attr_srp); |
| device_remove_file(dev, &dev_attr_buspower); |
| device_remove_file(dev, &dev_attr_bussuspend); |
| device_remove_file(dev, &dev_attr_busconnected); |
| device_remove_file(dev, &dev_attr_gotgctl); |
| device_remove_file(dev, &dev_attr_gusbcfg); |
| device_remove_file(dev, &dev_attr_grxfsiz); |
| device_remove_file(dev, &dev_attr_gnptxfsiz); |
| device_remove_file(dev, &dev_attr_gpvndctl); |
| device_remove_file(dev, &dev_attr_ggpio); |
| device_remove_file(dev, &dev_attr_guid); |
| device_remove_file(dev, &dev_attr_gsnpsid); |
| device_remove_file(dev, &dev_attr_devspeed); |
| device_remove_file(dev, &dev_attr_enumspeed); |
| device_remove_file(dev, &dev_attr_hptxfsiz); |
| device_remove_file(dev, &dev_attr_hprt0); |
| device_remove_file(dev, &dev_attr_remote_wakeup); |
| device_remove_file(dev, &dev_attr_regdump); |
| device_remove_file(dev, &dev_attr_hcddump); |
| device_remove_file(dev, &dev_attr_hcd_frrem); |
| device_remove_file(dev, &dev_attr_rd_reg_test); |
| device_remove_file(dev, &dev_attr_wr_reg_test); |
| } |
| |