diff options
Diffstat (limited to 'recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch')
-rw-r--r-- | recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch b/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch new file mode 100644 index 0000000..2d7d88f --- /dev/null +++ b/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch @@ -0,0 +1,348 @@ +From xxxx Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue <bryan.odonoghue@intel.com> +Date: Thu, 13 Feb 2014 16:41:02 +0000 +Subject: [PATCH 12/21] USB gadget serial + +--- + Documentation/usb/linux-cdc-acm.inf | 4 +- + drivers/usb/gadget/Kconfig | 5 +- + drivers/usb/gadget/pch_udc.c | 142 ++++++++++++++++++++++------------ + drivers/usb/gadget/serial.c | 24 +++++- + 4 files changed, 118 insertions(+), 57 deletions(-) + +diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf +index f0ffc27..e56f074 100644 +--- a/Documentation/usb/linux-cdc-acm.inf ++++ b/Documentation/usb/linux-cdc-acm.inf +@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys + [SourceDisksFiles] + [SourceDisksNames] + [DeviceList] +-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00 ++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE + + [DeviceList.NTamd64] +-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00 ++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE + + + ;------------------------------------------------------------------------------ +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index 14625fd..1ab9996 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -439,7 +439,7 @@ config USB_GOKU + gadget drivers to also be dynamically linked. + + config USB_EG20T +- tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" ++ tristate "Intel QRK/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" + depends on PCI + help + This is a USB device driver for EG20T PCH. +@@ -459,7 +459,8 @@ config USB_EG20T + ML7831 is for general purpose use. + ML7213/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7831 is completely compatible for Intel EG20T PCH. +- ++ ++ This driver can be used with Intel's Quark SOC platform + # + # LAST -- dummy/emulated controller + # +diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c +index 6490c00..df96b3b 100644 +--- a/drivers/usb/gadget/pch_udc.c ++++ b/drivers/usb/gadget/pch_udc.c +@@ -6,6 +6,7 @@ + * the Free Software Foundation; version 2 of the License. + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++#include <asm/qrk.h> + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/pci.h> +@@ -18,6 +19,10 @@ + #include <linux/gpio.h> + #include <linux/irq.h> + ++static unsigned int enable_msi = 1; ++module_param(enable_msi, uint, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode"); ++ + /* GPIO port for VBUS detecting */ + static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */ + +@@ -343,6 +348,7 @@ struct pch_vbus_gpio_data { + * @setup_data: Received setup data + * @phys_addr: of device memory + * @base_addr: for mapped device memory ++ * @bar: Indicates which PCI BAR for USB regs + * @irq: IRQ line for the device + * @cfg_data: current cfg, intf, and alt in use + * @vbus_gpio: GPIO informaton for detecting VBUS +@@ -371,13 +377,16 @@ struct pch_udc_dev { + struct usb_ctrlrequest setup_data; + unsigned long phys_addr; + void __iomem *base_addr; ++ unsigned bar; + unsigned irq; + struct pch_udc_cfg_data cfg_data; + struct pch_vbus_gpio_data vbus_gpio; + }; + +-#define PCH_UDC_PCI_BAR 1 ++#define PCH_UDC_PCI_BAR_QUARK 0 ++#define PCH_UDC_PCI_BAR_EG20T 1 + #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 ++#define PCI_DEVICE_ID_INTEL_QUARK_UDC 0x0939 + #define PCI_VENDOR_ID_ROHM 0x10DB + #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D + #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 +@@ -2779,55 +2788,70 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev) + { + struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev; + u32 dev_intr, ep_intr; +- int i; +- +- dev_intr = pch_udc_read_device_interrupts(dev); +- ep_intr = pch_udc_read_ep_interrupts(dev); +- +- /* For a hot plug, this find that the controller is hung up. */ +- if (dev_intr == ep_intr) +- if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) { +- dev_dbg(&dev->pdev->dev, "UDC: Hung up\n"); +- /* The controller is reset */ +- pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); +- return IRQ_HANDLED; ++ int i, events = 0; ++ ++ mask_pvm(dev->pdev); ++ do { ++ events = 0; ++ dev_intr = pch_udc_read_device_interrupts(dev); ++ ep_intr = pch_udc_read_ep_interrupts(dev); ++ ++ /* For a hot plug, this find that the controller is hung up. */ ++ if (dev_intr == ep_intr) ++ if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) { ++ dev_dbg(&dev->pdev->dev, "UDC: Hung up\n"); ++ /* The controller is reset */ ++ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); ++ unmask_pvm(dev->pdev); ++ return IRQ_HANDLED; ++ } ++ if (dev_intr){ ++ /* Clear device interrupts */ ++ pch_udc_write_device_interrupts(dev, dev_intr); ++ events = 1; + } +- if (dev_intr) +- /* Clear device interrupts */ +- pch_udc_write_device_interrupts(dev, dev_intr); +- if (ep_intr) +- /* Clear ep interrupts */ +- pch_udc_write_ep_interrupts(dev, ep_intr); +- if (!dev_intr && !ep_intr) +- return IRQ_NONE; +- spin_lock(&dev->lock); +- if (dev_intr) +- pch_udc_dev_isr(dev, dev_intr); +- if (ep_intr) { +- pch_udc_read_all_epstatus(dev, ep_intr); +- /* Process Control In interrupts, if present */ +- if (ep_intr & UDC_EPINT_IN_EP0) { +- pch_udc_svc_control_in(dev); +- pch_udc_postsvc_epinters(dev, 0); ++ if (ep_intr){ ++ /* Clear ep interrupts */ ++ pch_udc_write_ep_interrupts(dev, ep_intr); ++ events = 1; + } +- /* Process Control Out interrupts, if present */ +- if (ep_intr & UDC_EPINT_OUT_EP0) +- pch_udc_svc_control_out(dev); +- /* Process data in end point interrupts */ +- for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) { +- if (ep_intr & (1 << i)) { +- pch_udc_svc_data_in(dev, i); +- pch_udc_postsvc_epinters(dev, i); ++ if (!dev_intr && !ep_intr){ ++ unmask_pvm(dev->pdev); ++ return IRQ_NONE; ++ } ++ spin_lock(&dev->lock); ++ if (dev_intr){ ++ pch_udc_dev_isr(dev, dev_intr); ++ } ++ if (ep_intr) { ++ pch_udc_read_all_epstatus(dev, ep_intr); ++ /* Process Control In interrupts, if present */ ++ if (ep_intr & UDC_EPINT_IN_EP0) { ++ pch_udc_svc_control_in(dev); ++ pch_udc_postsvc_epinters(dev, 0); ++ } ++ /* Process Control Out interrupts, if present */ ++ if (ep_intr & UDC_EPINT_OUT_EP0) ++ pch_udc_svc_control_out(dev); ++ /* Process data in end point interrupts */ ++ for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) { ++ if (ep_intr & (1 << i)) { ++ pch_udc_svc_data_in(dev, i); ++ pch_udc_postsvc_epinters(dev, i); ++ } + } ++ /* Process data out end point interrupts */ ++ for (i = UDC_EPINT_OUT_SHIFT + 1; ++ i < (UDC_EPINT_OUT_SHIFT + PCH_UDC_USED_EP_NUM); ++ i++) ++ if (ep_intr & (1 << i)) ++ pch_udc_svc_data_out(dev, ++ i - UDC_EPINT_OUT_SHIFT); + } +- /* Process data out end point interrupts */ +- for (i = UDC_EPINT_OUT_SHIFT + 1; i < (UDC_EPINT_OUT_SHIFT + +- PCH_UDC_USED_EP_NUM); i++) +- if (ep_intr & (1 << i)) +- pch_udc_svc_data_out(dev, i - +- UDC_EPINT_OUT_SHIFT); +- } +- spin_unlock(&dev->lock); ++ spin_unlock(&dev->lock); ++ }while(events == 1); ++ unmask_pvm(dev->pdev); ++ + return IRQ_HANDLED; + } + +@@ -3108,7 +3132,7 @@ static void pch_udc_remove(struct pci_dev *pdev) + iounmap(dev->base_addr); + if (dev->mem_region) + release_mem_region(dev->phys_addr, +- pci_resource_len(pdev, PCH_UDC_PCI_BAR)); ++ pci_resource_len(pdev, dev->bar)); + if (dev->active) + pci_disable_device(pdev); + if (dev->registered) +@@ -3184,9 +3208,16 @@ static int pch_udc_probe(struct pci_dev *pdev, + dev->active = 1; + pci_set_drvdata(pdev, dev); + ++ /* Determine BAR based on PCI ID */ ++ if(id->device == PCI_DEVICE_ID_INTEL_QUARK_UDC){ ++ dev->bar = PCH_UDC_PCI_BAR_QUARK; ++ }else { ++ dev->bar = PCH_UDC_PCI_BAR_EG20T; ++ } ++ + /* PCI resource allocation */ +- resource = pci_resource_start(pdev, 1); +- len = pci_resource_len(pdev, 1); ++ resource = pci_resource_start(pdev, dev->bar); ++ len = pci_resource_len(pdev, dev->bar); + + if (!request_mem_region(resource, len, KBUILD_MODNAME)) { + dev_err(&pdev->dev, "%s: pci device used already\n", __func__); +@@ -3213,6 +3244,12 @@ static int pch_udc_probe(struct pci_dev *pdev, + retval = -ENODEV; + goto finished; + } ++ ++ pci_set_master(pdev); ++ if (enable_msi == 1){ ++ pci_enable_msi(pdev); ++ } ++ + if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, + dev)) { + dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, +@@ -3223,7 +3260,7 @@ static int pch_udc_probe(struct pci_dev *pdev, + dev->irq = pdev->irq; + dev->irq_registered = 1; + +- pci_set_master(pdev); ++ + pci_try_set_mwi(pdev); + + /* device struct setup */ +@@ -3261,6 +3298,11 @@ finished: + + static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { + { ++ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QUARK_UDC), ++ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, ++ .class_mask = 0xffffffff, ++ }, ++ { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC), + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, + .class_mask = 0xffffffff, +diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c +index 44752f5..e02a4c9 100644 +--- a/drivers/usb/gadget/serial.c ++++ b/drivers/usb/gadget/serial.c +@@ -127,6 +127,15 @@ static unsigned n_ports = 1; + module_param(n_ports, uint, 0); + MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); + ++static __u16 vendor = GS_VENDOR_ID; ++module_param(vendor, ushort, 0); ++MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" ++ __MODULE_STRING(GS_VENDOR_ID)")"); ++ ++static __u16 product = 0; ++module_param(product, ushort, 0); ++MODULE_PARM_DESC(product, "User specified product ID"); ++ + /*-------------------------------------------------------------------------*/ + + static int __init serial_bind_config(struct usb_configuration *c) +@@ -172,6 +181,14 @@ static int __init gs_bind(struct usb_composite_dev *cdev) + status = strings_dev[STRING_DESCRIPTION_IDX].id; + serial_config_driver.iConfiguration = status; + ++ /* Allow command line over-ride to set specific vendor/device id */ ++ if (vendor != GS_VENDOR_ID) ++ device_desc.idVendor = cpu_to_le16(vendor); ++ if (product != 0) ++ device_desc.idProduct = cpu_to_le16(product); ++ pr_info("g_serial: Vendor 0x%04x Product 0x%04x\n", ++ device_desc.idVendor, device_desc.idProduct); ++ + if (gadget_is_otg(cdev->gadget)) { + serial_config_driver.descriptors = otg_desc; + serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +@@ -201,6 +218,7 @@ static __refdata struct usb_composite_driver gserial_driver = { + .bind = gs_bind, + }; + ++static int bCfgVal; + static int __init init(void) + { + /* We *could* export two configs; that'd be much cleaner... +@@ -208,19 +226,19 @@ static int __init init(void) + */ + if (use_acm) { + serial_config_driver.label = "CDC ACM config"; +- serial_config_driver.bConfigurationValue = 2; ++ serial_config_driver.bConfigurationValue = ++bCfgVal; + device_desc.bDeviceClass = USB_CLASS_COMM; + device_desc.idProduct = + cpu_to_le16(GS_CDC_PRODUCT_ID); + } else if (use_obex) { + serial_config_driver.label = "CDC OBEX config"; +- serial_config_driver.bConfigurationValue = 3; ++ serial_config_driver.bConfigurationValue = ++bCfgVal; + device_desc.bDeviceClass = USB_CLASS_COMM; + device_desc.idProduct = + cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID); + } else { + serial_config_driver.label = "Generic Serial config"; +- serial_config_driver.bConfigurationValue = 1; ++ serial_config_driver.bConfigurationValue = ++bCfgVal; + device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; + device_desc.idProduct = + cpu_to_le16(GS_PRODUCT_ID); +-- +1.7.4.1 + |