-
+#ifdef CONFIG_ARM
#include "usbdev_rk.h"
#include "usbdev_grf_regs.h"
#include "dwc_otg_regs.h"
static struct dwc_otg_control_usb *control_usb;
+int is_rk3288_usb(void)
+{
+ if (!control_usb)
+ return false;
+
+ return control_usb->chip_id == RK3288_USB_CTLR ? true : false;
+}
+
#ifdef CONFIG_USB20_OTG
static void usb20otg_hw_init(void)
{
}
}
-static void usb20otg_soft_reset(void)
+static void usb20otg_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
{
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTG_H, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTGPHY, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTGC, true);
- udelay(5);
+ 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;
+ }
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTG_H, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTGPHY, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBOTGC, false);
+ reset_control_assert(rst_otg_h);
+ reset_control_assert(rst_otg_p);
+ reset_control_assert(rst_otg_c);
+ udelay(5);
+ reset_control_deassert(rst_otg_h);
+ reset_control_deassert(rst_otg_p);
+ reset_control_deassert(rst_otg_c);
mdelay(2);
}
}
#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)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_name(NULL, "usb_uart");
+ if (np && of_device_is_available(np))
+ return true;
+
+ return false;
+}
+
static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode)
{
- if (1 == enter_usb_uart_mode) {
+ if ((1 == enter_usb_uart_mode) && dwc_otg_uart_enabled()) {
/* bypass dm, enter uart mode */
control_usb->grf_uoc0_base->CON3 = (0x00c0 | (0x00c0 << 16));
control_usb->grf_uoc0_base->CON3 = (0x00c0 << 16);
}
}
+#else
+static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode)
+{
+}
#endif
static void usb20otg_power_enable(int 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 (usb20otg_get_status(USB_STATUS_BVABLID))
+ rk_battery_charger_detect_cb(USB_OTG_POWER_OFF);
} 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);
+ else if (!usb20otg_get_status(USB_STATUS_BVABLID))
+ rk_battery_charger_detect_cb(USB_OTG_POWER_ON);
}
}
.clock_enable = usb20otg_clock_enable,
.get_status = usb20otg_get_status,
.power_enable = usb20otg_power_enable,
-#ifdef CONFIG_RK_USB_UART
.dwc_otg_uart_mode = dwc_otg_uart_mode,
-#endif
- .bc_detect_cb = usb20otg_battery_charger_detect_cb,
+ .bc_detect_cb = rk_battery_charger_detect_cb,
};
#endif
{
/* usb phy config init
* set common_on = 0, in suspend mode, host1 PLL blocks remain powered.
- * for RK3288, hsic and other modules use host1 (DWC_OTG) 480M phy clk.
+ * for RK3288, ehci1 and other modules use host1 (DWC_OTG) 480M phy clk.
*/
control_usb->grf_uoc2_base->CON0 = (1 << 16) | 0;
}
}
-static void usb20host_soft_reset(void)
+static void usb20host_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
{
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1_H, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1C, true);
- udelay(5);
+ struct dwc_otg_platform_data *usbpdata = pdata;
+ struct reset_control *rst_host1_h, *rst_host1_p, *rst_host1_c;
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1_H, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1C, false);
+ rst_host1_h = devm_reset_control_get(usbpdata->dev, "host1_ahb");
+ rst_host1_p = devm_reset_control_get(usbpdata->dev, "host1_phy");
+ rst_host1_c = devm_reset_control_get(usbpdata->dev, "host1_controller");
+ if (IS_ERR(rst_host1_h) || IS_ERR(rst_host1_p) || IS_ERR(rst_host1_c)) {
+ dev_err(usbpdata->dev, "Fail to get reset control from dts\n");
+ return;
+ }
+
+ reset_control_assert(rst_host1_h);
+ reset_control_assert(rst_host1_p);
+ reset_control_assert(rst_host1_c);
+ udelay(5);
+ reset_control_deassert(rst_host1_h);
+ reset_control_deassert(rst_host1_p);
+ reset_control_deassert(rst_host1_c);
mdelay(2);
}
{
if (0 == enable) {
/* disable host_drv power */
- /* do not disable power in default */
+ if (gpio_is_valid(control_usb->host_gpios->gpio))
+ gpio_set_value(control_usb->host_gpios->gpio, 0);
} else if (1 == enable) {
/* enable host_drv power */
if (gpio_is_valid(control_usb->host_gpios->gpio))
#endif
-#ifdef CONFIG_USB_EHCI_RKHSIC
-static void rk_hsic_hw_init(void)
+#ifdef CONFIG_USB_EHCI1_RK
+static void rk_ehci1_hw_init(void)
{
/* usb phy config init
- * hsic phy config init, set hsicphy_txsrtune */
+ * ehci1 phy config init, set ehci1phy_txsrtune */
control_usb->grf_uoc3_base->CON0 = ((0xf << 6) << 16) | (0xf << 6);
/* other haredware init
control_usb->grf_uoc4_base->CON0 = 0x00ff00bc;
}
-static void rk_hsic_clock_init(void *pdata)
+static void rk_ehci1_clock_init(void *pdata)
{
- /* By default, hsicphy_480m's parent is otg phy 480MHz clk
+ /* By default, ehci1phy_480m's parent is otg phy 480MHz clk
* rk3188 must use host phy 480MHz clk, because if otg bypass
* to uart mode, otg phy 480MHz clk will be closed automatically
*/
struct rkehci_platform_data *usbpdata = pdata;
- struct clk *ahbclk, *phyclk480m_hsic, *phyclk12m_hsic;
+ struct clk *ahbclk, *phyclk480m_ehci1, *phyclk12m_ehci1;
- phyclk480m_hsic = devm_clk_get(usbpdata->dev, "hsicphy_480m");
- if (IS_ERR(phyclk480m_hsic)) {
- dev_err(usbpdata->dev, "Failed to get hsicphy_480m\n");
+ phyclk480m_ehci1 = devm_clk_get(usbpdata->dev, "ehci1phy_480m");
+ if (IS_ERR(phyclk480m_ehci1)) {
+ dev_err(usbpdata->dev, "Failed to get ehci1phy_480m\n");
return;
}
- phyclk12m_hsic = devm_clk_get(usbpdata->dev, "hsicphy_12m");
- if (IS_ERR(phyclk12m_hsic)) {
- dev_err(usbpdata->dev, "Failed to get hsicphy_12m\n");
+ phyclk12m_ehci1 = devm_clk_get(usbpdata->dev, "ehci1phy_12m");
+ if (IS_ERR(phyclk12m_ehci1)) {
+ dev_err(usbpdata->dev, "Failed to get ehci1phy_12m\n");
return;
}
- ahbclk = devm_clk_get(usbpdata->dev, "hclk_hsic");
+ ahbclk = devm_clk_get(usbpdata->dev, "hclk_ehci1");
if (IS_ERR(ahbclk)) {
- dev_err(usbpdata->dev, "Failed to get hclk_hsic\n");
+ dev_err(usbpdata->dev, "Failed to get hclk_ehci1\n");
return;
}
- usbpdata->hclk_hsic = ahbclk;
- usbpdata->hsic_phy_480m = phyclk480m_hsic;
- usbpdata->hsic_phy_12m = phyclk12m_hsic;
+ usbpdata->hclk_ehci = ahbclk;
+ usbpdata->ehci_phy_480m = phyclk480m_ehci1;
+ usbpdata->ehci_phy_12m = phyclk12m_ehci1;
}
-static void rk_hsic_clock_enable(void *pdata, int enable)
+static void rk_ehci1_clock_enable(void *pdata, int enable)
{
struct rkehci_platform_data *usbpdata = pdata;
if (enable == usbpdata->clk_status)
return;
if (enable) {
- clk_prepare_enable(usbpdata->hclk_hsic);
- clk_prepare_enable(usbpdata->hsic_phy_480m);
- clk_prepare_enable(usbpdata->hsic_phy_12m);
+ clk_prepare_enable(usbpdata->hclk_ehci);
+ clk_prepare_enable(usbpdata->ehci_phy_480m);
+ clk_prepare_enable(usbpdata->ehci_phy_12m);
usbpdata->clk_status = 1;
} else {
- clk_disable_unprepare(usbpdata->hclk_hsic);
- clk_disable_unprepare(usbpdata->hsic_phy_480m);
- clk_disable_unprepare(usbpdata->hsic_phy_12m);
+ clk_disable_unprepare(usbpdata->hclk_ehci);
+ clk_disable_unprepare(usbpdata->ehci_phy_480m);
+ clk_disable_unprepare(usbpdata->ehci_phy_12m);
usbpdata->clk_status = 0;
}
}
-static void rk_hsic_soft_reset(void)
+static void rk_ehci1_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
{
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSIC, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSIC_AUX, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSICPHY, true);
- udelay(5);
+ struct rkehci_platform_data *usbpdata = pdata;
+ struct reset_control *rst_ehci1_h, *rst_ehci1_a, *rst_ehci1_p;
+
+ rst_ehci1_h = devm_reset_control_get(usbpdata->dev, "ehci1_ahb");
+ rst_ehci1_a = devm_reset_control_get(usbpdata->dev, "ehci1_aux");
+ rst_ehci1_p = devm_reset_control_get(usbpdata->dev, "ehci1_phy");
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSIC, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSIC_AUX, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_HSICPHY, false);
+ reset_control_assert(rst_ehci1_h);
+ reset_control_assert(rst_ehci1_a);
+ reset_control_assert(rst_ehci1_p);
+ udelay(5);
+ reset_control_deassert(rst_ehci1_h);
+ reset_control_deassert(rst_ehci1_a);
+ reset_control_deassert(rst_ehci1_p);
mdelay(2);
- /* HSIC per-port reset */
+ /* EHCI1 per-port reset */
control_usb->grf_uoc3_base->CON0 = ((1 << 10) << 16) | (1 << 10);
udelay(2);
control_usb->grf_uoc3_base->CON0 = ((1 << 10) << 16) | (0 << 10);
udelay(2);
}
-struct rkehci_platform_data rkhsic_pdata_rk3288 = {
- .hclk_hsic = NULL,
- .hsic_phy_12m = NULL,
- .hsic_phy_480m = NULL,
+struct rkehci_platform_data rkehci1_pdata_rk3288 = {
+ .hclk_ehci = NULL,
+ .ehci_phy_12m = NULL,
+ .ehci_phy_480m = NULL,
.clk_status = -1,
- .hw_init = rk_hsic_hw_init,
- .clock_init = rk_hsic_clock_init,
- .clock_enable = rk_hsic_clock_enable,
- .soft_reset = rk_hsic_soft_reset,
+ .hw_init = rk_ehci1_hw_init,
+ .clock_init = rk_ehci1_clock_init,
+ .clock_enable = rk_ehci1_clock_enable,
+ .soft_reset = rk_ehci1_soft_reset,
};
#endif
}
}
-static void rk_ehci_soft_reset(void)
+static void rk_ehci_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
{
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0_H, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0PHY, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0C, true);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USB_HOST0, true);
- udelay(5);
+ struct rkehci_platform_data *usbpdata = pdata;
+ struct reset_control *rst_host0_h, *rst_host0_p,
+ *rst_host0_c , *rst_host0;
+
+ rst_host0_h = devm_reset_control_get(usbpdata->dev, "ehci_ahb");
+ rst_host0_p = devm_reset_control_get(usbpdata->dev, "ehci_phy");
+ rst_host0_c = devm_reset_control_get(usbpdata->dev, "ehci_controller");
+ rst_host0 = devm_reset_control_get(usbpdata->dev, "ehci");
+ if (IS_ERR(rst_host0_h) || IS_ERR(rst_host0_p) ||
+ IS_ERR(rst_host0_c) || IS_ERR(rst_host0)) {
+ dev_err(usbpdata->dev, "Fail to get reset control from dts\n");
+ return;
+ }
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0_H, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0PHY, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST0C, false);
- rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USB_HOST0, false);
+ reset_control_assert(rst_host0_h);
+ reset_control_assert(rst_host0_p);
+ reset_control_assert(rst_host0_c);
+ reset_control_assert(rst_host0);
+ udelay(5);
+ reset_control_deassert(rst_host0_h);
+ reset_control_deassert(rst_host0_p);
+ reset_control_deassert(rst_host0_c);
+ reset_control_deassert(rst_host0);
mdelay(2);
}
}
}
-static void rk_ohci_soft_reset(void)
+static void rk_ohci_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
{
}
static void usb_battery_charger_detect_work(struct work_struct *work)
{
- rk_usb_charger_status = usb_battery_charger_detect(0);
+ rk_battery_charger_detect_cb(usb_battery_charger_detect(1));
}
/********** handler for bvalid irq **********/
/* clear irq */
control_usb->grf_uoc0_base->CON4 = (0x0008 | (0x0008 << 16));
-#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,
schedule_delayed_work(&control_usb->usb_det_wakeup_work,
HZ / 10);
}
-
- rk_usb_charger_status = USB_BC_TYPE_SDP;
schedule_delayed_work(&control_usb->usb_charger_det_work, HZ / 10);
return IRQ_HANDLED;
/* id fall */
if (uoc_con & (1 << 7)) {
-#ifdef CONFIG_RK_USB_UART
/* usb otg dp/dm switch to usb phy */
dwc_otg_uart_mode(NULL, PHY_USB_MODE);
-#endif
/* clear id fall irq pandding */
control_usb->grf_uoc0_base->CON4 = ((1 << 7) | (1 << 23));
}
return IRQ_HANDLED;
}
-/***** handler for otg line status change *****/
+#ifdef USB_LINESTATE_IRQ
+/***** handler for usb line status change *****/
static irqreturn_t line_irq_handler(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
+#endif
/************* register usb detection irqs **************/
static int otg_irq_detect_init(struct platform_device *pdev)
{
int ret = 0;
int irq = 0;
-
if (control_usb->usb_irq_wakeup) {
wake_lock_init(&control_usb->usb_wakelock, WAKE_LOCK_SUSPEND,
"usb_detect");
/*register otg_bvalid irq */
irq = platform_get_irq_byname(pdev, "otg_bvalid");
- if (irq > 0) {
- ret =
- request_irq(irq, bvalid_irq_handler, 0, "otg_bvalid", NULL);
+ 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);
- return ret;
} else {
/* enable bvalid irq */
control_usb->grf_uoc0_base->CON4 = 0x000c000c;
- if (control_usb->usb_irq_wakeup)
- enable_irq_wake(irq);
}
}
/*register otg_id irq */
irq = platform_get_irq_byname(pdev, "otg_id");
- if (irq > 0) {
+ if ((irq > 0) && control_usb->usb_irq_wakeup) {
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;
} else {
+ /* enable otg_id irq */
control_usb->grf_uoc0_base->CON4 = 0x00f000f0;
- if (control_usb->usb_irq_wakeup)
- enable_irq_wake(irq);
}
}
#if 0
return ret;
}
-#ifdef CONFIG_OF
-
-static const struct of_device_id rk_usb_control_id_table[] = {
- {
- .compatible = "rockchip,rk3288-usb-control",
- },
- {},
-};
-
-#endif
-
static int rk_usb_control_probe(struct platform_device *pdev)
{
int gpio, err;
control_usb->host_gpios->gpio = gpio;
if (!gpio_is_valid(gpio)) {
- dev_err(&pdev->dev, "invalid host gpio%d\n", gpio);
+ dev_warn(&pdev->dev, "host_drv_gpio is not specified or invalid\n");
} else {
err = devm_gpio_request(&pdev->dev, gpio, "host_drv_gpio");
if (err) {
control_usb->otg_gpios->gpio = gpio;
if (!gpio_is_valid(gpio)) {
- dev_err(&pdev->dev, "invalid otg gpio%d\n", gpio);
+ dev_warn(&pdev->dev, "otg_drv_gpio is not specified or invalid\n");
} else {
err = devm_gpio_request(&pdev->dev, gpio, "otg_drv_gpio");
if (err) {
return ret;
}
-static int rk_usb_control_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static struct platform_driver rk_usb_control_driver = {
- .probe = rk_usb_control_probe,
- .remove = rk_usb_control_remove,
- .driver = {
- .name = "rk3288-usb-control",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(rk_usb_control_id_table),
- },
-};
-
#ifdef CONFIG_OF
-
static const struct of_device_id dwc_otg_control_usb_id_table[] = {
{
.compatible = "rockchip,rk3288-dwc-control-usb",
},
{},
};
-
#endif
static int dwc_otg_control_usb_probe(struct platform_device *pdev)
{
- struct clk *hclk_usb_peri, *phyclk_480m, *phyclk480m_parent;
int ret = 0;
- if (!control_usb) {
- dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
- ret = -ENOMEM;
- goto err1;
- }
-
- 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);
-
- phyclk480m_parent = devm_clk_get(&pdev->dev, "usbphy2_480m");
- if (IS_ERR(phyclk480m_parent)) {
- dev_err(&pdev->dev, "Failed to get usbphy2_480m\n");
- goto err2;
- }
+ ret = rk_usb_control_probe(pdev);
+ if (ret)
+ return ret;
- phyclk_480m = devm_clk_get(&pdev->dev, "usbphy_480m");
- if (IS_ERR(phyclk_480m)) {
- dev_err(&pdev->dev, "Failed to get usbphy_480m\n");
- goto err2;
+ control_usb->hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
+ if (IS_ERR(control_usb->hclk_usb_peri)) {
+ dev_info(&pdev->dev, "no hclk_usb_peri specified\n");
+ control_usb->hclk_usb_peri = NULL;
}
- clk_set_parent(phyclk_480m, phyclk480m_parent);
+ clk_prepare_enable(control_usb->hclk_usb_peri);
ret = usb_grf_ioremap(pdev);
if (ret) {
dev_err(&pdev->dev, "Failed to ioremap usb grf\n");
- goto err2;
+ goto err;
}
#ifdef CONFIG_USB20_OTG
- if (usb20otg_get_status(USB_STATUS_BVABLID)) {
- rk_usb_charger_status = USB_BC_TYPE_SDP;
+ 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 err2;
+ goto err;
return 0;
-err2:
- clk_disable_unprepare(hclk_usb_peri);
-err1:
+err:
+ clk_disable_unprepare(control_usb->hclk_usb_peri);
return ret;
}
{
int retval = 0;
- retval = platform_driver_register(&rk_usb_control_driver);
- if (retval < 0) {
- printk(KERN_ERR "%s retval=%d\n", __func__, retval);
- return retval;
- }
-
retval = platform_driver_register(&dwc_otg_control_usb_driver);
if (retval < 0) {
static void __exit dwc_otg_control_usb_exit(void)
{
- platform_driver_unregister(&rk_usb_control_driver);
platform_driver_unregister(&dwc_otg_control_usb_driver);
}
MODULE_AUTHOR("RockChip Inc.");
MODULE_DESCRIPTION("RockChip Control Module USB Driver");
MODULE_LICENSE("GPL v2");
+#endif