0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/fsl_devices.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/of_platform.h>
0014 #include <linux/clk.h>
0015 #include <linux/module.h>
0016 #include <linux/dma-mapping.h>
0017
0018 struct fsl_usb2_dev_data {
0019 char *dr_mode;
0020 char *drivers[3];
0021 enum fsl_usb2_operating_modes op_mode;
0022 };
0023
0024 static struct fsl_usb2_dev_data dr_mode_data[] = {
0025 {
0026 .dr_mode = "host",
0027 .drivers = { "fsl-ehci", NULL, NULL, },
0028 .op_mode = FSL_USB2_DR_HOST,
0029 },
0030 {
0031 .dr_mode = "otg",
0032 .drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", },
0033 .op_mode = FSL_USB2_DR_OTG,
0034 },
0035 {
0036 .dr_mode = "peripheral",
0037 .drivers = { "fsl-usb2-udc", NULL, NULL, },
0038 .op_mode = FSL_USB2_DR_DEVICE,
0039 },
0040 };
0041
0042 static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)
0043 {
0044 const unsigned char *prop;
0045 int i;
0046
0047 prop = of_get_property(np, "dr_mode", NULL);
0048 if (prop) {
0049 for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
0050 if (!strcmp(prop, dr_mode_data[i].dr_mode))
0051 return &dr_mode_data[i];
0052 }
0053 }
0054 pr_warn("%pOF: Invalid 'dr_mode' property, fallback to host mode\n",
0055 np);
0056 return &dr_mode_data[0];
0057 }
0058
0059 static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
0060 {
0061 if (!phy_type)
0062 return FSL_USB2_PHY_NONE;
0063 if (!strcasecmp(phy_type, "ulpi"))
0064 return FSL_USB2_PHY_ULPI;
0065 if (!strcasecmp(phy_type, "utmi"))
0066 return FSL_USB2_PHY_UTMI;
0067 if (!strcasecmp(phy_type, "utmi_wide"))
0068 return FSL_USB2_PHY_UTMI_WIDE;
0069 if (!strcasecmp(phy_type, "utmi_dual"))
0070 return FSL_USB2_PHY_UTMI_DUAL;
0071 if (!strcasecmp(phy_type, "serial"))
0072 return FSL_USB2_PHY_SERIAL;
0073
0074 return FSL_USB2_PHY_NONE;
0075 }
0076
0077 static struct platform_device *fsl_usb2_device_register(
0078 struct platform_device *ofdev,
0079 struct fsl_usb2_platform_data *pdata,
0080 const char *name, int id)
0081 {
0082 struct platform_device *pdev;
0083 const struct resource *res = ofdev->resource;
0084 unsigned int num = ofdev->num_resources;
0085 int retval;
0086
0087 pdev = platform_device_alloc(name, id);
0088 if (!pdev) {
0089 retval = -ENOMEM;
0090 goto error;
0091 }
0092
0093 pdev->dev.parent = &ofdev->dev;
0094
0095 pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
0096
0097 if (!pdev->dev.dma_mask) {
0098 pdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
0099 } else {
0100 retval = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
0101 if (retval)
0102 goto error;
0103 }
0104
0105 retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
0106 if (retval)
0107 goto error;
0108
0109 if (num) {
0110 retval = platform_device_add_resources(pdev, res, num);
0111 if (retval)
0112 goto error;
0113 }
0114
0115 pdev->dev.of_node = ofdev->dev.of_node;
0116 pdev->dev.of_node_reused = true;
0117
0118 retval = platform_device_add(pdev);
0119 if (retval)
0120 goto error;
0121
0122 return pdev;
0123
0124 error:
0125 platform_device_put(pdev);
0126 return ERR_PTR(retval);
0127 }
0128
0129 static const struct of_device_id fsl_usb2_mph_dr_of_match[];
0130
0131 static enum fsl_usb2_controller_ver usb_get_ver_info(struct device_node *np)
0132 {
0133 enum fsl_usb2_controller_ver ver = FSL_USB_VER_NONE;
0134
0135
0136
0137
0138
0139
0140
0141
0142 if (of_device_is_compatible(np, "fsl-usb2-dr")) {
0143 if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
0144 ver = FSL_USB_VER_1_6;
0145 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
0146 ver = FSL_USB_VER_2_2;
0147 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4"))
0148 ver = FSL_USB_VER_2_4;
0149 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.5"))
0150 ver = FSL_USB_VER_2_5;
0151 else
0152 ver = FSL_USB_VER_OLD;
0153
0154 if (ver > FSL_USB_VER_NONE)
0155 return ver;
0156 }
0157
0158 if (of_device_is_compatible(np, "fsl,mpc5121-usb2-dr"))
0159 return FSL_USB_VER_OLD;
0160
0161 if (of_device_is_compatible(np, "fsl-usb2-mph")) {
0162 if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
0163 ver = FSL_USB_VER_1_6;
0164 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
0165 ver = FSL_USB_VER_2_2;
0166 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.4"))
0167 ver = FSL_USB_VER_2_4;
0168 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.5"))
0169 ver = FSL_USB_VER_2_5;
0170 else
0171 ver = FSL_USB_VER_OLD;
0172 }
0173
0174 return ver;
0175 }
0176
0177 static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
0178 {
0179 struct device_node *np = ofdev->dev.of_node;
0180 struct platform_device *usb_dev;
0181 struct fsl_usb2_platform_data data, *pdata;
0182 struct fsl_usb2_dev_data *dev_data;
0183 const struct of_device_id *match;
0184 const unsigned char *prop;
0185 static unsigned int idx;
0186 int i;
0187
0188 if (!of_device_is_available(np))
0189 return -ENODEV;
0190
0191 match = of_match_device(fsl_usb2_mph_dr_of_match, &ofdev->dev);
0192 if (!match)
0193 return -ENODEV;
0194
0195 pdata = &data;
0196 if (match->data)
0197 memcpy(pdata, match->data, sizeof(data));
0198 else
0199 memset(pdata, 0, sizeof(data));
0200
0201 dev_data = get_dr_mode_data(np);
0202
0203 if (of_device_is_compatible(np, "fsl-usb2-mph")) {
0204 if (of_get_property(np, "port0", NULL))
0205 pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
0206
0207 if (of_get_property(np, "port1", NULL))
0208 pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
0209
0210 pdata->operating_mode = FSL_USB2_MPH_HOST;
0211 } else {
0212 if (of_get_property(np, "fsl,invert-drvvbus", NULL))
0213 pdata->invert_drvvbus = 1;
0214
0215 if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
0216 pdata->invert_pwr_fault = 1;
0217
0218
0219 pdata->operating_mode = dev_data->op_mode;
0220 }
0221
0222 prop = of_get_property(np, "phy_type", NULL);
0223 pdata->phy_mode = determine_usb_phy(prop);
0224 pdata->controller_ver = usb_get_ver_info(np);
0225
0226
0227 pdata->has_fsl_erratum_a007792 =
0228 of_property_read_bool(np, "fsl,usb-erratum-a007792");
0229 pdata->has_fsl_erratum_a005275 =
0230 of_property_read_bool(np, "fsl,usb-erratum-a005275");
0231 pdata->has_fsl_erratum_a005697 =
0232 of_property_read_bool(np, "fsl,usb_erratum-a005697");
0233 pdata->has_fsl_erratum_a006918 =
0234 of_property_read_bool(np, "fsl,usb_erratum-a006918");
0235 pdata->has_fsl_erratum_14 =
0236 of_property_read_bool(np, "fsl,usb_erratum-14");
0237
0238
0239
0240
0241
0242 pdata->check_phy_clk_valid =
0243 of_property_read_bool(np, "phy-clk-valid");
0244
0245 if (pdata->have_sysif_regs) {
0246 if (pdata->controller_ver == FSL_USB_VER_NONE) {
0247 dev_warn(&ofdev->dev, "Could not get controller version\n");
0248 return -ENODEV;
0249 }
0250 }
0251
0252 for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
0253 if (!dev_data->drivers[i])
0254 continue;
0255 usb_dev = fsl_usb2_device_register(ofdev, pdata,
0256 dev_data->drivers[i], idx);
0257 if (IS_ERR(usb_dev)) {
0258 dev_err(&ofdev->dev, "Can't register usb device\n");
0259 return PTR_ERR(usb_dev);
0260 }
0261 }
0262 idx++;
0263 return 0;
0264 }
0265
0266 static int __unregister_subdev(struct device *dev, void *d)
0267 {
0268 platform_device_unregister(to_platform_device(dev));
0269 return 0;
0270 }
0271
0272 static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
0273 {
0274 device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
0275 return 0;
0276 }
0277
0278 #ifdef CONFIG_PPC_MPC512x
0279
0280 #define USBGENCTRL 0x200
0281 #define GC_WU_INT_CLR (1 << 5)
0282 #define GC_ULPI_SEL (1 << 4)
0283 #define GC_PPP (1 << 3)
0284 #define GC_PFP (1 << 2)
0285 #define GC_WU_ULPI_EN (1 << 1)
0286 #define GC_WU_IE (1 << 1)
0287
0288 #define ISIPHYCTRL 0x204
0289 #define PHYCTRL_PHYE (1 << 4)
0290 #define PHYCTRL_BSENH (1 << 3)
0291 #define PHYCTRL_BSEN (1 << 2)
0292 #define PHYCTRL_LSFE (1 << 1)
0293 #define PHYCTRL_PXE (1 << 0)
0294
0295 int fsl_usb2_mpc5121_init(struct platform_device *pdev)
0296 {
0297 struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
0298 struct clk *clk;
0299 int err;
0300
0301 clk = devm_clk_get(pdev->dev.parent, "ipg");
0302 if (IS_ERR(clk)) {
0303 dev_err(&pdev->dev, "failed to get clk\n");
0304 return PTR_ERR(clk);
0305 }
0306 err = clk_prepare_enable(clk);
0307 if (err) {
0308 dev_err(&pdev->dev, "failed to enable clk\n");
0309 return err;
0310 }
0311 pdata->clk = clk;
0312
0313 if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
0314 u32 reg = 0;
0315
0316 if (pdata->invert_drvvbus)
0317 reg |= GC_PPP;
0318
0319 if (pdata->invert_pwr_fault)
0320 reg |= GC_PFP;
0321
0322 out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
0323 out_be32(pdata->regs + USBGENCTRL, reg);
0324 }
0325 return 0;
0326 }
0327
0328 static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
0329 {
0330 struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
0331
0332 pdata->regs = NULL;
0333
0334 if (pdata->clk)
0335 clk_disable_unprepare(pdata->clk);
0336 }
0337
0338 static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
0339 .big_endian_desc = 1,
0340 .big_endian_mmio = 1,
0341 .es = 1,
0342 .have_sysif_regs = 0,
0343 .le_setup_buf = 1,
0344 .init = fsl_usb2_mpc5121_init,
0345 .exit = fsl_usb2_mpc5121_exit,
0346 };
0347 #endif
0348
0349 static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = {
0350 .have_sysif_regs = 1,
0351 };
0352
0353 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
0354 { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, },
0355 { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, },
0356 #ifdef CONFIG_PPC_MPC512x
0357 { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
0358 #endif
0359 {},
0360 };
0361 MODULE_DEVICE_TABLE(of, fsl_usb2_mph_dr_of_match);
0362
0363 static struct platform_driver fsl_usb2_mph_dr_driver = {
0364 .driver = {
0365 .name = "fsl-usb2-mph-dr",
0366 .of_match_table = fsl_usb2_mph_dr_of_match,
0367 },
0368 .probe = fsl_usb2_mph_dr_of_probe,
0369 .remove = fsl_usb2_mph_dr_of_remove,
0370 };
0371
0372 module_platform_driver(fsl_usb2_mph_dr_driver);
0373
0374 MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
0375 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
0376 MODULE_LICENSE("GPL");