1 /* 2 * Copyright 2012 Freescale Semiconductor, Inc. 3 * 4 * The code contained herein is licensed under the GNU General Public 5 * License. You may obtain a copy of the GNU General Public License 6 * Version 2 or later at the following locations: 7 * 8 * http://www.opensource.org/licenses/gpl-license.html 9 * http://www.gnu.org/copyleft/gpl.html 10 */ 11 12 #include <linux/module.h> 13 #include <linux/of_platform.h> 14 #include <linux/clk.h> 15 #include <linux/err.h> 16 #include <linux/io.h> 17 #include <linux/delay.h> 18 19 #include "ci_hdrc_imx.h" 20 21 #define MX25_USB_PHY_CTRL_OFFSET 0x08 22 #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) 23 24 #define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0) 25 #define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0) 26 #define MX25_EHCI_INTERFACE_MASK (0xf) 27 28 #define MX25_OTG_SIC_SHIFT 29 29 #define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT) 30 #define MX25_OTG_PM_BIT BIT(24) 31 #define MX25_OTG_PP_BIT BIT(11) 32 #define MX25_OTG_OCPOL_BIT BIT(3) 33 34 #define MX25_H1_SIC_SHIFT 21 35 #define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT) 36 #define MX25_H1_PP_BIT BIT(18) 37 #define MX25_H1_PM_BIT BIT(16) 38 #define MX25_H1_IPPUE_UP_BIT BIT(7) 39 #define MX25_H1_IPPUE_DOWN_BIT BIT(6) 40 #define MX25_H1_TLL_BIT BIT(5) 41 #define MX25_H1_USBTE_BIT BIT(4) 42 #define MX25_H1_OCPOL_BIT BIT(2) 43 44 #define MX27_H1_PM_BIT BIT(8) 45 #define MX27_H2_PM_BIT BIT(16) 46 #define MX27_OTG_PM_BIT BIT(24) 47 48 #define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 49 #define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c 50 #define MX53_USB_UH2_CTRL_OFFSET 0x14 51 #define MX53_USB_UH3_CTRL_OFFSET 0x18 52 #define MX53_BM_OVER_CUR_DIS_H1 BIT(5) 53 #define MX53_BM_OVER_CUR_DIS_OTG BIT(8) 54 #define MX53_BM_OVER_CUR_DIS_UHx BIT(30) 55 #define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3 56 #define MX53_USB_PLL_DIV_24_MHZ 0x01 57 58 #define MX6_BM_OVER_CUR_DIS BIT(7) 59 60 struct usbmisc_ops { 61 /* It's called once when probe a usb device */ 62 int (*init)(struct imx_usbmisc_data *data); 63 /* It's called once after adding a usb device */ 64 int (*post)(struct imx_usbmisc_data *data); 65 }; 66 67 struct imx_usbmisc { 68 void __iomem *base; 69 spinlock_t lock; 70 struct clk *clk; 71 const struct usbmisc_ops *ops; 72 }; 73 74 static struct imx_usbmisc *usbmisc; 75 76 static int usbmisc_imx25_init(struct imx_usbmisc_data *data) 77 { 78 unsigned long flags; 79 u32 val = 0; 80 81 if (data->index > 1) 82 return -EINVAL; 83 84 spin_lock_irqsave(&usbmisc->lock, flags); 85 switch (data->index) { 86 case 0: 87 val = readl(usbmisc->base); 88 val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); 89 val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; 90 val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); 91 writel(val, usbmisc->base); 92 break; 93 case 1: 94 val = readl(usbmisc->base); 95 val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT); 96 val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; 97 val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | 98 MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); 99 100 writel(val, usbmisc->base); 101 102 break; 103 } 104 spin_unlock_irqrestore(&usbmisc->lock, flags); 105 106 return 0; 107 } 108 109 static int usbmisc_imx25_post(struct imx_usbmisc_data *data) 110 { 111 void __iomem *reg; 112 unsigned long flags; 113 u32 val; 114 115 if (data->index > 2) 116 return -EINVAL; 117 118 reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; 119 120 if (data->evdo) { 121 spin_lock_irqsave(&usbmisc->lock, flags); 122 val = readl(reg); 123 writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); 124 spin_unlock_irqrestore(&usbmisc->lock, flags); 125 usleep_range(5000, 10000); /* needed to stabilize voltage */ 126 } 127 128 return 0; 129 } 130 131 static int usbmisc_imx27_init(struct imx_usbmisc_data *data) 132 { 133 unsigned long flags; 134 u32 val; 135 136 switch (data->index) { 137 case 0: 138 val = MX27_OTG_PM_BIT; 139 break; 140 case 1: 141 val = MX27_H1_PM_BIT; 142 break; 143 case 2: 144 val = MX27_H2_PM_BIT; 145 break; 146 default: 147 return -EINVAL; 148 }; 149 150 spin_lock_irqsave(&usbmisc->lock, flags); 151 if (data->disable_oc) 152 val = readl(usbmisc->base) | val; 153 else 154 val = readl(usbmisc->base) & ~val; 155 writel(val, usbmisc->base); 156 spin_unlock_irqrestore(&usbmisc->lock, flags); 157 158 return 0; 159 } 160 161 static int usbmisc_imx53_init(struct imx_usbmisc_data *data) 162 { 163 void __iomem *reg = NULL; 164 unsigned long flags; 165 u32 val = 0; 166 167 if (data->index > 3) 168 return -EINVAL; 169 170 /* Select a 24 MHz reference clock for the PHY */ 171 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET; 172 val = readl(reg); 173 val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; 174 val |= MX53_USB_PLL_DIV_24_MHZ; 175 writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); 176 177 if (data->disable_oc) { 178 spin_lock_irqsave(&usbmisc->lock, flags); 179 switch (data->index) { 180 case 0: 181 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 182 val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; 183 break; 184 case 1: 185 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 186 val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; 187 break; 188 case 2: 189 reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; 190 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 191 break; 192 case 3: 193 reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; 194 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 195 break; 196 } 197 if (reg && val) 198 writel(val, reg); 199 spin_unlock_irqrestore(&usbmisc->lock, flags); 200 } 201 202 return 0; 203 } 204 205 static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) 206 { 207 unsigned long flags; 208 u32 reg; 209 210 if (data->index > 3) 211 return -EINVAL; 212 213 if (data->disable_oc) { 214 spin_lock_irqsave(&usbmisc->lock, flags); 215 reg = readl(usbmisc->base + data->index * 4); 216 writel(reg | MX6_BM_OVER_CUR_DIS, 217 usbmisc->base + data->index * 4); 218 spin_unlock_irqrestore(&usbmisc->lock, flags); 219 } 220 221 return 0; 222 } 223 224 static const struct usbmisc_ops imx25_usbmisc_ops = { 225 .init = usbmisc_imx25_init, 226 .post = usbmisc_imx25_post, 227 }; 228 229 static const struct usbmisc_ops imx27_usbmisc_ops = { 230 .init = usbmisc_imx27_init, 231 }; 232 233 static const struct usbmisc_ops imx53_usbmisc_ops = { 234 .init = usbmisc_imx53_init, 235 }; 236 237 static const struct usbmisc_ops imx6q_usbmisc_ops = { 238 .init = usbmisc_imx6q_init, 239 }; 240 241 int imx_usbmisc_init(struct imx_usbmisc_data *data) 242 { 243 if (!usbmisc) 244 return -EPROBE_DEFER; 245 if (!usbmisc->ops->init) 246 return 0; 247 return usbmisc->ops->init(data); 248 } 249 EXPORT_SYMBOL_GPL(imx_usbmisc_init); 250 251 int imx_usbmisc_init_post(struct imx_usbmisc_data *data) 252 { 253 if (!usbmisc) 254 return -EPROBE_DEFER; 255 if (!usbmisc->ops->post) 256 return 0; 257 return usbmisc->ops->post(data); 258 } 259 EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); 260 261 static const struct of_device_id usbmisc_imx_dt_ids[] = { 262 { 263 .compatible = "fsl,imx25-usbmisc", 264 .data = &imx25_usbmisc_ops, 265 }, 266 { 267 .compatible = "fsl,imx35-usbmisc", 268 .data = &imx25_usbmisc_ops, 269 }, 270 { 271 .compatible = "fsl,imx27-usbmisc", 272 .data = &imx27_usbmisc_ops, 273 }, 274 { 275 .compatible = "fsl,imx51-usbmisc", 276 .data = &imx53_usbmisc_ops, 277 }, 278 { 279 .compatible = "fsl,imx53-usbmisc", 280 .data = &imx53_usbmisc_ops, 281 }, 282 { 283 .compatible = "fsl,imx6q-usbmisc", 284 .data = &imx6q_usbmisc_ops, 285 }, 286 { /* sentinel */ } 287 }; 288 MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); 289 290 static int usbmisc_imx_probe(struct platform_device *pdev) 291 { 292 struct resource *res; 293 struct imx_usbmisc *data; 294 int ret; 295 struct of_device_id *tmp_dev; 296 297 if (usbmisc) 298 return -EBUSY; 299 300 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 301 if (!data) 302 return -ENOMEM; 303 304 spin_lock_init(&data->lock); 305 306 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 307 data->base = devm_ioremap_resource(&pdev->dev, res); 308 if (IS_ERR(data->base)) 309 return PTR_ERR(data->base); 310 311 data->clk = devm_clk_get(&pdev->dev, NULL); 312 if (IS_ERR(data->clk)) { 313 dev_err(&pdev->dev, 314 "failed to get clock, err=%ld\n", PTR_ERR(data->clk)); 315 return PTR_ERR(data->clk); 316 } 317 318 ret = clk_prepare_enable(data->clk); 319 if (ret) { 320 dev_err(&pdev->dev, 321 "clk_prepare_enable failed, err=%d\n", ret); 322 return ret; 323 } 324 325 tmp_dev = (struct of_device_id *) 326 of_match_device(usbmisc_imx_dt_ids, &pdev->dev); 327 data->ops = (const struct usbmisc_ops *)tmp_dev->data; 328 usbmisc = data; 329 330 return 0; 331 } 332 333 static int usbmisc_imx_remove(struct platform_device *pdev) 334 { 335 clk_disable_unprepare(usbmisc->clk); 336 usbmisc = NULL; 337 return 0; 338 } 339 340 static struct platform_driver usbmisc_imx_driver = { 341 .probe = usbmisc_imx_probe, 342 .remove = usbmisc_imx_remove, 343 .driver = { 344 .name = "usbmisc_imx", 345 .owner = THIS_MODULE, 346 .of_match_table = usbmisc_imx_dt_ids, 347 }, 348 }; 349 350 module_platform_driver(usbmisc_imx_driver); 351 352 MODULE_ALIAS("platform:usbmisc-imx"); 353 MODULE_LICENSE("GPL v2"); 354 MODULE_DESCRIPTION("driver for imx usb non-core registers"); 355 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 356