diff --git a/drivers/phy/phy-grx500-usb.c b/drivers/phy/phy-grx500-usb.c
index 9404f439130490c74809b16c4be87c196c08b8f7..8f3a21e2639602547cc3596336e9d8df9db9ffd2 100644
--- a/drivers/phy/phy-grx500-usb.c
+++ b/drivers/phy/phy-grx500-usb.c
@@ -15,9 +15,22 @@
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/clk.h>
+#include <linux/interrupt.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/workqueue.h>
 #include <linux/reset.h>
 
+#define SECOND_TIME_DELAY 30
+
+struct ltq_dwc3_phy;
+
+struct ltq_oc_ops {
+	int (*enable)(struct ltq_dwc3_phy *);
+	int (*disable)(struct ltq_dwc3_phy *);
+	int (*init)(struct ltq_dwc3_phy *);
+};
+
 struct ltq_dwc3_phy_cfg {
 	u8 tx_invert_ovrd;
 	u8 rx_invert_ovrd;
@@ -37,6 +50,13 @@ struct ltq_dwc3_phy {
 	const struct ltq_dwc3_phy_cfg *cfg;
 	bool is_tx_pol_inv;
 	bool is_rx_pol_inv;
+
+	/* OCP */
+	bool is_enable_oc;
+	unsigned int irq;
+	struct workqueue_struct *workq;
+	struct delayed_work oc_recover_w;
+	const struct ltq_oc_ops *oc_ops;
 };
 
 static const struct ltq_dwc3_phy_cfg grx500_phy_cfg = {
@@ -46,6 +66,103 @@ static const struct ltq_dwc3_phy_cfg grx500_phy_cfg = {
 	.rx_ovrd_offset = 0x4014,
 };
 
+static int ltq_grx500_oc_enable(struct ltq_dwc3_phy *dwc3_phy)
+{
+	struct pinctrl *p;
+
+	p = devm_pinctrl_get_select(
+		dwc3_phy->dev, PINCTRL_STATE_IDLE);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+	msleep(50);
+
+	return 0;
+}
+
+static int ltq_grx500_oc_disable(struct ltq_dwc3_phy *dwc3_phy)
+{
+	struct pinctrl *p;
+
+	p = devm_pinctrl_get_select(
+		dwc3_phy->dev, PINCTRL_STATE_DEFAULT);
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+	msleep(50);
+
+	return 0;
+}
+
+void ltq_oc_recovery_worker(struct work_struct *work)
+{
+	struct ltq_dwc3_phy *dwc3_phy = container_of(work,
+		struct ltq_dwc3_phy, oc_recover_w.work);
+
+	dev_info(dwc3_phy->dev, "Turn on the power again to recover\n");
+
+	/* Restart OCP to recover */
+	dwc3_phy->oc_ops->disable(dwc3_phy);
+	dwc3_phy->oc_ops->enable(dwc3_phy);
+
+	irq_set_irq_type(dwc3_phy->irq, IRQ_TYPE_LEVEL_LOW);
+}
+
+static irqreturn_t ltq_oc_irq(int irq, void *_dwc3_phy)
+{
+	struct ltq_dwc3_phy *dwc3_phy = _dwc3_phy;
+
+	dev_info(dwc3_phy->dev, "USB OC protection is triggered\n");
+
+	irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+	queue_delayed_work(dwc3_phy->workq,
+		&dwc3_phy->oc_recover_w, SECOND_TIME_DELAY*HZ);
+
+	return IRQ_HANDLED;
+}
+
+static int ltq_grx500_oc_init(struct ltq_dwc3_phy *dwc3_phy)
+{
+	int ret;
+	struct device *dev = dwc3_phy->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+
+	dwc3_phy->irq = platform_get_irq(pdev, 0);
+	if (dwc3_phy->irq < 0) {
+		dev_err(dev, "missing IRQ resource\n");
+		return -EINVAL;
+	}
+
+	dwc3_phy->workq = create_singlethread_workqueue("usb ocp wq");
+	if (!dwc3_phy->workq) {
+		dev_err(dev, "create_singlethread_workqueue() failed\n");
+		return -ENOMEM;
+	}
+	INIT_DELAYED_WORK(&dwc3_phy->oc_recover_w, ltq_oc_recovery_worker);
+
+	if (dwc3_phy->vbus_reg) {
+		ret = regulator_enable(dwc3_phy->vbus_reg);
+		if (ret) {
+			dev_err(dev, "regulator enable failed\n");
+			return ret;
+		}
+	}
+
+	ret = devm_request_irq(dev, dwc3_phy->irq, &ltq_oc_irq,
+		IRQ_TYPE_LEVEL_LOW, "usb ocp", dwc3_phy);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ #%d --> %d\n",
+			dwc3_phy->irq, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct ltq_oc_ops grx500_ltq_oc_ops = {
+	.enable = ltq_grx500_oc_enable,
+	.disable = ltq_grx500_oc_disable,
+	.init = ltq_grx500_oc_init,
+};
+
 static inline u32 ltq_dwc3_phy_readl(void __iomem *base, u32 offset)
 {
 	return readl(base + offset);
@@ -108,6 +225,9 @@ static int ltq_dwc3_phy_power_on(struct phy *phy)
 		}
 	}
 
+	if (dwc3_phy->is_enable_oc)
+		dwc3_phy->oc_ops->enable(dwc3_phy);
+
 	return 0;
 }
 
@@ -115,6 +235,9 @@ static int ltq_dwc3_phy_power_off(struct phy *phy)
 {
 	struct ltq_dwc3_phy *dwc3_phy = phy_get_drvdata(phy);
 
+	if (dwc3_phy->is_enable_oc)
+		dwc3_phy->oc_ops->disable(dwc3_phy);
+
 	if (dwc3_phy->vbus_reg)
 		regulator_disable(dwc3_phy->vbus_reg);
 
@@ -151,6 +274,8 @@ static int ltq_usb_read_dt(struct ltq_dwc3_phy *dwc3_phy,
 													"invert-rx-polarity");
 	dwc3_phy->is_tx_pol_inv = of_property_read_bool(dev->of_node,
 													"invert-tx-polarity");
+	dwc3_phy->is_enable_oc = of_property_read_bool(dev->of_node,
+													"enable-over-current");
 
 	return 0;
 }
@@ -195,6 +320,8 @@ static int ltq_dwc3_phy_probe(struct platform_device *pdev)
 
 	dwc3_phy->base = base;
 	dwc3_phy->dev = dev;
+	if (dwc3_phy->is_enable_oc)
+		dwc3_phy->oc_ops = &grx500_ltq_oc_ops;
 
 	platform_set_drvdata(pdev, dwc3_phy);
 
@@ -206,6 +333,9 @@ static int ltq_dwc3_phy_probe(struct platform_device *pdev)
 
 	phy_set_drvdata(dwc3_phy->phy, dwc3_phy);
 
+	if (dwc3_phy->is_enable_oc)
+		dwc3_phy->oc_ops->init(dwc3_phy);
+
 	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 
 	return PTR_ERR_OR_ZERO(provider);