0001
0002
0003
0004
0005
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
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
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
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
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[] = {
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;
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
0145 reg = cdns_ti_readl(data, USBSS_W1);
0146 reg &= ~USBSS_W1_PWRUP_RST;
0147 cdns_ti_writel(data, USBSS_W1, reg);
0148
0149
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
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
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
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");