root/drivers/usb/host/fsl-mph-dr-of.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_dr_mode_data
  2. determine_usb_phy
  3. fsl_usb2_device_register
  4. usb_get_ver_info
  5. fsl_usb2_mph_dr_of_probe
  6. __unregister_subdev
  7. fsl_usb2_mph_dr_of_remove
  8. fsl_usb2_mpc5121_init
  9. fsl_usb2_mpc5121_exit

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Setup platform devices needed by the Freescale multi-port host
   4  * and/or dual-role USB controller modules based on the description
   5  * in flat device tree.
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/platform_device.h>
  10 #include <linux/fsl_devices.h>
  11 #include <linux/err.h>
  12 #include <linux/io.h>
  13 #include <linux/of_platform.h>
  14 #include <linux/clk.h>
  15 #include <linux/module.h>
  16 #include <linux/dma-mapping.h>
  17 
  18 struct fsl_usb2_dev_data {
  19         char *dr_mode;          /* controller mode */
  20         char *drivers[3];       /* drivers to instantiate for this mode */
  21         enum fsl_usb2_operating_modes op_mode;  /* operating mode */
  22 };
  23 
  24 static struct fsl_usb2_dev_data dr_mode_data[] = {
  25         {
  26                 .dr_mode = "host",
  27                 .drivers = { "fsl-ehci", NULL, NULL, },
  28                 .op_mode = FSL_USB2_DR_HOST,
  29         },
  30         {
  31                 .dr_mode = "otg",
  32                 .drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", },
  33                 .op_mode = FSL_USB2_DR_OTG,
  34         },
  35         {
  36                 .dr_mode = "peripheral",
  37                 .drivers = { "fsl-usb2-udc", NULL, NULL, },
  38                 .op_mode = FSL_USB2_DR_DEVICE,
  39         },
  40 };
  41 
  42 static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)
  43 {
  44         const unsigned char *prop;
  45         int i;
  46 
  47         prop = of_get_property(np, "dr_mode", NULL);
  48         if (prop) {
  49                 for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
  50                         if (!strcmp(prop, dr_mode_data[i].dr_mode))
  51                                 return &dr_mode_data[i];
  52                 }
  53         }
  54         pr_warn("%pOF: Invalid 'dr_mode' property, fallback to host mode\n",
  55                 np);
  56         return &dr_mode_data[0]; /* mode not specified, use host */
  57 }
  58 
  59 static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
  60 {
  61         if (!phy_type)
  62                 return FSL_USB2_PHY_NONE;
  63         if (!strcasecmp(phy_type, "ulpi"))
  64                 return FSL_USB2_PHY_ULPI;
  65         if (!strcasecmp(phy_type, "utmi"))
  66                 return FSL_USB2_PHY_UTMI;
  67         if (!strcasecmp(phy_type, "utmi_wide"))
  68                 return FSL_USB2_PHY_UTMI_WIDE;
  69         if (!strcasecmp(phy_type, "utmi_dual"))
  70                 return FSL_USB2_PHY_UTMI_DUAL;
  71         if (!strcasecmp(phy_type, "serial"))
  72                 return FSL_USB2_PHY_SERIAL;
  73 
  74         return FSL_USB2_PHY_NONE;
  75 }
  76 
  77 static struct platform_device *fsl_usb2_device_register(
  78                                         struct platform_device *ofdev,
  79                                         struct fsl_usb2_platform_data *pdata,
  80                                         const char *name, int id)
  81 {
  82         struct platform_device *pdev;
  83         const struct resource *res = ofdev->resource;
  84         unsigned int num = ofdev->num_resources;
  85         int retval;
  86 
  87         pdev = platform_device_alloc(name, id);
  88         if (!pdev) {
  89                 retval = -ENOMEM;
  90                 goto error;
  91         }
  92 
  93         pdev->dev.parent = &ofdev->dev;
  94 
  95         pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
  96 
  97         if (!pdev->dev.dma_mask)
  98                 pdev->dev.dma_mask = &ofdev->dev.coherent_dma_mask;
  99         else
 100                 dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
 101 
 102         retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
 103         if (retval)
 104                 goto error;
 105 
 106         if (num) {
 107                 retval = platform_device_add_resources(pdev, res, num);
 108                 if (retval)
 109                         goto error;
 110         }
 111 
 112         retval = platform_device_add(pdev);
 113         if (retval)
 114                 goto error;
 115 
 116         return pdev;
 117 
 118 error:
 119         platform_device_put(pdev);
 120         return ERR_PTR(retval);
 121 }
 122 
 123 static const struct of_device_id fsl_usb2_mph_dr_of_match[];
 124 
 125 static enum fsl_usb2_controller_ver usb_get_ver_info(struct device_node *np)
 126 {
 127         enum fsl_usb2_controller_ver ver = FSL_USB_VER_NONE;
 128 
 129         /*
 130          * returns 1 for usb controller version 1.6
 131          * returns 2 for usb controller version 2.2
 132          * returns 3 for usb controller version 2.4
 133          * returns 4 for usb controller version 2.5
 134          * returns 0 otherwise
 135          */
 136         if (of_device_is_compatible(np, "fsl-usb2-dr")) {
 137                 if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
 138                         ver = FSL_USB_VER_1_6;
 139                 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
 140                         ver = FSL_USB_VER_2_2;
 141                 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.4"))
 142                         ver = FSL_USB_VER_2_4;
 143                 else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.5"))
 144                         ver = FSL_USB_VER_2_5;
 145                 else /* for previous controller versions */
 146                         ver = FSL_USB_VER_OLD;
 147 
 148                 if (ver > FSL_USB_VER_NONE)
 149                         return ver;
 150         }
 151 
 152         if (of_device_is_compatible(np, "fsl,mpc5121-usb2-dr"))
 153                 return FSL_USB_VER_OLD;
 154 
 155         if (of_device_is_compatible(np, "fsl-usb2-mph")) {
 156                 if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
 157                         ver = FSL_USB_VER_1_6;
 158                 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
 159                         ver = FSL_USB_VER_2_2;
 160                 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.4"))
 161                         ver = FSL_USB_VER_2_4;
 162                 else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.5"))
 163                         ver = FSL_USB_VER_2_5;
 164                 else /* for previous controller versions */
 165                         ver = FSL_USB_VER_OLD;
 166         }
 167 
 168         return ver;
 169 }
 170 
 171 static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
 172 {
 173         struct device_node *np = ofdev->dev.of_node;
 174         struct platform_device *usb_dev;
 175         struct fsl_usb2_platform_data data, *pdata;
 176         struct fsl_usb2_dev_data *dev_data;
 177         const struct of_device_id *match;
 178         const unsigned char *prop;
 179         static unsigned int idx;
 180         int i;
 181 
 182         if (!of_device_is_available(np))
 183                 return -ENODEV;
 184 
 185         match = of_match_device(fsl_usb2_mph_dr_of_match, &ofdev->dev);
 186         if (!match)
 187                 return -ENODEV;
 188 
 189         pdata = &data;
 190         if (match->data)
 191                 memcpy(pdata, match->data, sizeof(data));
 192         else
 193                 memset(pdata, 0, sizeof(data));
 194 
 195         dev_data = get_dr_mode_data(np);
 196 
 197         if (of_device_is_compatible(np, "fsl-usb2-mph")) {
 198                 if (of_get_property(np, "port0", NULL))
 199                         pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
 200 
 201                 if (of_get_property(np, "port1", NULL))
 202                         pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
 203 
 204                 pdata->operating_mode = FSL_USB2_MPH_HOST;
 205         } else {
 206                 if (of_get_property(np, "fsl,invert-drvvbus", NULL))
 207                         pdata->invert_drvvbus = 1;
 208 
 209                 if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
 210                         pdata->invert_pwr_fault = 1;
 211 
 212                 /* setup mode selected in the device tree */
 213                 pdata->operating_mode = dev_data->op_mode;
 214         }
 215 
 216         prop = of_get_property(np, "phy_type", NULL);
 217         pdata->phy_mode = determine_usb_phy(prop);
 218         pdata->controller_ver = usb_get_ver_info(np);
 219 
 220         /* Activate Erratum by reading property in device tree */
 221         pdata->has_fsl_erratum_a007792 =
 222                 of_property_read_bool(np, "fsl,usb-erratum-a007792");
 223         pdata->has_fsl_erratum_a005275 =
 224                 of_property_read_bool(np, "fsl,usb-erratum-a005275");
 225         pdata->has_fsl_erratum_a005697 =
 226                 of_property_read_bool(np, "fsl,usb_erratum-a005697");
 227         pdata->has_fsl_erratum_a006918 =
 228                 of_property_read_bool(np, "fsl,usb_erratum-a006918");
 229         pdata->has_fsl_erratum_14 =
 230                 of_property_read_bool(np, "fsl,usb_erratum-14");
 231 
 232         /*
 233          * Determine whether phy_clk_valid needs to be checked
 234          * by reading property in device tree
 235          */
 236         pdata->check_phy_clk_valid =
 237                 of_property_read_bool(np, "phy-clk-valid");
 238 
 239         if (pdata->have_sysif_regs) {
 240                 if (pdata->controller_ver == FSL_USB_VER_NONE) {
 241                         dev_warn(&ofdev->dev, "Could not get controller version\n");
 242                         return -ENODEV;
 243                 }
 244         }
 245 
 246         for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
 247                 if (!dev_data->drivers[i])
 248                         continue;
 249                 usb_dev = fsl_usb2_device_register(ofdev, pdata,
 250                                         dev_data->drivers[i], idx);
 251                 if (IS_ERR(usb_dev)) {
 252                         dev_err(&ofdev->dev, "Can't register usb device\n");
 253                         return PTR_ERR(usb_dev);
 254                 }
 255         }
 256         idx++;
 257         return 0;
 258 }
 259 
 260 static int __unregister_subdev(struct device *dev, void *d)
 261 {
 262         platform_device_unregister(to_platform_device(dev));
 263         return 0;
 264 }
 265 
 266 static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
 267 {
 268         device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
 269         return 0;
 270 }
 271 
 272 #ifdef CONFIG_PPC_MPC512x
 273 
 274 #define USBGENCTRL              0x200           /* NOTE: big endian */
 275 #define GC_WU_INT_CLR           (1 << 5)        /* Wakeup int clear */
 276 #define GC_ULPI_SEL             (1 << 4)        /* ULPI i/f select (usb0 only)*/
 277 #define GC_PPP                  (1 << 3)        /* Inv. Port Power Polarity */
 278 #define GC_PFP                  (1 << 2)        /* Inv. Power Fault Polarity */
 279 #define GC_WU_ULPI_EN           (1 << 1)        /* Wakeup on ULPI event */
 280 #define GC_WU_IE                (1 << 1)        /* Wakeup interrupt enable */
 281 
 282 #define ISIPHYCTRL              0x204           /* NOTE: big endian */
 283 #define PHYCTRL_PHYE            (1 << 4)        /* On-chip UTMI PHY enable */
 284 #define PHYCTRL_BSENH           (1 << 3)        /* Bit Stuff Enable High */
 285 #define PHYCTRL_BSEN            (1 << 2)        /* Bit Stuff Enable */
 286 #define PHYCTRL_LSFE            (1 << 1)        /* Line State Filter Enable */
 287 #define PHYCTRL_PXE             (1 << 0)        /* PHY oscillator enable */
 288 
 289 int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 290 {
 291         struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 292         struct clk *clk;
 293         int err;
 294 
 295         clk = devm_clk_get(pdev->dev.parent, "ipg");
 296         if (IS_ERR(clk)) {
 297                 dev_err(&pdev->dev, "failed to get clk\n");
 298                 return PTR_ERR(clk);
 299         }
 300         err = clk_prepare_enable(clk);
 301         if (err) {
 302                 dev_err(&pdev->dev, "failed to enable clk\n");
 303                 return err;
 304         }
 305         pdata->clk = clk;
 306 
 307         if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
 308                 u32 reg = 0;
 309 
 310                 if (pdata->invert_drvvbus)
 311                         reg |= GC_PPP;
 312 
 313                 if (pdata->invert_pwr_fault)
 314                         reg |= GC_PFP;
 315 
 316                 out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
 317                 out_be32(pdata->regs + USBGENCTRL, reg);
 318         }
 319         return 0;
 320 }
 321 
 322 static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 323 {
 324         struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 325 
 326         pdata->regs = NULL;
 327 
 328         if (pdata->clk)
 329                 clk_disable_unprepare(pdata->clk);
 330 }
 331 
 332 static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
 333         .big_endian_desc = 1,
 334         .big_endian_mmio = 1,
 335         .es = 1,
 336         .have_sysif_regs = 0,
 337         .le_setup_buf = 1,
 338         .init = fsl_usb2_mpc5121_init,
 339         .exit = fsl_usb2_mpc5121_exit,
 340 };
 341 #endif /* CONFIG_PPC_MPC512x */
 342 
 343 static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = {
 344         .have_sysif_regs = 1,
 345 };
 346 
 347 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
 348         { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, },
 349         { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, },
 350 #ifdef CONFIG_PPC_MPC512x
 351         { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
 352 #endif
 353         {},
 354 };
 355 MODULE_DEVICE_TABLE(of, fsl_usb2_mph_dr_of_match);
 356 
 357 static struct platform_driver fsl_usb2_mph_dr_driver = {
 358         .driver = {
 359                 .name = "fsl-usb2-mph-dr",
 360                 .of_match_table = fsl_usb2_mph_dr_of_match,
 361         },
 362         .probe  = fsl_usb2_mph_dr_of_probe,
 363         .remove = fsl_usb2_mph_dr_of_remove,
 364 };
 365 
 366 module_platform_driver(fsl_usb2_mph_dr_driver);
 367 
 368 MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
 369 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
 370 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */