usb: support rk3368 OTG device side and EHCI
This commit is contained in:
parent
522b75a51d
commit
d2f97737dd
8 changed files with 641 additions and 32 deletions
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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 = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
|
||||
/*
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rockchip/cru.h>
|
||||
#include <linux/rockchip/grf.h>
|
||||
#include <linux/rockchip/cpu.h>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
516
drivers/usb/dwc_otg_310/usbdev_rk3368.c
Normal file
516
drivers/usb/dwc_otg_310/usbdev_rk3368.c
Normal file
|
|
@ -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");
|
||||
|
|
@ -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,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue