USB: add otg irq detect function and chip id detect function
authorwlf <wulf@rock-chips.com>
Wed, 5 Mar 2014 01:40:45 +0000 (09:40 +0800)
committerwlf <wulf@rock-chips.com>
Wed, 5 Mar 2014 01:40:45 +0000 (09:40 +0800)
arch/arm/boot/dts/rk3188.dtsi
drivers/usb/dwc_otg_310/usbdev_rk.h
drivers/usb/dwc_otg_310/usbdev_rk30.c

index 06dca7ce4dfccf65aaf5cefdd7f0a8d9c43deae2..b1cb283fc93ab2a29d61b7c97851ac525e77549c 100755 (executable)
        };
 
        dwc_control_usb: dwc-control-usb@0x200080ac {
-               compatible = "rockchip,dwc-control-usb";
+               compatible = "rockchip,rk3188-dwc-control-usb";
                reg = <0x200080ac 0x4>,
                      <0x2000810c 0x10>,
                      <0x2000811c 0x10>,
                            "GRF_UOC1_BASE",
                            "GRF_UOC2_BASE",
                            "GRF_UOC3_BASE";
+               interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "bvalid";
                gpios = <&gpio0 GPIO_C0 GPIO_ACTIVE_LOW>, <&gpio3 GPIO_D5 GPIO_ACTIVE_LOW>;
                clocks = <&clk_gates4 5>;
                clock-names = "hclk_usb_peri";
index cdc49c339b7c9fb5f9460ab64c42f33627c1f6b5..207654a83a218b9cf3f084d23fc10f7a86221d60 100755 (executable)
@@ -27,6 +27,7 @@ struct dwc_otg_platform_data {
     void (*power_enable)(int enable);
     void (*dwc_otg_uart_mode)(void* pdata, int enter_usb_uart_mode);
     int (*get_status)(int id);
+    int (*get_chip_id)(void);
 };
 
 struct rkehci_platform_data{
@@ -38,6 +39,7 @@ struct rkehci_platform_data{
        void (*clock_init)(void* pdata);
        void (*clock_enable)(void *pdata, int enable);
        void (*soft_reset)(void);
+       int (*get_chip_id)(void);
        int clk_status;
 };
 
@@ -50,6 +52,14 @@ struct dwc_otg_control_usb {
        struct gpio *host_gpios;
        struct gpio *otg_gpios;
        struct clk* hclk_usb_peri;
+       struct delayed_work usb_det_wakeup_work;
+       struct wake_lock usb_wakelock;
+       int chip_id;
+};
+
+enum {
+       RK3188_USB_CTLR = 0,    /* rk3188 chip usb */
+       RK3288_USB_CTLR,        /* rk3288 chip usb */
 };
 
 #endif
index 447a723eb9c9f1c7c5a22e1353e7f0267f458a3b..183ff92250963f95a2956a0cb3e8e2dbde9055d0 100755 (executable)
@@ -9,12 +9,22 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/gpio.h>
+#include <linux/wakelock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include "usbdev_rk.h"
 #include "dwc_otg_regs.h"
 
 static struct dwc_otg_control_usb *control_usb;
 
+int usb_get_chip_id(void)
+{
+       return control_usb->chip_id;
+}
+
 int dwc_otg_check_dpdm(void)
 {
        int bus_status = 0;
@@ -155,15 +165,16 @@ struct dwc_otg_platform_data usb20otg_pdata = {
        .ahbclk = NULL,
        .busclk = NULL,
        .phy_status = 0,
-       .hw_init=usb20otg_hw_init,
-       .phy_suspend=usb20otg_phy_suspend,
-       .soft_reset=usb20otg_soft_reset,
-       .clock_init=usb20otg_clock_init,
-       .clock_enable=usb20otg_clock_enable,
-       .get_status=usb20otg_get_status,
-       .power_enable=usb20otg_power_enable,
+       .hw_init = usb20otg_hw_init,
+       .phy_suspend = usb20otg_phy_suspend,
+       .soft_reset = usb20otg_soft_reset,
+       .clock_init = usb20otg_clock_init,
+       .clock_enable = usb20otg_clock_enable,
+       .get_status = usb20otg_get_status,
+       .get_chip_id = usb_get_chip_id,
+       .power_enable = usb20otg_power_enable,
 #ifdef CONFIG_RK_USB_UART
-       .dwc_otg_uart_mode=dwc_otg_uart_mode,
+       .dwc_otg_uart_mode = dwc_otg_uart_mode,
 #endif
 };
 
@@ -273,13 +284,14 @@ struct dwc_otg_platform_data usb20host_pdata = {
        .ahbclk = NULL,
        .busclk = NULL,
        .phy_status = 0,
-       .hw_init=usb20host_hw_init,
-       .phy_suspend=usb20host_phy_suspend,
-       .soft_reset=usb20host_soft_reset,
-       .clock_init=usb20host_clock_init,
-       .clock_enable=usb20host_clock_enable,
-       .get_status=usb20host_get_status,
-       .power_enable=usb20host_power_enable,
+       .hw_init = usb20host_hw_init,
+       .phy_suspend = usb20host_phy_suspend,
+       .soft_reset = usb20host_soft_reset,
+       .clock_init = usb20host_clock_init,
+       .clock_enable = usb20host_clock_enable,
+       .get_status = usb20host_get_status,
+       .get_chip_id = usb_get_chip_id,
+       .power_enable = usb20host_power_enable,
 };
 #endif
 
@@ -381,39 +393,123 @@ struct rkehci_platform_data rkhsic_pdata = {
        .clock_init = rk_hsic_clock_init,
        .clock_enable = rk_hsic_clock_enable,
        .soft_reset = rk_hsic_soft_reset,
+       .get_chip_id = usb_get_chip_id,
 };
 #endif
 
-static int dwc_otg_control_usb_probe(struct platform_device *pdev)
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+#define WAKE_LOCK_TIMEOUT (HZ * 10)
+
+inline static void do_wakeup(struct work_struct *work)
+{
+//     rk28_send_wakeup_key();
+}
+#endif
+
+/********** handler for bvalid irq **********/
+static irqreturn_t bvalid_irq_handler(int irq, void *dev_id)
+{
+       unsigned int * phy_con0;
+
+       /* clear irq */
+       if( usb_get_chip_id() == RK3188_USB_CTLR){
+               phy_con0 = (control_usb->grf_uoc0_base + 0xc);
+               *phy_con0 = (1 << 31) | (1 << 15);
+       }
+
+#ifdef CONFIG_RK_USB_UART
+       /* usb otg dp/dm switch to usb phy */
+       dwc_otg_uart_mode(NULL, PHY_USB_MODE);
+#endif
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+       wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
+       schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+/********** handler for otg id rise and fall edge **********/
+static irqreturn_t id_irq_handler(int irq, void *dev_id)
+{
+       /* clear irq */
+       if( usb_get_chip_id() == RK3288_USB_CTLR){
+
+       }
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+       wake_lock_timeout(&control_usb->usb_wakelock, WAKE_LOCK_TIMEOUT);
+       schedule_delayed_work(&control_usb->usb_det_wakeup_work, HZ/10);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+/************* register bvalid and otg_id irq **************/
+static int otg_irq_detect_init(struct platform_device *pdev)
 {
-       struct resource *res;
-       int gpio, err;
-       struct device_node *np = pdev->dev.of_node;
-       struct clk* hclk_usb_peri;
        int ret = 0;
+       int irq = 0;
+       unsigned int * phy_con0;
 
-       control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
-       if (!control_usb) {
-               dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
-               ret =  -ENOMEM;
-               goto err1;
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+       wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, "usb_detect");
+       INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup);
+#endif
+
+       irq = platform_get_irq_byname(pdev, "bvalid");
+       if (irq > 0) {
+               ret = request_irq(irq, bvalid_irq_handler, 0, "bvalid", NULL);
+               if(ret < 0){
+                       dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
+                       return ret;
+               }
+
+               /* clear & enable bvalid irq */
+               if( usb_get_chip_id() == RK3188_USB_CTLR){
+                       phy_con0 = (control_usb->grf_uoc0_base + 0xc);
+                       *phy_con0 = (3 << 30) | (3 << 14);
+               }
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+               enable_irq_wake(irq);
+#endif
        }
 
-       hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
-       if (IS_ERR(hclk_usb_peri)) {
-               dev_err(&pdev->dev, "Failed to get hclk_usb_peri\n");
-               ret = -EINVAL;
-               goto err1;
+       irq = platform_get_irq_byname(pdev, "otg_id");
+       if (irq > 0) {
+               ret = request_irq(irq, id_irq_handler, 0, "otg_id", NULL);
+               if(ret < 0){
+                       dev_err(&pdev->dev, "request_irq %d failed!\n", irq);
+                       return ret;
+               }
+
+               /* clear & enable otg_id change irq */
+               /* for rk3026 & rk3288 enable and clear id_fall_irq & id_rise_irq*/
+               if( usb_get_chip_id() == RK3288_USB_CTLR){
+
+               }
+
+#ifdef CONFIG_RK_USB_DETECT_BY_OTG_BVALID
+               enable_irq_wake(irq);
+#endif
        }
-       control_usb->hclk_usb_peri = hclk_usb_peri;
-       clk_prepare_enable(hclk_usb_peri);
+
+       return ret;
+}
+
+static int usb_grf_ioremap(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                "GRF_SOC_STATUS0");
        control_usb->grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(control_usb->grf_soc_status0)){
                ret = PTR_ERR(control_usb->grf_soc_status0);
-               goto err2;
+               return ret;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -421,7 +517,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        control_usb->grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(control_usb->grf_uoc0_base)){
                ret = PTR_ERR(control_usb->grf_uoc0_base);
-               goto err2;
+               return ret;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -429,7 +525,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        control_usb->grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(control_usb->grf_uoc1_base)){
                ret = PTR_ERR(control_usb->grf_uoc1_base);
-               goto err2;
+               return ret;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -437,7 +533,7 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        control_usb->grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(control_usb->grf_uoc2_base)){
                ret = PTR_ERR(control_usb->grf_uoc2_base);
-               goto err2;
+               return ret;
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -445,6 +541,76 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
        control_usb->grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(control_usb->grf_uoc3_base)){
                ret = PTR_ERR(control_usb->grf_uoc3_base);
+               return ret;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_OF
+static struct platform_device_id rk_usb_devtype[] = {
+       {
+               .name = "rk3188-usb",
+               .driver_data = RK3188_USB_CTLR,
+       },
+       {
+               .name = "rk3288-usb",
+               .driver_data = RK3288_USB_CTLR,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, rk_usb_devtype);
+
+static const struct of_device_id dwc_otg_control_usb_id_table[] = {
+       {       .compatible = "rockchip,rk3188-dwc-control-usb",
+               .data = &rk_usb_devtype[RK3188_USB_CTLR],
+       },
+       {
+               .compatible = "rockchip,rk3288-dwc-control-usb",
+               .data = &rk_usb_devtype[RK3288_USB_CTLR],
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, dwc_otg_control_usb_id_table);
+#endif
+
+static int dwc_otg_control_usb_probe(struct platform_device *pdev)
+{
+       int gpio, err;
+       struct device_node *np = pdev->dev.of_node;
+       struct clk* hclk_usb_peri;
+       int ret = 0;
+       const struct of_device_id *match =
+               of_match_device(of_match_ptr(dwc_otg_control_usb_id_table), &pdev->dev);
+
+       if (match)
+               pdev->id_entry = match->data;
+       else{
+               ret = -EINVAL;
+               goto err1;
+       }
+
+       control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
+       if (!control_usb) {
+               dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+               ret =  -ENOMEM;
+               goto err1;
+       }
+
+       control_usb->chip_id = pdev->id_entry->driver_data;
+
+       hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
+       if (IS_ERR(hclk_usb_peri)) {
+               dev_err(&pdev->dev, "Failed to get hclk_usb_peri\n");
+               ret = -EINVAL;
+               goto err1;
+       }
+       control_usb->hclk_usb_peri = hclk_usb_peri;
+       clk_prepare_enable(hclk_usb_peri);
+
+       ret = usb_grf_ioremap(pdev);
+       if(ret){
+               dev_err(&pdev->dev, "Failed to ioremap usb grf\n");
                goto err2;
        }
 
@@ -483,7 +649,11 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
                ret = err;
                goto err2;
        }
-
+#if 0 //disable for debug
+       ret = otg_irq_detect_init(pdev);
+       if (ret < 0)
+               goto err2;
+#endif
        return 0;
 
 err2:
@@ -498,14 +668,6 @@ static int dwc_otg_control_usb_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id dwc_otg_control_usb_id_table[] = {
-       { .compatible = "rockchip,dwc-control-usb" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, dwc_otg_control_usb_id_table);
-#endif
-
 static struct platform_driver dwc_otg_control_usb_driver = {
        .probe          = dwc_otg_control_usb_probe,
        .remove         = dwc_otg_control_usb_remove,
@@ -514,6 +676,7 @@ static struct platform_driver dwc_otg_control_usb_driver = {
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
        },
+       .id_table       = rk_usb_devtype,
 };
 
 static int __init dwc_otg_control_usb_init(void)