linux/drivers/mfd/omap-usb-tll.c
<<
>>
Prefs
   1/**
   2 * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI
   3 *
   4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
   5 * Author: Keshava Munegowda <keshava_mgowda@ti.com>
   6 *
   7 * This program is free software: you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2  of
   9 * the License as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/types.h>
  22#include <linux/slab.h>
  23#include <linux/spinlock.h>
  24#include <linux/platform_device.h>
  25#include <linux/clk.h>
  26#include <linux/io.h>
  27#include <linux/err.h>
  28#include <linux/pm_runtime.h>
  29#include <linux/platform_data/usb-omap.h>
  30
  31#define USBTLL_DRIVER_NAME      "usbhs_tll"
  32
  33/* TLL Register Set */
  34#define OMAP_USBTLL_REVISION                            (0x00)
  35#define OMAP_USBTLL_SYSCONFIG                           (0x10)
  36#define OMAP_USBTLL_SYSCONFIG_CACTIVITY                 (1 << 8)
  37#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE                 (1 << 3)
  38#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP                 (1 << 2)
  39#define OMAP_USBTLL_SYSCONFIG_SOFTRESET                 (1 << 1)
  40#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE                  (1 << 0)
  41
  42#define OMAP_USBTLL_SYSSTATUS                           (0x14)
  43#define OMAP_USBTLL_SYSSTATUS_RESETDONE                 (1 << 0)
  44
  45#define OMAP_USBTLL_IRQSTATUS                           (0x18)
  46#define OMAP_USBTLL_IRQENABLE                           (0x1C)
  47
  48#define OMAP_TLL_SHARED_CONF                            (0x30)
  49#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN             (1 << 6)
  50#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN            (1 << 5)
  51#define OMAP_TLL_SHARED_CONF_USB_DIVRATION              (1 << 2)
  52#define OMAP_TLL_SHARED_CONF_FCLK_REQ                   (1 << 1)
  53#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON                 (1 << 0)
  54
  55#define OMAP_TLL_CHANNEL_CONF(num)                      (0x040 + 0x004 * num)
  56#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT            24
  57#define OMAP_TLL_CHANNEL_CONF_DRVVBUS                   (1 << 16)
  58#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS                  (1 << 15)
  59#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF            (1 << 11)
  60#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE         (1 << 10)
  61#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE              (1 << 9)
  62#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE               (1 << 8)
  63#define OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI     (2 << 1)
  64#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS             (1 << 1)
  65#define OMAP_TLL_CHANNEL_CONF_CHANEN                    (1 << 0)
  66
  67#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0              0x0
  68#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM                0x1
  69#define OMAP_TLL_FSLSMODE_3PIN_PHY                      0x2
  70#define OMAP_TLL_FSLSMODE_4PIN_PHY                      0x3
  71#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0              0x4
  72#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM                0x5
  73#define OMAP_TLL_FSLSMODE_3PIN_TLL                      0x6
  74#define OMAP_TLL_FSLSMODE_4PIN_TLL                      0x7
  75#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0              0xA
  76#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM                0xB
  77
  78#define OMAP_TLL_ULPI_FUNCTION_CTRL(num)                (0x804 + 0x100 * num)
  79#define OMAP_TLL_ULPI_INTERFACE_CTRL(num)               (0x807 + 0x100 * num)
  80#define OMAP_TLL_ULPI_OTG_CTRL(num)                     (0x80A + 0x100 * num)
  81#define OMAP_TLL_ULPI_INT_EN_RISE(num)                  (0x80D + 0x100 * num)
  82#define OMAP_TLL_ULPI_INT_EN_FALL(num)                  (0x810 + 0x100 * num)
  83#define OMAP_TLL_ULPI_INT_STATUS(num)                   (0x813 + 0x100 * num)
  84#define OMAP_TLL_ULPI_INT_LATCH(num)                    (0x814 + 0x100 * num)
  85#define OMAP_TLL_ULPI_DEBUG(num)                        (0x815 + 0x100 * num)
  86#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num)             (0x816 + 0x100 * num)
  87
  88#define OMAP_REV2_TLL_CHANNEL_COUNT                     2
  89#define OMAP_TLL_CHANNEL_COUNT                          3
  90#define OMAP_TLL_CHANNEL_1_EN_MASK                      (1 << 0)
  91#define OMAP_TLL_CHANNEL_2_EN_MASK                      (1 << 1)
  92#define OMAP_TLL_CHANNEL_3_EN_MASK                      (1 << 2)
  93
  94/* Values of USBTLL_REVISION - Note: these are not given in the TRM */
  95#define OMAP_USBTLL_REV1                0x00000015      /* OMAP3 */
  96#define OMAP_USBTLL_REV2                0x00000018      /* OMAP 3630 */
  97#define OMAP_USBTLL_REV3                0x00000004      /* OMAP4 */
  98#define OMAP_USBTLL_REV4                0x00000006      /* OMAP5 */
  99
 100#define is_ehci_tll_mode(x)     (x == OMAP_EHCI_PORT_MODE_TLL)
 101
 102/* only PHY and UNUSED modes don't need TLL */
 103#define omap_usb_mode_needs_tll(x)      ((x) != OMAP_USBHS_PORT_MODE_UNUSED &&\
 104                                         (x) != OMAP_EHCI_PORT_MODE_PHY)
 105
 106struct usbtll_omap {
 107        int                                     nch;    /* num. of channels */
 108        struct usbhs_omap_platform_data         *pdata;
 109        struct clk                              **ch_clk;
 110};
 111
 112/*-------------------------------------------------------------------------*/
 113
 114static const char usbtll_driver_name[] = USBTLL_DRIVER_NAME;
 115static struct device    *tll_dev;
 116static DEFINE_SPINLOCK(tll_lock);       /* serialize access to tll_dev */
 117
 118/*-------------------------------------------------------------------------*/
 119
 120static inline void usbtll_write(void __iomem *base, u32 reg, u32 val)
 121{
 122        __raw_writel(val, base + reg);
 123}
 124
 125static inline u32 usbtll_read(void __iomem *base, u32 reg)
 126{
 127        return __raw_readl(base + reg);
 128}
 129
 130static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val)
 131{
 132        __raw_writeb(val, base + reg);
 133}
 134
 135static inline u8 usbtll_readb(void __iomem *base, u8 reg)
 136{
 137        return __raw_readb(base + reg);
 138}
 139
 140/*-------------------------------------------------------------------------*/
 141
 142static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
 143{
 144        switch (pmode) {
 145        case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
 146        case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
 147        case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
 148        case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
 149        case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
 150        case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
 151        case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
 152        case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
 153        case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
 154        case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
 155                return true;
 156
 157        default:
 158                return false;
 159        }
 160}
 161
 162/*
 163 * convert the port-mode enum to a value we can use in the FSLSMODE
 164 * field of USBTLL_CHANNEL_CONF
 165 */
 166static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
 167{
 168        switch (mode) {
 169        case OMAP_USBHS_PORT_MODE_UNUSED:
 170        case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
 171                return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
 172
 173        case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
 174                return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM;
 175
 176        case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
 177                return OMAP_TLL_FSLSMODE_3PIN_PHY;
 178
 179        case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
 180                return OMAP_TLL_FSLSMODE_4PIN_PHY;
 181
 182        case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
 183                return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0;
 184
 185        case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
 186                return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM;
 187
 188        case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
 189                return OMAP_TLL_FSLSMODE_3PIN_TLL;
 190
 191        case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
 192                return OMAP_TLL_FSLSMODE_4PIN_TLL;
 193
 194        case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
 195                return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0;
 196
 197        case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
 198                return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM;
 199        default:
 200                pr_warn("Invalid port mode, using default\n");
 201                return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0;
 202        }
 203}
 204
 205/**
 206 * usbtll_omap_probe - initialize TI-based HCDs
 207 *
 208 * Allocates basic resources for this USB host controller.
 209 */
 210static int usbtll_omap_probe(struct platform_device *pdev)
 211{
 212        struct device                           *dev =  &pdev->dev;
 213        struct usbhs_omap_platform_data         *pdata = dev->platform_data;
 214        void __iomem                            *base;
 215        struct resource                         *res;
 216        struct usbtll_omap                      *tll;
 217        unsigned                                reg;
 218        int                                     ret = 0;
 219        int                                     i, ver;
 220        bool needs_tll;
 221
 222        dev_dbg(dev, "starting TI HSUSB TLL Controller\n");
 223
 224        tll = devm_kzalloc(dev, sizeof(struct usbtll_omap), GFP_KERNEL);
 225        if (!tll) {
 226                dev_err(dev, "Memory allocation failed\n");
 227                return -ENOMEM;
 228        }
 229
 230        if (!pdata) {
 231                dev_err(dev, "Platform data missing\n");
 232                return -ENODEV;
 233        }
 234
 235        tll->pdata = pdata;
 236
 237        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 238        base = devm_request_and_ioremap(dev, res);
 239        if (!base) {
 240                ret = -EADDRNOTAVAIL;
 241                dev_err(dev, "Resource request/ioremap failed:%d\n", ret);
 242                return ret;
 243        }
 244
 245        platform_set_drvdata(pdev, tll);
 246        pm_runtime_enable(dev);
 247        pm_runtime_get_sync(dev);
 248
 249        ver =  usbtll_read(base, OMAP_USBTLL_REVISION);
 250        switch (ver) {
 251        case OMAP_USBTLL_REV1:
 252        case OMAP_USBTLL_REV4:
 253                tll->nch = OMAP_TLL_CHANNEL_COUNT;
 254                break;
 255        case OMAP_USBTLL_REV2:
 256        case OMAP_USBTLL_REV3:
 257                tll->nch = OMAP_REV2_TLL_CHANNEL_COUNT;
 258                break;
 259        default:
 260                tll->nch = OMAP_TLL_CHANNEL_COUNT;
 261                dev_dbg(dev,
 262                 "USB TLL Rev : 0x%x not recognized, assuming %d channels\n",
 263                        ver, tll->nch);
 264                break;
 265        }
 266
 267        tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
 268                                                GFP_KERNEL);
 269        if (!tll->ch_clk) {
 270                ret = -ENOMEM;
 271                dev_err(dev, "Couldn't allocate memory for channel clocks\n");
 272                goto err_clk_alloc;
 273        }
 274
 275        for (i = 0; i < tll->nch; i++) {
 276                char clkname[] = "usb_tll_hs_usb_chx_clk";
 277
 278                snprintf(clkname, sizeof(clkname),
 279                                        "usb_tll_hs_usb_ch%d_clk", i);
 280                tll->ch_clk[i] = clk_get(dev, clkname);
 281
 282                if (IS_ERR(tll->ch_clk[i]))
 283                        dev_dbg(dev, "can't get clock : %s\n", clkname);
 284        }
 285
 286        needs_tll = false;
 287        for (i = 0; i < tll->nch; i++)
 288                needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]);
 289
 290        if (needs_tll) {
 291
 292                /* Program Common TLL register */
 293                reg = usbtll_read(base, OMAP_TLL_SHARED_CONF);
 294                reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON
 295                        | OMAP_TLL_SHARED_CONF_USB_DIVRATION);
 296                reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN;
 297                reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN;
 298
 299                usbtll_write(base, OMAP_TLL_SHARED_CONF, reg);
 300
 301                /* Enable channels now */
 302                for (i = 0; i < tll->nch; i++) {
 303                        reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i));
 304
 305                        if (is_ohci_port(pdata->port_mode[i])) {
 306                                reg |= ohci_omap3_fslsmode(pdata->port_mode[i])
 307                                << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT;
 308                                reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS;
 309                        } else if (pdata->port_mode[i] ==
 310                                        OMAP_EHCI_PORT_MODE_TLL) {
 311                                /*
 312                                 * Disable AutoIdle, BitStuffing
 313                                 * and use SDR Mode
 314                                 */
 315                                reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
 316                                        | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
 317                                        | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
 318                        } else if (pdata->port_mode[i] ==
 319                                        OMAP_EHCI_PORT_MODE_HSIC) {
 320                                /*
 321                                 * HSIC Mode requires UTMI port configurations
 322                                 */
 323                                reg |= OMAP_TLL_CHANNEL_CONF_DRVVBUS
 324                                 | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
 325                                 | OMAP_TLL_CHANNEL_CONF_MODE_TRANSPARENT_UTMI
 326                                 | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
 327                        } else {
 328                                continue;
 329                        }
 330                        reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
 331                        usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg);
 332
 333                        usbtll_writeb(base,
 334                                      OMAP_TLL_ULPI_SCRATCH_REGISTER(i),
 335                                      0xbe);
 336                }
 337        }
 338
 339        pm_runtime_put_sync(dev);
 340        /* only after this can omap_tll_enable/disable work */
 341        spin_lock(&tll_lock);
 342        tll_dev = dev;
 343        spin_unlock(&tll_lock);
 344
 345        return 0;
 346
 347err_clk_alloc:
 348        pm_runtime_put_sync(dev);
 349        pm_runtime_disable(dev);
 350
 351        return ret;
 352}
 353
 354/**
 355 * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs
 356 * @pdev: USB Host Controller being removed
 357 *
 358 * Reverses the effect of usbtll_omap_probe().
 359 */
 360static int usbtll_omap_remove(struct platform_device *pdev)
 361{
 362        struct usbtll_omap *tll = platform_get_drvdata(pdev);
 363        int i;
 364
 365        spin_lock(&tll_lock);
 366        tll_dev = NULL;
 367        spin_unlock(&tll_lock);
 368
 369        for (i = 0; i < tll->nch; i++)
 370                if (!IS_ERR(tll->ch_clk[i]))
 371                        clk_put(tll->ch_clk[i]);
 372
 373        pm_runtime_disable(&pdev->dev);
 374        return 0;
 375}
 376
 377static int usbtll_runtime_resume(struct device *dev)
 378{
 379        struct usbtll_omap                      *tll = dev_get_drvdata(dev);
 380        struct usbhs_omap_platform_data         *pdata = tll->pdata;
 381        int i;
 382
 383        dev_dbg(dev, "usbtll_runtime_resume\n");
 384
 385        for (i = 0; i < tll->nch; i++) {
 386                if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
 387                        int r;
 388
 389                        if (IS_ERR(tll->ch_clk[i]))
 390                                continue;
 391
 392                        r = clk_enable(tll->ch_clk[i]);
 393                        if (r) {
 394                                dev_err(dev,
 395                                 "Error enabling ch %d clock: %d\n", i, r);
 396                        }
 397                }
 398        }
 399
 400        return 0;
 401}
 402
 403static int usbtll_runtime_suspend(struct device *dev)
 404{
 405        struct usbtll_omap                      *tll = dev_get_drvdata(dev);
 406        struct usbhs_omap_platform_data         *pdata = tll->pdata;
 407        int i;
 408
 409        dev_dbg(dev, "usbtll_runtime_suspend\n");
 410
 411        for (i = 0; i < tll->nch; i++) {
 412                if (omap_usb_mode_needs_tll(pdata->port_mode[i])) {
 413                        if (!IS_ERR(tll->ch_clk[i]))
 414                                clk_disable(tll->ch_clk[i]);
 415                }
 416        }
 417
 418        return 0;
 419}
 420
 421static const struct dev_pm_ops usbtllomap_dev_pm_ops = {
 422        SET_RUNTIME_PM_OPS(usbtll_runtime_suspend,
 423                           usbtll_runtime_resume,
 424                           NULL)
 425};
 426
 427static struct platform_driver usbtll_omap_driver = {
 428        .driver = {
 429                .name           = (char *)usbtll_driver_name,
 430                .owner          = THIS_MODULE,
 431                .pm             = &usbtllomap_dev_pm_ops,
 432        },
 433        .probe          = usbtll_omap_probe,
 434        .remove         = usbtll_omap_remove,
 435};
 436
 437int omap_tll_enable(void)
 438{
 439        int ret;
 440
 441        spin_lock(&tll_lock);
 442
 443        if (!tll_dev) {
 444                pr_err("%s: OMAP USB TLL not initialized\n", __func__);
 445                ret = -ENODEV;
 446        } else {
 447                ret = pm_runtime_get_sync(tll_dev);
 448        }
 449
 450        spin_unlock(&tll_lock);
 451
 452        return ret;
 453}
 454EXPORT_SYMBOL_GPL(omap_tll_enable);
 455
 456int omap_tll_disable(void)
 457{
 458        int ret;
 459
 460        spin_lock(&tll_lock);
 461
 462        if (!tll_dev) {
 463                pr_err("%s: OMAP USB TLL not initialized\n", __func__);
 464                ret = -ENODEV;
 465        } else {
 466                ret = pm_runtime_put_sync(tll_dev);
 467        }
 468
 469        spin_unlock(&tll_lock);
 470
 471        return ret;
 472}
 473EXPORT_SYMBOL_GPL(omap_tll_disable);
 474
 475MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
 476MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
 477MODULE_LICENSE("GPL v2");
 478MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers");
 479
 480static int __init omap_usbtll_drvinit(void)
 481{
 482        return platform_driver_register(&usbtll_omap_driver);
 483}
 484
 485/*
 486 * init before usbhs core driver;
 487 * The usbtll driver should be initialized before
 488 * the usbhs core driver probe function is called.
 489 */
 490fs_initcall(omap_usbtll_drvinit);
 491
 492static void __exit omap_usbtll_drvexit(void)
 493{
 494        platform_driver_unregister(&usbtll_omap_driver);
 495}
 496module_exit(omap_usbtll_drvexit);
 497
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.