1*387c359bSRoger Quadros // SPDX-License-Identifier: GPL-2.0 2*387c359bSRoger Quadros /** 3*387c359bSRoger Quadros * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller 4*387c359bSRoger Quadros * 5*387c359bSRoger Quadros * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com 6*387c359bSRoger Quadros */ 7*387c359bSRoger Quadros 8*387c359bSRoger Quadros #include <linux/bits.h> 9*387c359bSRoger Quadros #include <linux/clk.h> 10*387c359bSRoger Quadros #include <linux/module.h> 11*387c359bSRoger Quadros #include <linux/kernel.h> 12*387c359bSRoger Quadros #include <linux/interrupt.h> 13*387c359bSRoger Quadros #include <linux/platform_device.h> 14*387c359bSRoger Quadros #include <linux/dma-mapping.h> 15*387c359bSRoger Quadros #include <linux/io.h> 16*387c359bSRoger Quadros #include <linux/of_platform.h> 17*387c359bSRoger Quadros #include <linux/pm_runtime.h> 18*387c359bSRoger Quadros 19*387c359bSRoger Quadros /* USB Wrapper register offsets */ 20*387c359bSRoger Quadros #define USBSS_PID 0x0 21*387c359bSRoger Quadros #define USBSS_W1 0x4 22*387c359bSRoger Quadros #define USBSS_STATIC_CONFIG 0x8 23*387c359bSRoger Quadros #define USBSS_PHY_TEST 0xc 24*387c359bSRoger Quadros #define USBSS_DEBUG_CTRL 0x10 25*387c359bSRoger Quadros #define USBSS_DEBUG_INFO 0x14 26*387c359bSRoger Quadros #define USBSS_DEBUG_LINK_STATE 0x18 27*387c359bSRoger Quadros #define USBSS_DEVICE_CTRL 0x1c 28*387c359bSRoger Quadros 29*387c359bSRoger Quadros /* Wrapper 1 register bits */ 30*387c359bSRoger Quadros #define USBSS_W1_PWRUP_RST BIT(0) 31*387c359bSRoger Quadros #define USBSS_W1_OVERCURRENT_SEL BIT(8) 32*387c359bSRoger Quadros #define USBSS_W1_MODESTRAP_SEL BIT(9) 33*387c359bSRoger Quadros #define USBSS_W1_OVERCURRENT BIT(16) 34*387c359bSRoger Quadros #define USBSS_W1_MODESTRAP_MASK GENMASK(18, 17) 35*387c359bSRoger Quadros #define USBSS_W1_MODESTRAP_SHIFT 17 36*387c359bSRoger Quadros #define USBSS_W1_USB2_ONLY BIT(19) 37*387c359bSRoger Quadros 38*387c359bSRoger Quadros /* Static config register bits */ 39*387c359bSRoger Quadros #define USBSS1_STATIC_PLL_REF_SEL_MASK GENMASK(8, 5) 40*387c359bSRoger Quadros #define USBSS1_STATIC_PLL_REF_SEL_SHIFT 5 41*387c359bSRoger Quadros #define USBSS1_STATIC_LOOPBACK_MODE_MASK GENMASK(4, 3) 42*387c359bSRoger Quadros #define USBSS1_STATIC_LOOPBACK_MODE_SHIFT 3 43*387c359bSRoger Quadros #define USBSS1_STATIC_VBUS_SEL_MASK GENMASK(2, 1) 44*387c359bSRoger Quadros #define USBSS1_STATIC_VBUS_SEL_SHIFT 1 45*387c359bSRoger Quadros #define USBSS1_STATIC_LANE_REVERSE BIT(0) 46*387c359bSRoger Quadros 47*387c359bSRoger Quadros /* Modestrap modes */ 48*387c359bSRoger Quadros enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE, 49*387c359bSRoger Quadros USBSS_MODESTRAP_MODE_HOST, 50*387c359bSRoger Quadros USBSS_MODESTRAP_MODE_PERIPHERAL}; 51*387c359bSRoger Quadros 52*387c359bSRoger Quadros struct cdns_ti { 53*387c359bSRoger Quadros struct device *dev; 54*387c359bSRoger Quadros void __iomem *usbss; 55*387c359bSRoger Quadros int usb2_only:1; 56*387c359bSRoger Quadros int vbus_divider:1; 57*387c359bSRoger Quadros struct clk *usb2_refclk; 58*387c359bSRoger Quadros struct clk *lpm_clk; 59*387c359bSRoger Quadros }; 60*387c359bSRoger Quadros 61*387c359bSRoger Quadros static const int cdns_ti_rate_table[] = { /* in KHZ */ 62*387c359bSRoger Quadros 9600, 63*387c359bSRoger Quadros 10000, 64*387c359bSRoger Quadros 12000, 65*387c359bSRoger Quadros 19200, 66*387c359bSRoger Quadros 20000, 67*387c359bSRoger Quadros 24000, 68*387c359bSRoger Quadros 25000, 69*387c359bSRoger Quadros 26000, 70*387c359bSRoger Quadros 38400, 71*387c359bSRoger Quadros 40000, 72*387c359bSRoger Quadros 58000, 73*387c359bSRoger Quadros 50000, 74*387c359bSRoger Quadros 52000, 75*387c359bSRoger Quadros }; 76*387c359bSRoger Quadros 77*387c359bSRoger Quadros static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset) 78*387c359bSRoger Quadros { 79*387c359bSRoger Quadros return readl(data->usbss + offset); 80*387c359bSRoger Quadros } 81*387c359bSRoger Quadros 82*387c359bSRoger Quadros static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value) 83*387c359bSRoger Quadros { 84*387c359bSRoger Quadros writel(value, data->usbss + offset); 85*387c359bSRoger Quadros } 86*387c359bSRoger Quadros 87*387c359bSRoger Quadros static int cdns_ti_probe(struct platform_device *pdev) 88*387c359bSRoger Quadros { 89*387c359bSRoger Quadros struct device *dev = &pdev->dev; 90*387c359bSRoger Quadros struct device_node *node = pdev->dev.of_node; 91*387c359bSRoger Quadros struct cdns_ti *data; 92*387c359bSRoger Quadros int error; 93*387c359bSRoger Quadros u32 reg; 94*387c359bSRoger Quadros int rate_code, i; 95*387c359bSRoger Quadros unsigned long rate; 96*387c359bSRoger Quadros 97*387c359bSRoger Quadros data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 98*387c359bSRoger Quadros if (!data) 99*387c359bSRoger Quadros return -ENOMEM; 100*387c359bSRoger Quadros 101*387c359bSRoger Quadros platform_set_drvdata(pdev, data); 102*387c359bSRoger Quadros 103*387c359bSRoger Quadros data->dev = dev; 104*387c359bSRoger Quadros 105*387c359bSRoger Quadros data->usbss = devm_platform_ioremap_resource(pdev, 0); 106*387c359bSRoger Quadros if (IS_ERR(data->usbss)) { 107*387c359bSRoger Quadros dev_err(dev, "can't map IOMEM resource\n"); 108*387c359bSRoger Quadros return PTR_ERR(data->usbss); 109*387c359bSRoger Quadros } 110*387c359bSRoger Quadros 111*387c359bSRoger Quadros data->usb2_refclk = devm_clk_get(dev, "ref"); 112*387c359bSRoger Quadros if (IS_ERR(data->usb2_refclk)) { 113*387c359bSRoger Quadros dev_err(dev, "can't get usb2_refclk\n"); 114*387c359bSRoger Quadros return PTR_ERR(data->usb2_refclk); 115*387c359bSRoger Quadros } 116*387c359bSRoger Quadros 117*387c359bSRoger Quadros data->lpm_clk = devm_clk_get(dev, "lpm"); 118*387c359bSRoger Quadros if (IS_ERR(data->lpm_clk)) { 119*387c359bSRoger Quadros dev_err(dev, "can't get lpm_clk\n"); 120*387c359bSRoger Quadros return PTR_ERR(data->lpm_clk); 121*387c359bSRoger Quadros } 122*387c359bSRoger Quadros 123*387c359bSRoger Quadros rate = clk_get_rate(data->usb2_refclk); 124*387c359bSRoger Quadros rate /= 1000; /* To KHz */ 125*387c359bSRoger Quadros for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) { 126*387c359bSRoger Quadros if (cdns_ti_rate_table[i] == rate) 127*387c359bSRoger Quadros break; 128*387c359bSRoger Quadros } 129*387c359bSRoger Quadros 130*387c359bSRoger Quadros if (i == ARRAY_SIZE(cdns_ti_rate_table)) { 131*387c359bSRoger Quadros dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate); 132*387c359bSRoger Quadros return -EINVAL; 133*387c359bSRoger Quadros } 134*387c359bSRoger Quadros 135*387c359bSRoger Quadros rate_code = i; 136*387c359bSRoger Quadros 137*387c359bSRoger Quadros pm_runtime_enable(dev); 138*387c359bSRoger Quadros error = pm_runtime_get_sync(dev); 139*387c359bSRoger Quadros if (error < 0) { 140*387c359bSRoger Quadros dev_err(dev, "pm_runtime_get_sync failed: %d\n", error); 141*387c359bSRoger Quadros goto err_get; 142*387c359bSRoger Quadros } 143*387c359bSRoger Quadros 144*387c359bSRoger Quadros /* assert RESET */ 145*387c359bSRoger Quadros reg = cdns_ti_readl(data, USBSS_W1); 146*387c359bSRoger Quadros reg &= ~USBSS_W1_PWRUP_RST; 147*387c359bSRoger Quadros cdns_ti_writel(data, USBSS_W1, reg); 148*387c359bSRoger Quadros 149*387c359bSRoger Quadros /* set static config */ 150*387c359bSRoger Quadros reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG); 151*387c359bSRoger Quadros reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK; 152*387c359bSRoger Quadros reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT; 153*387c359bSRoger Quadros 154*387c359bSRoger Quadros reg &= ~USBSS1_STATIC_VBUS_SEL_MASK; 155*387c359bSRoger Quadros data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider"); 156*387c359bSRoger Quadros if (data->vbus_divider) 157*387c359bSRoger Quadros reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT; 158*387c359bSRoger Quadros 159*387c359bSRoger Quadros cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg); 160*387c359bSRoger Quadros reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG); 161*387c359bSRoger Quadros 162*387c359bSRoger Quadros /* set USB2_ONLY mode if requested */ 163*387c359bSRoger Quadros reg = cdns_ti_readl(data, USBSS_W1); 164*387c359bSRoger Quadros data->usb2_only = device_property_read_bool(dev, "ti,usb2-only"); 165*387c359bSRoger Quadros if (data->usb2_only) 166*387c359bSRoger Quadros reg |= USBSS_W1_USB2_ONLY; 167*387c359bSRoger Quadros 168*387c359bSRoger Quadros /* set default modestrap */ 169*387c359bSRoger Quadros reg |= USBSS_W1_MODESTRAP_SEL; 170*387c359bSRoger Quadros reg &= ~USBSS_W1_MODESTRAP_MASK; 171*387c359bSRoger Quadros reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT; 172*387c359bSRoger Quadros cdns_ti_writel(data, USBSS_W1, reg); 173*387c359bSRoger Quadros 174*387c359bSRoger Quadros /* de-assert RESET */ 175*387c359bSRoger Quadros reg |= USBSS_W1_PWRUP_RST; 176*387c359bSRoger Quadros cdns_ti_writel(data, USBSS_W1, reg); 177*387c359bSRoger Quadros 178*387c359bSRoger Quadros error = of_platform_populate(node, NULL, NULL, dev); 179*387c359bSRoger Quadros if (error) { 180*387c359bSRoger Quadros dev_err(dev, "failed to create children: %d\n", error); 181*387c359bSRoger Quadros goto err; 182*387c359bSRoger Quadros } 183*387c359bSRoger Quadros 184*387c359bSRoger Quadros return 0; 185*387c359bSRoger Quadros 186*387c359bSRoger Quadros err: 187*387c359bSRoger Quadros pm_runtime_put_sync(data->dev); 188*387c359bSRoger Quadros err_get: 189*387c359bSRoger Quadros pm_runtime_disable(data->dev); 190*387c359bSRoger Quadros 191*387c359bSRoger Quadros return error; 192*387c359bSRoger Quadros } 193*387c359bSRoger Quadros 194*387c359bSRoger Quadros static int cdns_ti_remove_core(struct device *dev, void *c) 195*387c359bSRoger Quadros { 196*387c359bSRoger Quadros struct platform_device *pdev = to_platform_device(dev); 197*387c359bSRoger Quadros 198*387c359bSRoger Quadros platform_device_unregister(pdev); 199*387c359bSRoger Quadros 200*387c359bSRoger Quadros return 0; 201*387c359bSRoger Quadros } 202*387c359bSRoger Quadros 203*387c359bSRoger Quadros static int cdns_ti_remove(struct platform_device *pdev) 204*387c359bSRoger Quadros { 205*387c359bSRoger Quadros struct device *dev = &pdev->dev; 206*387c359bSRoger Quadros 207*387c359bSRoger Quadros device_for_each_child(dev, NULL, cdns_ti_remove_core); 208*387c359bSRoger Quadros pm_runtime_put_sync(dev); 209*387c359bSRoger Quadros pm_runtime_disable(dev); 210*387c359bSRoger Quadros 211*387c359bSRoger Quadros platform_set_drvdata(pdev, NULL); 212*387c359bSRoger Quadros 213*387c359bSRoger Quadros return 0; 214*387c359bSRoger Quadros } 215*387c359bSRoger Quadros 216*387c359bSRoger Quadros static const struct of_device_id cdns_ti_of_match[] = { 217*387c359bSRoger Quadros { .compatible = "ti,j721e-usb", }, 218*387c359bSRoger Quadros {}, 219*387c359bSRoger Quadros }; 220*387c359bSRoger Quadros MODULE_DEVICE_TABLE(of, cdns_ti_of_match); 221*387c359bSRoger Quadros 222*387c359bSRoger Quadros static struct platform_driver cdns_ti_driver = { 223*387c359bSRoger Quadros .probe = cdns_ti_probe, 224*387c359bSRoger Quadros .remove = cdns_ti_remove, 225*387c359bSRoger Quadros .driver = { 226*387c359bSRoger Quadros .name = "cdns3-ti", 227*387c359bSRoger Quadros .of_match_table = cdns_ti_of_match, 228*387c359bSRoger Quadros }, 229*387c359bSRoger Quadros }; 230*387c359bSRoger Quadros 231*387c359bSRoger Quadros module_platform_driver(cdns_ti_driver); 232*387c359bSRoger Quadros 233*387c359bSRoger Quadros MODULE_ALIAS("platform:cdns3-ti"); 234*387c359bSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 235*387c359bSRoger Quadros MODULE_LICENSE("GPL v2"); 236*387c359bSRoger Quadros MODULE_DESCRIPTION("Cadence USB3 TI Glue Layer"); 237