Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * OMAP OTG controller driver
0004  *
0005  * Based on code from tahvo-usb.c and isp1301_omap.c drivers.
0006  *
0007  * Copyright (C) 2005-2006 Nokia Corporation
0008  * Copyright (C) 2004 Texas Instruments
0009  * Copyright (C) 2004 David Brownell
0010  */
0011 
0012 #include <linux/io.h>
0013 #include <linux/err.h>
0014 #include <linux/extcon.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/platform_data/usb-omap1.h>
0020 
0021 struct otg_device {
0022     void __iomem            *base;
0023     bool                id;
0024     bool                vbus;
0025     struct extcon_dev       *extcon;
0026     struct notifier_block       vbus_nb;
0027     struct notifier_block       id_nb;
0028 };
0029 
0030 #define OMAP_OTG_CTRL       0x0c
0031 #define OMAP_OTG_ASESSVLD   (1 << 20)
0032 #define OMAP_OTG_BSESSEND   (1 << 19)
0033 #define OMAP_OTG_BSESSVLD   (1 << 18)
0034 #define OMAP_OTG_VBUSVLD    (1 << 17)
0035 #define OMAP_OTG_ID     (1 << 16)
0036 #define OMAP_OTG_XCEIV_OUTPUTS \
0037     (OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \
0038      OMAP_OTG_VBUSVLD  | OMAP_OTG_ID)
0039 
0040 static void omap_otg_ctrl(struct otg_device *otg_dev, u32 outputs)
0041 {
0042     u32 l;
0043 
0044     l = readl(otg_dev->base + OMAP_OTG_CTRL);
0045     l &= ~OMAP_OTG_XCEIV_OUTPUTS;
0046     l |= outputs;
0047     writel(l, otg_dev->base + OMAP_OTG_CTRL);
0048 }
0049 
0050 static void omap_otg_set_mode(struct otg_device *otg_dev)
0051 {
0052     if (!otg_dev->id && otg_dev->vbus)
0053         /* Set B-session valid. */
0054         omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSVLD);
0055     else if (otg_dev->vbus)
0056         /* Set A-session valid. */
0057         omap_otg_ctrl(otg_dev, OMAP_OTG_ASESSVLD);
0058     else if (!otg_dev->id)
0059         /* Set B-session end to indicate no VBUS. */
0060         omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSEND);
0061 }
0062 
0063 static int omap_otg_id_notifier(struct notifier_block *nb,
0064                 unsigned long event, void *ptr)
0065 {
0066     struct otg_device *otg_dev = container_of(nb, struct otg_device, id_nb);
0067 
0068     otg_dev->id = event;
0069     omap_otg_set_mode(otg_dev);
0070 
0071     return NOTIFY_DONE;
0072 }
0073 
0074 static int omap_otg_vbus_notifier(struct notifier_block *nb,
0075                   unsigned long event, void *ptr)
0076 {
0077     struct otg_device *otg_dev = container_of(nb, struct otg_device,
0078                           vbus_nb);
0079 
0080     otg_dev->vbus = event;
0081     omap_otg_set_mode(otg_dev);
0082 
0083     return NOTIFY_DONE;
0084 }
0085 
0086 static int omap_otg_probe(struct platform_device *pdev)
0087 {
0088     const struct omap_usb_config *config = pdev->dev.platform_data;
0089     struct otg_device *otg_dev;
0090     struct extcon_dev *extcon;
0091     int ret;
0092     u32 rev;
0093 
0094     if (!config || !config->extcon)
0095         return -ENODEV;
0096 
0097     extcon = extcon_get_extcon_dev(config->extcon);
0098     if (IS_ERR(extcon))
0099         return PTR_ERR(extcon);
0100 
0101     otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
0102     if (!otg_dev)
0103         return -ENOMEM;
0104 
0105     otg_dev->base = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]);
0106     if (IS_ERR(otg_dev->base))
0107         return PTR_ERR(otg_dev->base);
0108 
0109     otg_dev->extcon = extcon;
0110     otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
0111     otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
0112 
0113     ret = devm_extcon_register_notifier(&pdev->dev, extcon,
0114                     EXTCON_USB_HOST, &otg_dev->id_nb);
0115     if (ret)
0116         return ret;
0117 
0118     ret = devm_extcon_register_notifier(&pdev->dev, extcon,
0119                     EXTCON_USB, &otg_dev->vbus_nb);
0120     if (ret) {
0121         return ret;
0122     }
0123 
0124     otg_dev->id = extcon_get_state(extcon, EXTCON_USB_HOST);
0125     otg_dev->vbus = extcon_get_state(extcon, EXTCON_USB);
0126     omap_otg_set_mode(otg_dev);
0127 
0128     rev = readl(otg_dev->base);
0129 
0130     dev_info(&pdev->dev,
0131          "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n",
0132          (rev >> 4) & 0xf, rev & 0xf, config->extcon, otg_dev->id,
0133          otg_dev->vbus);
0134 
0135     platform_set_drvdata(pdev, otg_dev);
0136 
0137     return 0;
0138 }
0139 
0140 static struct platform_driver omap_otg_driver = {
0141     .probe      = omap_otg_probe,
0142     .driver     = {
0143         .name   = "omap_otg",
0144     },
0145 };
0146 module_platform_driver(omap_otg_driver);
0147 
0148 MODULE_DESCRIPTION("OMAP USB OTG controller driver");
0149 MODULE_LICENSE("GPL");
0150 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");