From d2f97737dd28afb428e12df600883cfadef801db Mon Sep 17 00:00:00 2001 From: lyz Date: Mon, 15 Dec 2014 20:45:51 +0800 Subject: [PATCH] usb: support rk3368 OTG device side and EHCI --- arch/arm64/boot/dts/rk3368-tb_8846.dts | 18 +- arch/arm64/boot/dts/rk3368.dtsi | 77 ++++ drivers/usb/dwc_otg_310/Makefile | 2 +- drivers/usb/dwc_otg_310/dwc_otg_driver.c | 38 +- drivers/usb/dwc_otg_310/usbdev_rk.h | 7 + drivers/usb/dwc_otg_310/usbdev_rk3368.c | 516 +++++++++++++++++++++++ drivers/usb/host/ehci-rockchip.c | 4 + drivers/usb/host/ohci-rockchip.c | 11 +- 8 files changed, 641 insertions(+), 32 deletions(-) create mode 100644 drivers/usb/dwc_otg_310/usbdev_rk3368.c diff --git a/arch/arm64/boot/dts/rk3368-tb_8846.dts b/arch/arm64/boot/dts/rk3368-tb_8846.dts index 31c3cdb872e4..05fae8ba4bf1 100644 --- a/arch/arm64/boot/dts/rk3368-tb_8846.dts +++ b/arch/arm64/boot/dts/rk3368-tb_8846.dts @@ -186,16 +186,6 @@ }; }; - usb_control { - compatible = "rockchip,rk3288-usb-control"; - - host_drv_gpio = <&gpio0 GPIO_A4 GPIO_ACTIVE_LOW>; - otg_drv_gpio = <&gpio0 GPIO_D1 GPIO_ACTIVE_LOW>; - - rockchip,remote_wakeup; - rockchip,usb_irq_wakeup; - }; - io-domains { compatible = "rockchip,rk3368-io-voltage-domain"; rockchip,grf = <&grf>; @@ -748,6 +738,14 @@ status="disabled"; }; +&dwc_control_usb { + host_drv_gpio = <&gpio0 GPIO_A4 GPIO_ACTIVE_LOW>; + otg_drv_gpio = <&gpio0 GPIO_D1 GPIO_ACTIVE_LOW>; + + rockchip,remote_wakeup; + rockchip,usb_irq_wakeup; + }; + /include/ "../../../arm/boot/dts/act8846.dtsi" &act8846 { gpios =<&gpio0 GPIO_A0 GPIO_ACTIVE_LOW>,<&gpio0 GPIO_A3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rk3368.dtsi b/arch/arm64/boot/dts/rk3368.dtsi index 77dd88ae5347..bcb539fe55f5 100755 --- a/arch/arm64/boot/dts/rk3368.dtsi +++ b/arch/arm64/boot/dts/rk3368.dtsi @@ -1175,6 +1175,83 @@ clock-names = "clk_crypto", "sclk_crypto", "mclk_crypto"; status = "okay"; }; + dwc_control_usb: dwc-control-usb { + compatible = "rockchip,rk3368-dwc-control-usb"; + rockchip,grf = <&grf>; + interrupts = , , + , ; + interrupt-names = "otg_id", "otg_bvalid", + "otg_linestate", "host0_linestate"; + clocks = <&clk_gates20 6>, <&usbphy_480m>; + clock-names = "hclk_usb_peri", "usbphy_480m"; + //resets = <&reset RK3128_RST_USBPOR>; + //reset-names = "usbphy_por"; + usb_bc{ + compatible = "inno,phy"; + regbase = &dwc_control_usb; + rk_usb,bvalid = <0x04b 23 1>; + rk_usb,iddig = <0x04b 26 1>; + rk_usb,vdmsrcen = <0x718 12 1>; + rk_usb,vdpsrcen = <0x718 11 1>; + rk_usb,rdmpden = <0x718 10 1>; + rk_usb,idpsrcen = <0x718 9 1>; + rk_usb,idmsinken = <0x718 8 1>; + rk_usb,idpsinken = <0x718 7 1>; + rk_usb,dpattach = <0x4b8 31 1>; + rk_usb,cpdet = <0x4b8 30 1>; + rk_usb,dcpattach = <0x4b8 29 1>; + }; + }; + + usb0: usb@ff580000 { + compatible = "rockchip,rk3368_usb20_otg"; + reg = <0x0 0xff580000 0x0 0x40000>; + interrupts = ; + clocks = <&clk_gates8 1>, <&clk_gates20 1>; + clock-names = "clk_usbphy0", "hclk_otg"; + resets = <&reset RK3368_SRST_USBOTG0_H>, <&reset RK3368_SRST_USBOTGPHY0>, + <&reset RK3368_SRST_USBOTGC0>; + reset-names = "otg_ahb", "otg_phy", "otg_controller"; + /*0 - Normal, 1 - Force Host, 2 - Force Device*/ + rockchip,usb-mode = <0>; + }; + + usb_ehci: usb@ff500000 { + compatible = "generic-ehci"; + reg = <0x0 0xff500000 0x0 0x20000>; + interrupts = ; + clocks = <&clk_gates8 1>, <&clk_gates20 3>; + clock-names = "clk_usbphy0", "hclk_ehci"; + //resets = <&reset RK3288_SOFT_RST_USBHOST0_H>, <&reset RK3288_SOFT_RST_USBHOST0PHY>, + // <&reset RK3288_SOFT_RST_USBHOST0C>, <&reset RK3288_SOFT_RST_USB_HOST0>; + //reset-names = "ehci_ahb", "ehci_phy", "ehci_controller", "ehci"; + }; + + usb_ohci: usb@ff520000 { + compatible = "generic-ohci"; + reg = <0x0 0xff520000 0x0 0x20000>; + interrupts = ; + clocks = <&clk_gates8 1>, <&clk_gates20 3>; + clock-names = "clk_usbphy0", "hclk_ohci"; + }; + + usb_hsic: usb@ff5c0000 { + compatible = "rockchip,rk3288_rk_hsic_host"; + reg = <0x0 0xff5c0000 0x0 0x40000>; + interrupts = ; +/* + clocks = <&hsicphy_480m>, <&clk_gates7 8>, + <&hsicphy_12m>, <&usbphy_480m>, + <&otgphy1_480m>, <&otgphy2_480m>; + clock-names = "hsicphy_480m", "hclk_hsic", + "hsicphy_12m", "usbphy_480m", + "hsic_usbphy1", "hsic_usbphy2"; + resets = <&reset RK3288_SOFT_RST_HSIC>, <&reset RK3288_SOFT_RST_HSIC_AUX>, + <&reset RK3288_SOFT_RST_HSICPHY>; + reset-names = "hsic_ahb", "hsic_aux", "hsic_phy"; +*/ + status = "disabled"; + }; pinctrl: pinctrl { compatible = "rockchip,rk3368-pinctrl"; diff --git a/drivers/usb/dwc_otg_310/Makefile b/drivers/usb/dwc_otg_310/Makefile index b1656829613b..a7fd8784976b 100755 --- a/drivers/usb/dwc_otg_310/Makefile +++ b/drivers/usb/dwc_otg_310/Makefile @@ -25,5 +25,5 @@ endif dwc_otg-objs += common_port/dwc_common_linux.o #objs relative to RK platform -dwc_otg-objs += usbdev_rk30.o usbdev_rk32.o usbdev_rk3036.o usbdev_rk3126.o usbdev_bc.o +dwc_otg-objs += usbdev_rk30.o usbdev_rk32.o usbdev_rk3036.o usbdev_rk3126.o usbdev_rk3368.o usbdev_bc.o obj-$(CONFIG_DWC_OTG_310) := dwc_otg.o diff --git a/drivers/usb/dwc_otg_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c index cbd3f364e37c..d90be6d841d1 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -959,15 +959,13 @@ static int host20_driver_probe(struct platform_device *_dev) of_match_device(of_match_ptr(usb20_host_of_match), &_dev->dev); if (match && match->data) { - dev->platform_data = (void *)match->data; + pldata = (void *)match->data; + pldata->dev = dev; } else { - dev_err(dev, "usb20host match failed\n"); + dev_err(dev, "usb20otg match failed\n"); return -EINVAL; } - pldata = dev->platform_data; - pldata->dev = dev; - if (!node) { dev_err(dev, "device node not found\n"); return -EINVAL; @@ -1012,8 +1010,7 @@ static int host20_driver_probe(struct platform_device *_dev) retval = -ENOMEM; goto clk_disable; } - dev_dbg(&_dev->dev, "base=0x%08x\n", - (unsigned)dwc_otg_device->os_dep.base); + dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base); /* Set device flags indicating whether the HCD supports DMA. */ if (!_dev->dev.dma_mask) @@ -1156,18 +1153,18 @@ static int dwc_otg_driver_resume(struct platform_device *_dev) static void dwc_otg_driver_shutdown(struct platform_device *_dev) { struct device *dev = &_dev->dev; - struct dwc_otg_platform_data *pldata = dev->platform_data; dwc_otg_device_t *otg_dev = dev->platform_data; dwc_otg_core_if_t *core_if = otg_dev->core_if; + struct dwc_otg_platform_data *pldata = otg_dev->pldata; dctl_data_t dctl = {.d32 = 0 }; DWC_PRINTF("%s: disconnect USB %s mode\n", __func__, dwc_otg_is_host_mode(core_if) ? "host" : "device"); - if( pldata->dwc_otg_uart_mode != NULL) - pldata->dwc_otg_uart_mode( pldata, PHY_USB_MODE); - if(pldata->phy_suspend != NULL) - pldata->phy_suspend(pldata, USB_PHY_ENABLED); + if (pldata->dwc_otg_uart_mode != NULL) + pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE); + if (pldata->phy_suspend != NULL) + pldata->phy_suspend(pldata, USB_PHY_ENABLED); if (dwc_otg_is_host_mode(core_if)) { if (core_if->hcd_cb && core_if->hcd_cb->stop) core_if->hcd_cb->stop(core_if->hcd_cb_p); @@ -1303,6 +1300,10 @@ static const struct of_device_id usb20_otg_of_match[] = { .compatible = "rockchip,rk3126_usb20_otg", .data = &usb20otg_pdata_rk3126, }, + { + .compatible = "rockchip,rk3368_usb20_otg", + .data = &usb20otg_pdata_rk3368, + }, { }, }; @@ -1332,21 +1333,19 @@ static int otg20_driver_probe(struct platform_device *_dev) const struct of_device_id *match = of_match_device(of_match_ptr(usb20_otg_of_match), &_dev->dev); - if (match) { - dev->platform_data = (void *)match->data; + if (match && match->data) { + pldata = (void *)match->data; + pldata->dev = dev; } else { dev_err(dev, "usb20otg match failed\n"); return -EINVAL; } - pldata = dev->platform_data; - pldata->dev = dev; - if (!node) { dev_err(dev, "device node not found\n"); return -EINVAL; } - /*todo : move to usbdev_rk-XX.c */ + if (pldata->hw_init) pldata->hw_init(); @@ -1395,8 +1394,7 @@ static int otg20_driver_probe(struct platform_device *_dev) retval = -ENOMEM; goto clk_disable; } - dev_dbg(&_dev->dev, "base=0x%08x\n", - (unsigned)dwc_otg_device->os_dep.base); + dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base); /* Set device flags indicating whether the HCD supports DMA. */ if (!_dev->dev.dma_mask) diff --git a/drivers/usb/dwc_otg_310/usbdev_rk.h b/drivers/usb/dwc_otg_310/usbdev_rk.h index 16ef6d78c54b..bed18c605e88 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk.h +++ b/drivers/usb/dwc_otg_310/usbdev_rk.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -71,6 +73,10 @@ extern struct dwc_otg_platform_data usb20otg_pdata_rk3126; extern struct dwc_otg_platform_data usb20host_pdata_rk3126; extern struct dwc_otg_platform_data usb20ohci_pdata_rk3126; extern struct rkehci_platform_data usb20ehci_pdata_rk3126; +/* rk3368 platform data */ +extern struct rkehci_platform_data usb20ehci_pdata_rk3368; +extern struct dwc_otg_platform_data usb20ohci_pdata_rk3368; +extern struct dwc_otg_platform_data usb20otg_pdata_rk3368; struct dwc_otg_platform_data { void *privdata; @@ -120,6 +126,7 @@ struct dwc_otg_control_usb { pGRF_SOC_STATUS19_RK3288 grf_soc_status19_rk3288; pGRF_SOC_STATUS21_RK3288 grf_soc_status21_rk3288; + struct regmap *grf; struct gpio *host_gpios; struct gpio *otg_gpios; struct clk *hclk_usb_peri; diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3368.c b/drivers/usb/dwc_otg_310/usbdev_rk3368.c new file mode 100644 index 000000000000..8be87337097a --- /dev/null +++ b/drivers/usb/dwc_otg_310/usbdev_rk3368.c @@ -0,0 +1,516 @@ +#include "usbdev_rk.h" +#include "usbdev_grf_regs.h" +#include "dwc_otg_regs.h" +static struct dwc_otg_control_usb *control_usb; + +static u32 uoc_read(u32 reg) +{ + unsigned int val; + + regmap_read(control_usb->grf, reg, &val); + return val; +} + +static void uoc_write(u32 value, u32 reg) +{ + regmap_write(control_usb->grf, reg, value); +} + +#ifdef CONFIG_USB20_OTG +static void usb20otg_hw_init(void) +{ + /* Turn off differential receiver in suspend mode */ + uoc_write(UOC_HIWORD_UPDATE(0, 1, 2), 0x798); + + /* other haredware init,include: + * DRV_VBUS GPIO init */ + if (gpio_is_valid(control_usb->otg_gpios->gpio)) + gpio_set_value(control_usb->otg_gpios->gpio, 0); +} + +static void usb20otg_phy_suspend(void *pdata, int suspend) +{ + struct dwc_otg_platform_data *usbpdata = pdata; + + if (suspend) { + /* enable soft control */ + uoc_write(UOC_HIWORD_UPDATE(0x55, 0x7f, 0), 0x700); + usbpdata->phy_status = 1; + } else { + /* exit suspend */ + uoc_write(UOC_HIWORD_UPDATE(0x0, 0x1, 0), 0x700); + usbpdata->phy_status = 0; + } +} + +static void usb20otg_soft_reset(void *pdata, enum rkusb_rst_flag rst_type) +{ + struct dwc_otg_platform_data *usbpdata = pdata; + struct reset_control *rst_otg_h, *rst_otg_p, *rst_otg_c; + + rst_otg_h = devm_reset_control_get(usbpdata->dev, "otg_ahb"); + rst_otg_p = devm_reset_control_get(usbpdata->dev, "otg_phy"); + rst_otg_c = devm_reset_control_get(usbpdata->dev, "otg_controller"); + if (IS_ERR(rst_otg_h) || IS_ERR(rst_otg_p) || IS_ERR(rst_otg_c)) { + dev_err(usbpdata->dev, "Fail to get reset control from dts\n"); + return; + } + + switch (rst_type) { + case RST_POR: + /* PHY reset */ + uoc_write(UOC_HIWORD_UPDATE(0x1, 0x3, 0), 0x700); + reset_control_assert(rst_otg_p); + udelay(15); + uoc_write(UOC_HIWORD_UPDATE(0x2, 0x3, 0), 0x700); + udelay(1500); + reset_control_deassert(rst_otg_p); + udelay(2); + + /* Controller reset */ + reset_control_assert(rst_otg_c); + reset_control_assert(rst_otg_h); + + udelay(2); + + reset_control_deassert(rst_otg_c); + reset_control_deassert(rst_otg_h); + break; + + default: + break; + } +} + +static void usb20otg_clock_init(void *pdata) +{ + struct dwc_otg_platform_data *usbpdata = pdata; + struct clk *ahbclk, *phyclk; + + ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg"); + if (IS_ERR(ahbclk)) { + dev_err(usbpdata->dev, "Failed to get hclk_usb0\n"); + return; + } + + phyclk = devm_clk_get(usbpdata->dev, "clk_usbphy0"); + if (IS_ERR(phyclk)) { + dev_err(usbpdata->dev, "Failed to get clk_usbphy0\n"); + return; + } + + usbpdata->phyclk = phyclk; + usbpdata->ahbclk = ahbclk; +} + +static void usb20otg_clock_enable(void *pdata, int enable) +{ + struct dwc_otg_platform_data *usbpdata = pdata; + + if (enable) { + clk_prepare_enable(usbpdata->ahbclk); + clk_prepare_enable(usbpdata->phyclk); + } else { + clk_disable_unprepare(usbpdata->ahbclk); + clk_disable_unprepare(usbpdata->phyclk); + } +} + +static int usb20otg_get_status(int id) +{ + int ret = -1; + u32 soc_status15 = uoc_read(0x4bc); + + switch (id) { + case USB_STATUS_BVABLID: + /* bvalid in grf */ + ret = soc_status15 & (0x1 << 23); + break; + case USB_STATUS_DPDM: + /* dpdm in grf */ + ret = soc_status15 & (0x3 << 24); + break; + case USB_STATUS_ID: + /* id in grf */ + ret = soc_status15 & (0x1 << 26); + break; + case USB_CHIP_ID: + ret = control_usb->chip_id; + break; + case USB_REMOTE_WAKEUP: + ret = control_usb->remote_wakeup; + break; + case USB_IRQ_WAKEUP: + ret = control_usb->usb_irq_wakeup; + break; + default: + break; + } + return ret; +} + +#ifdef CONFIG_RK_USB_UART +/** + * dwc_otg_uart_enabled - check if a usb-uart bypass func is enabled in DT + * + * Returns true if the status property of node "usb_uart" is set to "okay" + * or "ok", if this property is absent it will use the default status "ok" + * 0 otherwise + */ +static bool dwc_otg_uart_enabled(void) +{ + return false; +} + +static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) +{ +} +#else +static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) +{ +} +#endif + +static void usb20otg_power_enable(int enable) +{ + if (0 == enable) { + /* disable otg_drv power */ + if (gpio_is_valid(control_usb->otg_gpios->gpio)) + gpio_set_value(control_usb->otg_gpios->gpio, 0); + } else if (1 == enable) { + /* enable otg_drv power */ + if (gpio_is_valid(control_usb->otg_gpios->gpio)) + gpio_set_value(control_usb->otg_gpios->gpio, 1); + } +} + +struct dwc_otg_platform_data usb20otg_pdata_rk3368 = { + .phyclk = NULL, + .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, + .dwc_otg_uart_mode = dwc_otg_uart_mode, + /* .bc_detect_cb = rk_battery_charger_detect_cb, */ +}; +#endif + +#ifdef CONFIG_USB_EHCI_RK +static void usb20ehci_hw_init(void) +{ + /* Turn off differential receiver in suspend mode */ + uoc_write(UOC_HIWORD_UPDATE(0, 1, 2), 0x7b8); + /* Set disconnect detection trigger point to 600mv */ + uoc_write(UOC_HIWORD_UPDATE(1, 0xf, 11), 0x7bc); + + /* other haredware init,include: + * DRV_VBUS GPIO init */ + if (gpio_is_valid(control_usb->host_gpios->gpio)) { + if (!gpio_get_value(control_usb->host_gpios->gpio)) + gpio_set_value(control_usb->host_gpios->gpio, 1); + } +} + +static void usb20ehci_phy_suspend(void *pdata, int suspend) +{ + struct rkehci_platform_data *usbpdata = pdata; + + if (suspend) { + /* enable soft control */ + uoc_write(UOC_HIWORD_UPDATE(0x1d5, 0x1ff, 0), 0x728); + usbpdata->phy_status = 1; + } else { + /* exit suspend */ + uoc_write(UOC_HIWORD_UPDATE(0x0, 0x1, 0), 0x728); + usbpdata->phy_status = 0; + } +} + +static void usb20ehci_soft_reset(void *pdata, enum rkusb_rst_flag rst_type) +{ + struct rkehci_platform_data *usbpdata = pdata; + struct reset_control *rst_host_h, *rst_host_p, *rst_host_c; + + rst_host_h = devm_reset_control_get(usbpdata->dev, "host_ahb"); + rst_host_p = devm_reset_control_get(usbpdata->dev, "host_phy"); + rst_host_c = devm_reset_control_get(usbpdata->dev, "host_controller"); + if (IS_ERR(rst_host_h) || IS_ERR(rst_host_p) || IS_ERR(rst_host_c)) { + dev_err(usbpdata->dev, "Fail to get reset control from dts\n"); + return; + } + + switch (rst_type) { + case RST_POR: + /* PHY reset */ + uoc_write(UOC_HIWORD_UPDATE(0x1, 0x3, 0), 0x728); + reset_control_assert(rst_host_p); + udelay(15); + uoc_write(UOC_HIWORD_UPDATE(0x2, 0x3, 0), 0x728); + + udelay(1500); + reset_control_deassert(rst_host_p); + + /* Controller reset */ + reset_control_assert(rst_host_c); + reset_control_assert(rst_host_h); + + udelay(5); + + reset_control_deassert(rst_host_c); + reset_control_deassert(rst_host_h); + break; + + default: + break; + } +} + +static void usb20ehci_clock_init(void *pdata) +{ +} + +static void usb20ehci_clock_enable(void *pdata, int enable) +{ +} + +static int usb20ehci_get_status(int id) +{ + /* For HOST port in rk336x can not get any info from GRF */ + return -ENOENT; +} + +struct rkehci_platform_data usb20ehci_pdata_rk3368 = { + .phyclk = NULL, + .ahbclk = NULL, + .phy_status = 0, + .hw_init = usb20ehci_hw_init, + .phy_suspend = usb20ehci_phy_suspend, + .soft_reset = usb20ehci_soft_reset, + .clock_init = usb20ehci_clock_init, + .clock_enable = usb20ehci_clock_enable, + .get_status = usb20ehci_get_status, +}; +#endif + +struct dwc_otg_platform_data usb20ohci_pdata_rk3368; + +#ifdef CONFIG_OF +static const struct of_device_id rk_usb_control_id_table[] = { + { + .compatible = "rockchip,rk3368-usb-control", + }, + {}, +}; +#endif +/********************************************************************* + rk3126 usb detections +*********************************************************************/ + +#define WAKE_LOCK_TIMEOUT (HZ * 10) +static inline void do_wakeup(struct work_struct *work) +{ + /* wake up the system */ + rk_send_wakeup_key(); +} + +static void usb_battery_charger_detect_work(struct work_struct *work) +{ + /* rk_battery_charger_detect_cb(usb_battery_charger_detect(1)); */ +} + +/********** handler for bvalid irq **********/ +static irqreturn_t bvalid_irq_handler(int irq, void *dev_id) +{ + /* clear irq */ + uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x690); +#ifdef CONFIG_RK_USB_UART + /* usb otg dp/dm switch to usb phy */ + dwc_otg_uart_mode(NULL, PHY_USB_MODE); +#endif + + if (control_usb->usb_irq_wakeup) { + wake_lock_timeout(&control_usb->usb_wakelock, + WAKE_LOCK_TIMEOUT); + schedule_delayed_work(&control_usb->usb_det_wakeup_work, + HZ / 10); + } + + schedule_delayed_work(&control_usb->usb_charger_det_work, HZ / 10); + + return IRQ_HANDLED; +} + +/************* register usb detection irqs **************/ +static int otg_irq_detect_init(struct platform_device *pdev) +{ + int ret = 0; + int irq = 0; + + wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND, + "usb_detect"); + INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup); +#if 0 + /*register otg_bvalid irq */ + irq = platform_get_irq_byname(pdev, "otg_bvalid"); + if ((irq > 0) && control_usb->usb_irq_wakeup) { + ret = request_irq(irq, bvalid_irq_handler, + 0, "otg_bvalid", NULL); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq %d failed!\n", irq); + } else { + /* enable bvalid irq */ + uoc_write(UOC_HIWORD_UPDATE(0x1, 0x1, 3), 0x680); + } + } +#endif + return 0; +} + +/********** end of usb detections **********/ +#ifdef CONFIG_OF +static const struct of_device_id dwc_otg_control_usb_id_table[] = { + { + .compatible = "rockchip,rk3368-dwc-control-usb", + }, + {}, +}; +#endif +static int dwc_otg_control_usb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct clk *hclk_usb_peri; + struct regmap *grf; + int gpio, ret = 0; + + control_usb = devm_kzalloc(dev, sizeof(*control_usb), GFP_KERNEL); + if (!control_usb) { + dev_err(&pdev->dev, "Unable to alloc memory for control usb\n"); + return -ENOMEM; + } + + /* Init regmap GRF */ + grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, "Missing rockchip,grf property\n"); + return PTR_ERR(grf); + } + control_usb->grf = grf; + + /* Init Vbus-drv GPIOs */ + control_usb->host_gpios = + devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL); + if (!control_usb->host_gpios) { + dev_err(&pdev->dev, "Unable to alloc memory for host_gpios\n"); + return -ENOMEM; + } + + gpio = of_get_named_gpio(np, "host_drv_gpio", 0); + control_usb->host_gpios->gpio = gpio; + + if (gpio_is_valid(gpio)) { + if (devm_gpio_request(&pdev->dev, gpio, "usb_host_drv")) { + dev_err(&pdev->dev, + "Failed to request GPIO%d for host_drv\n", + gpio); + return -EINVAL; + } + gpio_direction_output(control_usb->host_gpios->gpio, 1); + } + + control_usb->otg_gpios = + devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL); + if (!control_usb->otg_gpios) { + dev_err(&pdev->dev, "Unable to alloc memory for otg_gpios\n"); + return -ENOMEM; + } + + gpio = of_get_named_gpio(np, "otg_drv_gpio", 0); + control_usb->otg_gpios->gpio = gpio; + + if (gpio_is_valid(gpio)) { + if (devm_gpio_request(&pdev->dev, gpio, "usb_otg_drv")) { + dev_err(&pdev->dev, + "failed to request GPIO%d for otg_drv\n", gpio); + return -EINVAL; + } + gpio_direction_output(control_usb->otg_gpios->gpio, 0); + } + + + control_usb->remote_wakeup = of_property_read_bool(np, + "rockchip,remote_wakeup"); + control_usb->usb_irq_wakeup = of_property_read_bool(np, + "rockchip,usb_irq_wakeup"); + + /* Init hclk_usb_peri */ + 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"); + return PTR_ERR(hclk_usb_peri); + } + control_usb->hclk_usb_peri = hclk_usb_peri; + clk_prepare_enable(hclk_usb_peri); + +#ifdef CONFIG_USB20_OTG + INIT_DELAYED_WORK(&control_usb->usb_charger_det_work, + usb_battery_charger_detect_work); + + if (usb20otg_get_status(USB_STATUS_BVABLID)) + schedule_delayed_work(&control_usb->usb_charger_det_work, + HZ / 10); +#endif + + ret = otg_irq_detect_init(pdev); + if (ret < 0) + goto err; + + return 0; + +err: + clk_disable_unprepare(hclk_usb_peri); + return ret; +} + +static int dwc_otg_control_usb_remove(struct platform_device *pdev) +{ + clk_disable_unprepare(control_usb->hclk_usb_peri); + return 0; +} + +static struct platform_driver dwc_otg_control_usb_driver = { + .probe = dwc_otg_control_usb_probe, + .remove = dwc_otg_control_usb_remove, + .driver = { + .name = "rk3368-dwc-control-usb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table), + }, +}; + +static int __init dwc_otg_control_usb_init(void) +{ + int retval = 0; + + retval |= platform_driver_register(&dwc_otg_control_usb_driver); + return retval; +} + +subsys_initcall(dwc_otg_control_usb_init); + +static void __exit dwc_otg_control_usb_exit(void) +{ + platform_driver_unregister(&dwc_otg_control_usb_driver); +} + +module_exit(dwc_otg_control_usb_exit); +MODULE_ALIAS("platform: dwc_control_usb"); +MODULE_AUTHOR("RockChip Inc."); +MODULE_DESCRIPTION("RockChip Control Module USB Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-rockchip.c b/drivers/usb/host/ehci-rockchip.c index 874f8008150e..022d1deb1465 100755 --- a/drivers/usb/host/ehci-rockchip.c +++ b/drivers/usb/host/ehci-rockchip.c @@ -253,6 +253,10 @@ static struct of_device_id rk_ehci_of_match[] = { .compatible = "rockchip,rk3126_ehci", .data = &usb20ehci_pdata_rk3126, }, + { + .compatible = "rockchip,rk3368_ehci", + .data = &usb20ehci_pdata_rk3368, + }, {}, }; diff --git a/drivers/usb/host/ohci-rockchip.c b/drivers/usb/host/ohci-rockchip.c index 1bc765978823..4ea543284463 100755 --- a/drivers/usb/host/ohci-rockchip.c +++ b/drivers/usb/host/ohci-rockchip.c @@ -93,6 +93,10 @@ static struct of_device_id rk_ohci_of_match[] = { .compatible = "rockchip,rk3126_ohci", .data = &usb20ohci_pdata_rk3126, }, + { + .compatible = "rockchip,rk3368_ohci", + .data = &usb20ohci_pdata_rk3368, + }, {}, }; @@ -120,7 +124,7 @@ static int ohci_hcd_rk_probe(struct platform_device *pdev) return -ENODEV; match = of_match_device(of_match_ptr(rk_ohci_of_match), &pdev->dev); - if (match) { + if (match && match->data) { pldata = (struct dwc_otg_platform_data *)match->data; } else { dev_err(dev, "ohci_rk match failed\n"); @@ -145,6 +149,11 @@ static int ohci_hcd_rk_probe(struct platform_device *pdev) goto clk_disable; } + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "UHH OHCI get resource failed\n"); -- 2.34.1