root/drivers/usb/phy/phy-omap-otg.c

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

DEFINITIONS

This source file includes following definitions.
  1. omap_otg_ctrl
  2. omap_otg_set_mode
  3. omap_otg_id_notifier
  4. omap_otg_vbus_notifier
  5. omap_otg_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * OMAP OTG controller driver
   4  *
   5  * Based on code from tahvo-usb.c and isp1301_omap.c drivers.
   6  *
   7  * Copyright (C) 2005-2006 Nokia Corporation
   8  * Copyright (C) 2004 Texas Instruments
   9  * Copyright (C) 2004 David Brownell
  10  */
  11 
  12 #include <linux/io.h>
  13 #include <linux/err.h>
  14 #include <linux/extcon.h>
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/platform_device.h>
  19 #include <linux/platform_data/usb-omap1.h>
  20 
  21 struct otg_device {
  22         void __iomem                    *base;
  23         bool                            id;
  24         bool                            vbus;
  25         struct extcon_dev               *extcon;
  26         struct notifier_block           vbus_nb;
  27         struct notifier_block           id_nb;
  28 };
  29 
  30 #define OMAP_OTG_CTRL           0x0c
  31 #define OMAP_OTG_ASESSVLD       (1 << 20)
  32 #define OMAP_OTG_BSESSEND       (1 << 19)
  33 #define OMAP_OTG_BSESSVLD       (1 << 18)
  34 #define OMAP_OTG_VBUSVLD        (1 << 17)
  35 #define OMAP_OTG_ID             (1 << 16)
  36 #define OMAP_OTG_XCEIV_OUTPUTS \
  37         (OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \
  38          OMAP_OTG_VBUSVLD  | OMAP_OTG_ID)
  39 
  40 static void omap_otg_ctrl(struct otg_device *otg_dev, u32 outputs)
  41 {
  42         u32 l;
  43 
  44         l = readl(otg_dev->base + OMAP_OTG_CTRL);
  45         l &= ~OMAP_OTG_XCEIV_OUTPUTS;
  46         l |= outputs;
  47         writel(l, otg_dev->base + OMAP_OTG_CTRL);
  48 }
  49 
  50 static void omap_otg_set_mode(struct otg_device *otg_dev)
  51 {
  52         if (!otg_dev->id && otg_dev->vbus)
  53                 /* Set B-session valid. */
  54                 omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSVLD);
  55         else if (otg_dev->vbus)
  56                 /* Set A-session valid. */
  57                 omap_otg_ctrl(otg_dev, OMAP_OTG_ASESSVLD);
  58         else if (!otg_dev->id)
  59                 /* Set B-session end to indicate no VBUS. */
  60                 omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSEND);
  61 }
  62 
  63 static int omap_otg_id_notifier(struct notifier_block *nb,
  64                                 unsigned long event, void *ptr)
  65 {
  66         struct otg_device *otg_dev = container_of(nb, struct otg_device, id_nb);
  67 
  68         otg_dev->id = event;
  69         omap_otg_set_mode(otg_dev);
  70 
  71         return NOTIFY_DONE;
  72 }
  73 
  74 static int omap_otg_vbus_notifier(struct notifier_block *nb,
  75                                   unsigned long event, void *ptr)
  76 {
  77         struct otg_device *otg_dev = container_of(nb, struct otg_device,
  78                                                   vbus_nb);
  79 
  80         otg_dev->vbus = event;
  81         omap_otg_set_mode(otg_dev);
  82 
  83         return NOTIFY_DONE;
  84 }
  85 
  86 static int omap_otg_probe(struct platform_device *pdev)
  87 {
  88         const struct omap_usb_config *config = pdev->dev.platform_data;
  89         struct otg_device *otg_dev;
  90         struct extcon_dev *extcon;
  91         int ret;
  92         u32 rev;
  93 
  94         if (!config || !config->extcon)
  95                 return -ENODEV;
  96 
  97         extcon = extcon_get_extcon_dev(config->extcon);
  98         if (!extcon)
  99                 return -EPROBE_DEFER;
 100 
 101         otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
 102         if (!otg_dev)
 103                 return -ENOMEM;
 104 
 105         otg_dev->base = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
 106         if (IS_ERR(otg_dev->base))
 107                 return PTR_ERR(otg_dev->base);
 108 
 109         otg_dev->extcon = extcon;
 110         otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
 111         otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
 112 
 113         ret = devm_extcon_register_notifier(&pdev->dev, extcon,
 114                                         EXTCON_USB_HOST, &otg_dev->id_nb);
 115         if (ret)
 116                 return ret;
 117 
 118         ret = devm_extcon_register_notifier(&pdev->dev, extcon,
 119                                         EXTCON_USB, &otg_dev->vbus_nb);
 120         if (ret) {
 121                 return ret;
 122         }
 123 
 124         otg_dev->id = extcon_get_state(extcon, EXTCON_USB_HOST);
 125         otg_dev->vbus = extcon_get_state(extcon, EXTCON_USB);
 126         omap_otg_set_mode(otg_dev);
 127 
 128         rev = readl(otg_dev->base);
 129 
 130         dev_info(&pdev->dev,
 131                  "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n",
 132                  (rev >> 4) & 0xf, rev & 0xf, config->extcon, otg_dev->id,
 133                  otg_dev->vbus);
 134 
 135         platform_set_drvdata(pdev, otg_dev);
 136 
 137         return 0;
 138 }
 139 
 140 static struct platform_driver omap_otg_driver = {
 141         .probe          = omap_otg_probe,
 142         .driver         = {
 143                 .name   = "omap_otg",
 144         },
 145 };
 146 module_platform_driver(omap_otg_driver);
 147 
 148 MODULE_DESCRIPTION("OMAP USB OTG controller driver");
 149 MODULE_LICENSE("GPL");
 150 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");

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