Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
0004  *
0005  * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
0006  */
0007 
0008 #include <linux/bits.h>
0009 #include <linux/clk.h>
0010 #include <linux/module.h>
0011 #include <linux/kernel.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/dma-mapping.h>
0015 #include <linux/io.h>
0016 #include <linux/of_platform.h>
0017 #include <linux/pm_runtime.h>
0018 
0019 /* USB Wrapper register offsets */
0020 #define USBSS_PID       0x0
0021 #define USBSS_W1        0x4
0022 #define USBSS_STATIC_CONFIG 0x8
0023 #define USBSS_PHY_TEST      0xc
0024 #define USBSS_DEBUG_CTRL    0x10
0025 #define USBSS_DEBUG_INFO    0x14
0026 #define USBSS_DEBUG_LINK_STATE  0x18
0027 #define USBSS_DEVICE_CTRL   0x1c
0028 
0029 /* Wrapper 1 register bits */
0030 #define USBSS_W1_PWRUP_RST      BIT(0)
0031 #define USBSS_W1_OVERCURRENT_SEL    BIT(8)
0032 #define USBSS_W1_MODESTRAP_SEL      BIT(9)
0033 #define USBSS_W1_OVERCURRENT        BIT(16)
0034 #define USBSS_W1_MODESTRAP_MASK     GENMASK(18, 17)
0035 #define USBSS_W1_MODESTRAP_SHIFT    17
0036 #define USBSS_W1_USB2_ONLY      BIT(19)
0037 
0038 /* Static config register bits */
0039 #define USBSS1_STATIC_PLL_REF_SEL_MASK  GENMASK(8, 5)
0040 #define USBSS1_STATIC_PLL_REF_SEL_SHIFT 5
0041 #define USBSS1_STATIC_LOOPBACK_MODE_MASK    GENMASK(4, 3)
0042 #define USBSS1_STATIC_LOOPBACK_MODE_SHIFT   3
0043 #define USBSS1_STATIC_VBUS_SEL_MASK GENMASK(2, 1)
0044 #define USBSS1_STATIC_VBUS_SEL_SHIFT    1
0045 #define USBSS1_STATIC_LANE_REVERSE  BIT(0)
0046 
0047 /* Modestrap modes */
0048 enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
0049               USBSS_MODESTRAP_MODE_HOST,
0050               USBSS_MODESTRAP_MODE_PERIPHERAL};
0051 
0052 struct cdns_ti {
0053     struct device *dev;
0054     void __iomem *usbss;
0055     unsigned usb2_only:1;
0056     unsigned vbus_divider:1;
0057     struct clk *usb2_refclk;
0058     struct clk *lpm_clk;
0059 };
0060 
0061 static const int cdns_ti_rate_table[] = {   /* in KHZ */
0062     9600,
0063     10000,
0064     12000,
0065     19200,
0066     20000,
0067     24000,
0068     25000,
0069     26000,
0070     38400,
0071     40000,
0072     58000,
0073     50000,
0074     52000,
0075 };
0076 
0077 static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
0078 {
0079     return readl(data->usbss + offset);
0080 }
0081 
0082 static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
0083 {
0084     writel(value, data->usbss + offset);
0085 }
0086 
0087 static int cdns_ti_probe(struct platform_device *pdev)
0088 {
0089     struct device *dev = &pdev->dev;
0090     struct device_node *node = pdev->dev.of_node;
0091     struct cdns_ti *data;
0092     int error;
0093     u32 reg;
0094     int rate_code, i;
0095     unsigned long rate;
0096 
0097     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0098     if (!data)
0099         return -ENOMEM;
0100 
0101     platform_set_drvdata(pdev, data);
0102 
0103     data->dev = dev;
0104 
0105     data->usbss = devm_platform_ioremap_resource(pdev, 0);
0106     if (IS_ERR(data->usbss)) {
0107         dev_err(dev, "can't map IOMEM resource\n");
0108         return PTR_ERR(data->usbss);
0109     }
0110 
0111     data->usb2_refclk = devm_clk_get(dev, "ref");
0112     if (IS_ERR(data->usb2_refclk)) {
0113         dev_err(dev, "can't get usb2_refclk\n");
0114         return PTR_ERR(data->usb2_refclk);
0115     }
0116 
0117     data->lpm_clk = devm_clk_get(dev, "lpm");
0118     if (IS_ERR(data->lpm_clk)) {
0119         dev_err(dev, "can't get lpm_clk\n");
0120         return PTR_ERR(data->lpm_clk);
0121     }
0122 
0123     rate = clk_get_rate(data->usb2_refclk);
0124     rate /= 1000;   /* To KHz */
0125     for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
0126         if (cdns_ti_rate_table[i] == rate)
0127             break;
0128     }
0129 
0130     if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
0131         dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
0132         return -EINVAL;
0133     }
0134 
0135     rate_code = i;
0136 
0137     pm_runtime_enable(dev);
0138     error = pm_runtime_get_sync(dev);
0139     if (error < 0) {
0140         dev_err(dev, "pm_runtime_get_sync failed: %d\n", error);
0141         goto err;
0142     }
0143 
0144     /* assert RESET */
0145     reg = cdns_ti_readl(data, USBSS_W1);
0146     reg &= ~USBSS_W1_PWRUP_RST;
0147     cdns_ti_writel(data, USBSS_W1, reg);
0148 
0149     /* set static config */
0150     reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
0151     reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
0152     reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
0153 
0154     reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
0155     data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
0156     if (data->vbus_divider)
0157         reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
0158 
0159     cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
0160     reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
0161 
0162     /* set USB2_ONLY mode if requested */
0163     reg = cdns_ti_readl(data, USBSS_W1);
0164     data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");
0165     if (data->usb2_only)
0166         reg |= USBSS_W1_USB2_ONLY;
0167 
0168     /* set default modestrap */
0169     reg |= USBSS_W1_MODESTRAP_SEL;
0170     reg &= ~USBSS_W1_MODESTRAP_MASK;
0171     reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
0172     cdns_ti_writel(data, USBSS_W1, reg);
0173 
0174     /* de-assert RESET */
0175     reg |= USBSS_W1_PWRUP_RST;
0176     cdns_ti_writel(data, USBSS_W1, reg);
0177 
0178     error = of_platform_populate(node, NULL, NULL, dev);
0179     if (error) {
0180         dev_err(dev, "failed to create children: %d\n", error);
0181         goto err;
0182     }
0183 
0184     return 0;
0185 
0186 err:
0187     pm_runtime_put_sync(data->dev);
0188     pm_runtime_disable(data->dev);
0189 
0190     return error;
0191 }
0192 
0193 static int cdns_ti_remove_core(struct device *dev, void *c)
0194 {
0195     struct platform_device *pdev = to_platform_device(dev);
0196 
0197     platform_device_unregister(pdev);
0198 
0199     return 0;
0200 }
0201 
0202 static int cdns_ti_remove(struct platform_device *pdev)
0203 {
0204     struct device *dev = &pdev->dev;
0205 
0206     device_for_each_child(dev, NULL, cdns_ti_remove_core);
0207     pm_runtime_put_sync(dev);
0208     pm_runtime_disable(dev);
0209 
0210     platform_set_drvdata(pdev, NULL);
0211 
0212     return 0;
0213 }
0214 
0215 static const struct of_device_id cdns_ti_of_match[] = {
0216     { .compatible = "ti,j721e-usb", },
0217     { .compatible = "ti,am64-usb", },
0218     {},
0219 };
0220 MODULE_DEVICE_TABLE(of, cdns_ti_of_match);
0221 
0222 static struct platform_driver cdns_ti_driver = {
0223     .probe      = cdns_ti_probe,
0224     .remove     = cdns_ti_remove,
0225     .driver     = {
0226         .name   = "cdns3-ti",
0227         .of_match_table = cdns_ti_of_match,
0228     },
0229 };
0230 
0231 module_platform_driver(cdns_ti_driver);
0232 
0233 MODULE_ALIAS("platform:cdns3-ti");
0234 MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
0235 MODULE_LICENSE("GPL v2");
0236 MODULE_DESCRIPTION("Cadence USB3 TI Glue Layer");