linux/arch/arm/mach-mmp/devices.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-mmp/devices.c
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/platform_device.h>
  11#include <linux/dma-mapping.h>
  12#include <linux/delay.h>
  13
  14#include <asm/irq.h>
  15#include "irqs.h"
  16#include "devices.h"
  17#include "cputype.h"
  18#include "regs-usb.h"
  19
  20int __init pxa_register_device(struct pxa_device_desc *desc,
  21                                void *data, size_t size)
  22{
  23        struct platform_device *pdev;
  24        struct resource res[2 + MAX_RESOURCE_DMA];
  25        int i, ret = 0, nres = 0;
  26
  27        pdev = platform_device_alloc(desc->drv_name, desc->id);
  28        if (pdev == NULL)
  29                return -ENOMEM;
  30
  31        pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
  32
  33        memset(res, 0, sizeof(res));
  34
  35        if (desc->start != -1ul && desc->size > 0) {
  36                res[nres].start = desc->start;
  37                res[nres].end   = desc->start + desc->size - 1;
  38                res[nres].flags = IORESOURCE_MEM;
  39                nres++;
  40        }
  41
  42        if (desc->irq != NO_IRQ) {
  43                res[nres].start = desc->irq;
  44                res[nres].end   = desc->irq;
  45                res[nres].flags = IORESOURCE_IRQ;
  46                nres++;
  47        }
  48
  49        for (i = 0; i < MAX_RESOURCE_DMA; i++, nres++) {
  50                if (desc->dma[i] == 0)
  51                        break;
  52
  53                res[nres].start = desc->dma[i];
  54                res[nres].end   = desc->dma[i];
  55                res[nres].flags = IORESOURCE_DMA;
  56        }
  57
  58        ret = platform_device_add_resources(pdev, res, nres);
  59        if (ret) {
  60                platform_device_put(pdev);
  61                return ret;
  62        }
  63
  64        if (data && size) {
  65                ret = platform_device_add_data(pdev, data, size);
  66                if (ret) {
  67                        platform_device_put(pdev);
  68                        return ret;
  69                }
  70        }
  71
  72        return platform_device_add(pdev);
  73}
  74
  75#if IS_ENABLED(CONFIG_USB) || IS_ENABLED(CONFIG_USB_GADGET)
  76#if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV)
  77#if IS_ENABLED(CONFIG_CPU_PXA910) || IS_ENABLED(CONFIG_CPU_PXA168)
  78
  79/*****************************************************************************
  80 * The registers read/write routines
  81 *****************************************************************************/
  82
  83static unsigned int u2o_get(void __iomem *base, unsigned int offset)
  84{
  85        return readl_relaxed(base + offset);
  86}
  87
  88static void u2o_set(void __iomem *base, unsigned int offset,
  89                unsigned int value)
  90{
  91        u32 reg;
  92
  93        reg = readl_relaxed(base + offset);
  94        reg |= value;
  95        writel_relaxed(reg, base + offset);
  96        readl_relaxed(base + offset);
  97}
  98
  99static void u2o_clear(void __iomem *base, unsigned int offset,
 100                unsigned int value)
 101{
 102        u32 reg;
 103
 104        reg = readl_relaxed(base + offset);
 105        reg &= ~value;
 106        writel_relaxed(reg, base + offset);
 107        readl_relaxed(base + offset);
 108}
 109
 110static void u2o_write(void __iomem *base, unsigned int offset,
 111                unsigned int value)
 112{
 113        writel_relaxed(value, base + offset);
 114        readl_relaxed(base + offset);
 115}
 116
 117
 118static DEFINE_MUTEX(phy_lock);
 119static int phy_init_cnt;
 120
 121static int usb_phy_init_internal(void __iomem *base)
 122{
 123        int loops;
 124
 125        pr_info("Init usb phy!!!\n");
 126
 127        /* Initialize the USB PHY power */
 128        if (cpu_is_pxa910()) {
 129                u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
 130                        | (1<<UTMI_CTRL_PU_REF_SHIFT));
 131        }
 132
 133        u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
 134        u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
 135
 136        /* UTMI_PLL settings */
 137        u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
 138                | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
 139                | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
 140                | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
 141
 142        u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
 143                | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
 144                | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
 145                | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
 146
 147        /* UTMI_TX */
 148        u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
 149                | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
 150                | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
 151                | UTMI_TX_AMP_MASK);
 152        u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
 153                | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
 154                | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
 155
 156        /* UTMI_RX */
 157        u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
 158                | UTMI_REG_SQ_LENGTH_MASK);
 159        u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
 160                | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
 161
 162        /* UTMI_IVREF */
 163        if (cpu_is_pxa168())
 164                /* fixing Microsoft Altair board interface with NEC hub issue -
 165                 * Set UTMI_IVREF from 0x4a3 to 0x4bf */
 166                u2o_write(base, UTMI_IVREF, 0x4bf);
 167
 168        /* toggle VCOCAL_START bit of UTMI_PLL */
 169        udelay(200);
 170        u2o_set(base, UTMI_PLL, VCOCAL_START);
 171        udelay(40);
 172        u2o_clear(base, UTMI_PLL, VCOCAL_START);
 173
 174        /* toggle REG_RCAL_START bit of UTMI_TX */
 175        udelay(400);
 176        u2o_set(base, UTMI_TX, REG_RCAL_START);
 177        udelay(40);
 178        u2o_clear(base, UTMI_TX, REG_RCAL_START);
 179        udelay(400);
 180
 181        /* Make sure PHY PLL is ready */
 182        loops = 0;
 183        while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
 184                mdelay(1);
 185                loops++;
 186                if (loops > 100) {
 187                        printk(KERN_WARNING "calibrate timeout, UTMI_PLL %x\n",
 188                                u2o_get(base, UTMI_PLL));
 189                        break;
 190                }
 191        }
 192
 193        if (cpu_is_pxa168()) {
 194                u2o_set(base, UTMI_RESERVE, 1 << 5);
 195                /* Turn on UTMI PHY OTG extension */
 196                u2o_write(base, UTMI_OTG_ADDON, 1);
 197        }
 198
 199        return 0;
 200}
 201
 202static int usb_phy_deinit_internal(void __iomem *base)
 203{
 204        pr_info("Deinit usb phy!!!\n");
 205
 206        if (cpu_is_pxa168())
 207                u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
 208
 209        u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
 210        u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
 211        u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
 212        u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
 213        u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
 214
 215        return 0;
 216}
 217
 218int pxa_usb_phy_init(void __iomem *phy_reg)
 219{
 220        mutex_lock(&phy_lock);
 221        if (phy_init_cnt++ == 0)
 222                usb_phy_init_internal(phy_reg);
 223        mutex_unlock(&phy_lock);
 224        return 0;
 225}
 226
 227void pxa_usb_phy_deinit(void __iomem *phy_reg)
 228{
 229        WARN_ON(phy_init_cnt == 0);
 230
 231        mutex_lock(&phy_lock);
 232        if (--phy_init_cnt == 0)
 233                usb_phy_deinit_internal(phy_reg);
 234        mutex_unlock(&phy_lock);
 235}
 236#endif
 237#endif
 238#endif
 239
 240#if IS_ENABLED(CONFIG_USB_SUPPORT)
 241static u64 __maybe_unused usb_dma_mask = ~(u32)0;
 242
 243#if IS_ENABLED(CONFIG_PHY_PXA_USB)
 244struct resource pxa168_usb_phy_resources[] = {
 245        [0] = {
 246                .start  = PXA168_U2O_PHYBASE,
 247                .end    = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
 248                .flags  = IORESOURCE_MEM,
 249        },
 250};
 251
 252struct platform_device pxa168_device_usb_phy = {
 253        .name           = "pxa-usb-phy",
 254        .id             = -1,
 255        .resource       = pxa168_usb_phy_resources,
 256        .num_resources  = ARRAY_SIZE(pxa168_usb_phy_resources),
 257        .dev            =  {
 258                .dma_mask       = &usb_dma_mask,
 259                .coherent_dma_mask = 0xffffffff,
 260        }
 261};
 262#endif /* CONFIG_PHY_PXA_USB */
 263
 264#if IS_ENABLED(CONFIG_USB_MV_UDC)
 265struct resource pxa168_u2o_resources[] = {
 266        /* regbase */
 267        [0] = {
 268                .start  = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
 269                .end    = PXA168_U2O_REGBASE + USB_REG_RANGE,
 270                .flags  = IORESOURCE_MEM,
 271                .name   = "capregs",
 272        },
 273        /* phybase */
 274        [1] = {
 275                .start  = PXA168_U2O_PHYBASE,
 276                .end    = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
 277                .flags  = IORESOURCE_MEM,
 278                .name   = "phyregs",
 279        },
 280        [2] = {
 281                .start  = IRQ_PXA168_USB1,
 282                .end    = IRQ_PXA168_USB1,
 283                .flags  = IORESOURCE_IRQ,
 284        },
 285};
 286
 287struct platform_device pxa168_device_u2o = {
 288        .name           = "mv-udc",
 289        .id             = -1,
 290        .resource       = pxa168_u2o_resources,
 291        .num_resources  = ARRAY_SIZE(pxa168_u2o_resources),
 292        .dev            =  {
 293                .dma_mask       = &usb_dma_mask,
 294                .coherent_dma_mask = 0xffffffff,
 295        }
 296};
 297#endif /* CONFIG_USB_MV_UDC */
 298
 299#if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O)
 300struct resource pxa168_u2oehci_resources[] = {
 301        [0] = {
 302                .start  = PXA168_U2O_REGBASE,
 303                .end    = PXA168_U2O_REGBASE + USB_REG_RANGE,
 304                .flags  = IORESOURCE_MEM,
 305        },
 306        [1] = {
 307                .start  = IRQ_PXA168_USB1,
 308                .end    = IRQ_PXA168_USB1,
 309                .flags  = IORESOURCE_IRQ,
 310        },
 311};
 312
 313struct platform_device pxa168_device_u2oehci = {
 314        .name           = "pxa-u2oehci",
 315        .id             = -1,
 316        .dev            = {
 317                .dma_mask               = &usb_dma_mask,
 318                .coherent_dma_mask      = 0xffffffff,
 319        },
 320
 321        .num_resources  = ARRAY_SIZE(pxa168_u2oehci_resources),
 322        .resource       = pxa168_u2oehci_resources,
 323};
 324#endif
 325
 326#if IS_ENABLED(CONFIG_USB_MV_OTG)
 327struct resource pxa168_u2ootg_resources[] = {
 328        /* regbase */
 329        [0] = {
 330                .start  = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
 331                .end    = PXA168_U2O_REGBASE + USB_REG_RANGE,
 332                .flags  = IORESOURCE_MEM,
 333                .name   = "capregs",
 334        },
 335        /* phybase */
 336        [1] = {
 337                .start  = PXA168_U2O_PHYBASE,
 338                .end    = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
 339                .flags  = IORESOURCE_MEM,
 340                .name   = "phyregs",
 341        },
 342        [2] = {
 343                .start  = IRQ_PXA168_USB1,
 344                .end    = IRQ_PXA168_USB1,
 345                .flags  = IORESOURCE_IRQ,
 346        },
 347};
 348
 349struct platform_device pxa168_device_u2ootg = {
 350        .name           = "mv-otg",
 351        .id             = -1,
 352        .dev  = {
 353                .dma_mask          = &usb_dma_mask,
 354                .coherent_dma_mask = 0xffffffff,
 355        },
 356
 357        .num_resources  = ARRAY_SIZE(pxa168_u2ootg_resources),
 358        .resource      = pxa168_u2ootg_resources,
 359};
 360#endif /* CONFIG_USB_MV_OTG */
 361
 362#endif
 363