1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RZ/V2M USB3DRD driver 4 * 5 * Copyright (C) 2022 Renesas Electronics Corporation 6 */ 7 8 #include <linux/io.h> 9 #include <linux/of_platform.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/reset.h> 13 #include <linux/usb/rzv2m_usb3drd.h> 14 15 #define USB_PERI_DRD_CON 0x000 16 17 #define USB_PERI_DRD_CON_PERI_RST BIT(31) 18 #define USB_PERI_DRD_CON_HOST_RST BIT(30) 19 #define USB_PERI_DRD_CON_PERI_CON BIT(24) 20 21 static void rzv2m_usb3drd_set_bit(struct rzv2m_usb3drd *usb3, u32 bits, 22 u32 offs) 23 { 24 u32 val = readl(usb3->reg + offs); 25 26 val |= bits; 27 writel(val, usb3->reg + offs); 28 } 29 30 static void rzv2m_usb3drd_clear_bit(struct rzv2m_usb3drd *usb3, u32 bits, 31 u32 offs) 32 { 33 u32 val = readl(usb3->reg + offs); 34 35 val &= ~bits; 36 writel(val, usb3->reg + offs); 37 } 38 39 void rzv2m_usb3drd_reset(struct device *dev, bool host) 40 { 41 struct rzv2m_usb3drd *usb3 = dev_get_drvdata(dev); 42 43 if (host) { 44 rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_CON, 45 USB_PERI_DRD_CON); 46 rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_HOST_RST, 47 USB_PERI_DRD_CON); 48 rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_RST, 49 USB_PERI_DRD_CON); 50 } else { 51 rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_CON, 52 USB_PERI_DRD_CON); 53 rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_HOST_RST, 54 USB_PERI_DRD_CON); 55 rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_RST, 56 USB_PERI_DRD_CON); 57 } 58 } 59 EXPORT_SYMBOL_GPL(rzv2m_usb3drd_reset); 60 61 static void rzv2m_usb3drd_remove(struct platform_device *pdev) 62 { 63 struct rzv2m_usb3drd *usb3 = platform_get_drvdata(pdev); 64 65 of_platform_depopulate(usb3->dev); 66 pm_runtime_put(usb3->dev); 67 pm_runtime_disable(&pdev->dev); 68 reset_control_assert(usb3->drd_rstc); 69 } 70 71 static int rzv2m_usb3drd_probe(struct platform_device *pdev) 72 { 73 struct rzv2m_usb3drd *usb3; 74 int ret; 75 76 usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); 77 if (!usb3) 78 return -ENOMEM; 79 80 usb3->dev = &pdev->dev; 81 82 usb3->drd_irq = platform_get_irq_byname(pdev, "drd"); 83 if (usb3->drd_irq < 0) 84 return usb3->drd_irq; 85 86 usb3->reg = devm_platform_ioremap_resource(pdev, 0); 87 if (IS_ERR(usb3->reg)) 88 return PTR_ERR(usb3->reg); 89 90 platform_set_drvdata(pdev, usb3); 91 92 usb3->drd_rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 93 if (IS_ERR(usb3->drd_rstc)) 94 return dev_err_probe(&pdev->dev, PTR_ERR(usb3->drd_rstc), 95 "failed to get drd reset"); 96 97 reset_control_deassert(usb3->drd_rstc); 98 pm_runtime_enable(&pdev->dev); 99 ret = pm_runtime_resume_and_get(usb3->dev); 100 if (ret) 101 goto err_rst; 102 103 ret = of_platform_populate(usb3->dev->of_node, NULL, NULL, usb3->dev); 104 if (ret) 105 goto err_pm; 106 107 return 0; 108 109 err_pm: 110 pm_runtime_put(usb3->dev); 111 112 err_rst: 113 pm_runtime_disable(&pdev->dev); 114 reset_control_assert(usb3->drd_rstc); 115 return ret; 116 } 117 118 static const struct of_device_id rzv2m_usb3drd_of_match[] = { 119 { .compatible = "renesas,rzv2m-usb3drd", }, 120 { /* Sentinel */ } 121 }; 122 MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match); 123 124 static struct platform_driver rzv2m_usb3drd_driver = { 125 .driver = { 126 .name = "rzv2m-usb3drd", 127 .of_match_table = rzv2m_usb3drd_of_match, 128 }, 129 .probe = rzv2m_usb3drd_probe, 130 .remove_new = rzv2m_usb3drd_remove, 131 }; 132 module_platform_driver(rzv2m_usb3drd_driver); 133 134 MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 135 MODULE_DESCRIPTION("Renesas RZ/V2M USB3DRD driver"); 136 MODULE_LICENSE("GPL"); 137 MODULE_ALIAS("platform:rzv2m_usb3drd"); 138