USB: add otg irq detect function and chip id detect function

This commit is contained in:
wlf
2014-03-05 09:40:45 +08:00
parent 1ab191c614
commit 88ac83bca1
3 changed files with 238 additions and 63 deletions

View File

@@ -584,7 +584,7 @@
};
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>,
@@ -595,6 +595,8 @@
"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";

View File

@@ -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

View File

@@ -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,16 +393,202 @@ 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
#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)
{
int ret = 0;
int irq = 0;
unsigned int * phy_con0;
#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
}
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
}
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);
return ret;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC0_BASE");
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);
return ret;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC1_BASE");
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);
return ret;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC2_BASE");
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);
return ret;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC3_BASE");
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)
{
struct resource *res;
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) {
@@ -399,6 +597,8 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
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");
@@ -408,43 +608,9 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev)
control_usb->hclk_usb_peri = hclk_usb_peri;
clk_prepare_enable(hclk_usb_peri);
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;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC0_BASE");
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;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC1_BASE");
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;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC2_BASE");
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;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"GRF_UOC3_BASE");
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);
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)