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 MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 25 #define MX53_USB_UH2_CTRL_OFFSET 0x14 26 #define MX53_USB_UH3_CTRL_OFFSET 0x18 27 #define MX53_BM_OVER_CUR_DIS_H1 BIT(5) 28 #define MX53_BM_OVER_CUR_DIS_OTG BIT(8) 29 #define MX53_BM_OVER_CUR_DIS_UHx BIT(30) 30 31 #define MX6_BM_OVER_CUR_DIS BIT(7) 32 33 struct usbmisc_ops { 34 /* It's called once when probe a usb device */ 35 int (*init)(struct imx_usbmisc_data *data); 36 /* It's called once after adding a usb device */ 37 int (*post)(struct imx_usbmisc_data *data); 38 }; 39 40 struct imx_usbmisc { 41 void __iomem *base; 42 spinlock_t lock; 43 struct clk *clk; 44 const struct usbmisc_ops *ops; 45 }; 46 47 static struct imx_usbmisc *usbmisc; 48 49 static int usbmisc_imx25_post(struct imx_usbmisc_data *data) 50 { 51 void __iomem *reg; 52 unsigned long flags; 53 u32 val; 54 55 if (data->index > 2) 56 return -EINVAL; 57 58 reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; 59 60 if (data->evdo) { 61 spin_lock_irqsave(&usbmisc->lock, flags); 62 val = readl(reg); 63 writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); 64 spin_unlock_irqrestore(&usbmisc->lock, flags); 65 usleep_range(5000, 10000); /* needed to stabilize voltage */ 66 } 67 68 return 0; 69 } 70 71 static int usbmisc_imx53_init(struct imx_usbmisc_data *data) 72 { 73 void __iomem *reg = NULL; 74 unsigned long flags; 75 u32 val = 0; 76 77 if (data->index > 3) 78 return -EINVAL; 79 80 if (data->disable_oc) { 81 spin_lock_irqsave(&usbmisc->lock, flags); 82 switch (data->index) { 83 case 0: 84 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 85 val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; 86 break; 87 case 1: 88 reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; 89 val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; 90 break; 91 case 2: 92 reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; 93 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 94 break; 95 case 3: 96 reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; 97 val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; 98 break; 99 } 100 if (reg && val) 101 writel(val, reg); 102 spin_unlock_irqrestore(&usbmisc->lock, flags); 103 } 104 105 return 0; 106 } 107 108 static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) 109 { 110 unsigned long flags; 111 u32 reg; 112 113 if (data->index > 3) 114 return -EINVAL; 115 116 if (data->disable_oc) { 117 spin_lock_irqsave(&usbmisc->lock, flags); 118 reg = readl(usbmisc->base + data->index * 4); 119 writel(reg | MX6_BM_OVER_CUR_DIS, 120 usbmisc->base + data->index * 4); 121 spin_unlock_irqrestore(&usbmisc->lock, flags); 122 } 123 124 return 0; 125 } 126 127 static const struct usbmisc_ops imx25_usbmisc_ops = { 128 .post = usbmisc_imx25_post, 129 }; 130 131 static const struct usbmisc_ops imx53_usbmisc_ops = { 132 .init = usbmisc_imx53_init, 133 }; 134 135 static const struct usbmisc_ops imx6q_usbmisc_ops = { 136 .init = usbmisc_imx6q_init, 137 }; 138 139 int imx_usbmisc_init(struct imx_usbmisc_data *data) 140 { 141 if (!usbmisc) 142 return -EPROBE_DEFER; 143 if (!usbmisc->ops->init) 144 return 0; 145 return usbmisc->ops->init(data); 146 } 147 EXPORT_SYMBOL_GPL(imx_usbmisc_init); 148 149 int imx_usbmisc_init_post(struct imx_usbmisc_data *data) 150 { 151 if (!usbmisc) 152 return -EPROBE_DEFER; 153 if (!usbmisc->ops->post) 154 return 0; 155 return usbmisc->ops->post(data); 156 } 157 EXPORT_SYMBOL_GPL(imx_usbmisc_init_post); 158 159 static const struct of_device_id usbmisc_imx_dt_ids[] = { 160 { 161 .compatible = "fsl,imx25-usbmisc", 162 .data = &imx25_usbmisc_ops, 163 }, 164 { 165 .compatible = "fsl,imx53-usbmisc", 166 .data = &imx53_usbmisc_ops, 167 }, 168 { 169 .compatible = "fsl,imx6q-usbmisc", 170 .data = &imx6q_usbmisc_ops, 171 }, 172 { /* sentinel */ } 173 }; 174 MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); 175 176 static int usbmisc_imx_probe(struct platform_device *pdev) 177 { 178 struct resource *res; 179 struct imx_usbmisc *data; 180 int ret; 181 struct of_device_id *tmp_dev; 182 183 if (usbmisc) 184 return -EBUSY; 185 186 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 187 if (!data) 188 return -ENOMEM; 189 190 spin_lock_init(&data->lock); 191 192 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 193 data->base = devm_ioremap_resource(&pdev->dev, res); 194 if (IS_ERR(data->base)) 195 return PTR_ERR(data->base); 196 197 data->clk = devm_clk_get(&pdev->dev, NULL); 198 if (IS_ERR(data->clk)) { 199 dev_err(&pdev->dev, 200 "failed to get clock, err=%ld\n", PTR_ERR(data->clk)); 201 return PTR_ERR(data->clk); 202 } 203 204 ret = clk_prepare_enable(data->clk); 205 if (ret) { 206 dev_err(&pdev->dev, 207 "clk_prepare_enable failed, err=%d\n", ret); 208 return ret; 209 } 210 211 tmp_dev = (struct of_device_id *) 212 of_match_device(usbmisc_imx_dt_ids, &pdev->dev); 213 data->ops = (const struct usbmisc_ops *)tmp_dev->data; 214 usbmisc = data; 215 216 return 0; 217 } 218 219 static int usbmisc_imx_remove(struct platform_device *pdev) 220 { 221 clk_disable_unprepare(usbmisc->clk); 222 usbmisc = NULL; 223 return 0; 224 } 225 226 static struct platform_driver usbmisc_imx_driver = { 227 .probe = usbmisc_imx_probe, 228 .remove = usbmisc_imx_remove, 229 .driver = { 230 .name = "usbmisc_imx", 231 .owner = THIS_MODULE, 232 .of_match_table = usbmisc_imx_dt_ids, 233 }, 234 }; 235 236 module_platform_driver(usbmisc_imx_driver); 237 238 MODULE_ALIAS("platform:usbmisc-imx"); 239 MODULE_LICENSE("GPL v2"); 240 MODULE_DESCRIPTION("driver for imx usb non-core registers"); 241 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); 242