linux/arch/arm/mach-omap2/usb-tusb6010.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-omap2/usb-tusb6010.c
   3 *
   4 * Copyright (C) 2006 Nokia Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/types.h>
  12#include <linux/errno.h>
  13#include <linux/delay.h>
  14#include <linux/platform_device.h>
  15#include <linux/gpio.h>
  16
  17#include <linux/usb/musb.h>
  18
  19#include <mach/gpmc.h>
  20#include <mach/mux.h>
  21
  22
  23static u8               async_cs, sync_cs;
  24static unsigned         refclk_psec;
  25
  26
  27/* t2_ps, when quantized to fclk units, must happen no earlier than
  28 * the clock after after t1_NS.
  29 *
  30 * Return a possibly updated value of t2_ps, converted to nsec.
  31 */
  32static unsigned
  33next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)
  34{
  35        unsigned        t1_ps = t1_NS * 1000;
  36        unsigned        t1_f, t2_f;
  37
  38        if ((t1_ps + fclk_ps) < t2_ps)
  39                return t2_ps / 1000;
  40
  41        t1_f = (t1_ps + fclk_ps - 1) / fclk_ps;
  42        t2_f = (t2_ps + fclk_ps - 1) / fclk_ps;
  43
  44        if (t1_f >= t2_f)
  45                t2_f = t1_f + 1;
  46
  47        return (t2_f * fclk_ps) / 1000;
  48}
  49
  50/* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
  51
  52static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps)
  53{
  54        struct gpmc_timings     t;
  55        unsigned                t_acsnh_advnh = sysclk_ps + 3000;
  56        unsigned                tmp;
  57
  58        memset(&t, 0, sizeof(t));
  59
  60        /* CS_ON = t_acsnh_acsnl */
  61        t.cs_on = 8;
  62        /* ADV_ON = t_acsnh_advnh - t_advn */
  63        t.adv_on = next_clk(t.cs_on, t_acsnh_advnh - 7000, fclk_ps);
  64
  65        /*
  66         * READ ... from omap2420 TRM fig 12-13
  67         */
  68
  69        /* ADV_RD_OFF = t_acsnh_advnh */
  70        t.adv_rd_off = next_clk(t.adv_on, t_acsnh_advnh, fclk_ps);
  71
  72        /* OE_ON = t_acsnh_advnh + t_advn_oen (then wait for nRDY) */
  73        t.oe_on = next_clk(t.adv_on, t_acsnh_advnh + 1000, fclk_ps);
  74
  75        /* ACCESS = counters continue only after nRDY */
  76        tmp = t.oe_on * 1000 + 300;
  77        t.access = next_clk(t.oe_on, tmp, fclk_ps);
  78
  79        /* OE_OFF = after data gets sampled */
  80        tmp = t.access * 1000;
  81        t.oe_off = next_clk(t.access, tmp, fclk_ps);
  82
  83        t.cs_rd_off = t.oe_off;
  84
  85        tmp = t.cs_rd_off * 1000 + 7000 /* t_acsn_rdy_z */;
  86        t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
  87
  88        /*
  89         * WRITE ... from omap2420 TRM fig 12-15
  90         */
  91
  92        /* ADV_WR_OFF = t_acsnh_advnh */
  93        t.adv_wr_off = t.adv_rd_off;
  94
  95        /* WE_ON = t_acsnh_advnh + t_advn_wen (then wait for nRDY) */
  96        t.we_on = next_clk(t.adv_wr_off, t_acsnh_advnh + 1000, fclk_ps);
  97
  98        /* WE_OFF = after data gets sampled */
  99        tmp = t.we_on * 1000 + 300;
 100        t.we_off = next_clk(t.we_on, tmp, fclk_ps);
 101
 102        t.cs_wr_off = t.we_off;
 103
 104        tmp = t.cs_wr_off * 1000 + 7000 /* t_acsn_rdy_z */;
 105        t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
 106
 107        return gpmc_cs_set_timings(async_cs, &t);
 108}
 109
 110static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
 111{
 112        struct gpmc_timings     t;
 113        unsigned                t_scsnh_advnh = sysclk_ps + 3000;
 114        unsigned                tmp;
 115
 116        memset(&t, 0, sizeof(t));
 117        t.cs_on = 8;
 118
 119        /* ADV_ON = t_acsnh_advnh - t_advn */
 120        t.adv_on = next_clk(t.cs_on, t_scsnh_advnh - 7000, fclk_ps);
 121
 122        /* GPMC_CLK rate = fclk rate / div */
 123        t.sync_clk = 12 /* 11.1 nsec */;
 124        tmp = (t.sync_clk * 1000 + fclk_ps - 1) / fclk_ps;
 125        if (tmp > 4)
 126                return -ERANGE;
 127        if (tmp <= 0)
 128                tmp = 1;
 129        t.page_burst_access = (fclk_ps * tmp) / 1000;
 130
 131        /*
 132         * READ ... based on omap2420 TRM fig 12-19, 12-20
 133         */
 134
 135        /* ADV_RD_OFF = t_scsnh_advnh */
 136        t.adv_rd_off = next_clk(t.adv_on, t_scsnh_advnh, fclk_ps);
 137
 138        /* OE_ON = t_scsnh_advnh + t_advn_oen * fclk_ps (then wait for nRDY) */
 139        tmp = (t.adv_rd_off * 1000) + (3 * fclk_ps);
 140        t.oe_on = next_clk(t.adv_on, tmp, fclk_ps);
 141
 142        /* ACCESS = number of clock cycles after t_adv_eon */
 143        tmp = (t.oe_on * 1000) + (5 * fclk_ps);
 144        t.access = next_clk(t.oe_on, tmp, fclk_ps);
 145
 146        /* OE_OFF = after data gets sampled */
 147        tmp = (t.access * 1000) + (1 * fclk_ps);
 148        t.oe_off = next_clk(t.access, tmp, fclk_ps);
 149
 150        t.cs_rd_off = t.oe_off;
 151
 152        tmp = t.cs_rd_off * 1000 + 7000 /* t_scsn_rdy_z */;
 153        t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
 154
 155        /*
 156         * WRITE ... based on omap2420 TRM fig 12-21
 157         */
 158
 159        /* ADV_WR_OFF = t_scsnh_advnh */
 160        t.adv_wr_off = t.adv_rd_off;
 161
 162        /* WE_ON = t_scsnh_advnh + t_advn_wen * fclk_ps (then wait for nRDY) */
 163        tmp = (t.adv_wr_off * 1000) + (3 * fclk_ps);
 164        t.we_on = next_clk(t.adv_wr_off, tmp, fclk_ps);
 165
 166        /* WE_OFF = number of clock cycles after t_adv_wen */
 167        tmp = (t.we_on * 1000) + (6 * fclk_ps);
 168        t.we_off = next_clk(t.we_on, tmp, fclk_ps);
 169
 170        t.cs_wr_off = t.we_off;
 171
 172        tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
 173        t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
 174
 175        return gpmc_cs_set_timings(sync_cs, &t);
 176}
 177
 178extern unsigned long gpmc_get_fclk_period(void);
 179
 180/* tusb driver calls this when it changes the chip's clocking */
 181int tusb6010_platform_retime(unsigned is_refclk)
 182{
 183        static const char       error[] =
 184                KERN_ERR "tusb6010 %s retime error %d\n";
 185
 186        unsigned        fclk_ps = gpmc_get_fclk_period();
 187        unsigned        sysclk_ps;
 188        int             status;
 189
 190        if (!refclk_psec || fclk_ps == 0)
 191                return -ENODEV;
 192
 193        sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 194
 195        status = tusb_set_async_mode(sysclk_ps, fclk_ps);
 196        if (status < 0) {
 197                printk(error, "async", status);
 198                goto done;
 199        }
 200        status = tusb_set_sync_mode(sysclk_ps, fclk_ps);
 201        if (status < 0)
 202                printk(error, "sync", status);
 203done:
 204        return status;
 205}
 206EXPORT_SYMBOL_GPL(tusb6010_platform_retime);
 207
 208static struct resource tusb_resources[] = {
 209        /* Order is significant!  The start/end fields
 210         * are updated during setup..
 211         */
 212        { /* Asynchronous access */
 213                .flags  = IORESOURCE_MEM,
 214        },
 215        { /* Synchronous access */
 216                .flags  = IORESOURCE_MEM,
 217        },
 218        { /* IRQ */
 219                .flags  = IORESOURCE_IRQ,
 220        },
 221};
 222
 223static u64 tusb_dmamask = ~(u32)0;
 224
 225static struct platform_device tusb_device = {
 226        .name           = "musb_hdrc",
 227        .id             = -1,
 228        .dev = {
 229                .dma_mask               = &tusb_dmamask,
 230                .coherent_dma_mask      = 0xffffffff,
 231        },
 232        .num_resources  = ARRAY_SIZE(tusb_resources),
 233        .resource       = tusb_resources,
 234};
 235
 236
 237/* this may be called only from board-*.c setup code */
 238int __init
 239tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 240                unsigned ps_refclk, unsigned waitpin,
 241                unsigned async, unsigned sync,
 242                unsigned irq, unsigned dmachan)
 243{
 244        int             status;
 245        static char     error[] __initdata =
 246                KERN_ERR "tusb6010 init error %d, %d\n";
 247
 248        /* ASYNC region, primarily for PIO */
 249        status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
 250                                &tusb_resources[0].start);
 251        if (status < 0) {
 252                printk(error, 1, status);
 253                return status;
 254        }
 255        tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
 256        async_cs = async;
 257        gpmc_cs_write_reg(async, GPMC_CS_CONFIG1,
 258                          GPMC_CONFIG1_PAGE_LEN(2)
 259                        | GPMC_CONFIG1_WAIT_READ_MON
 260                        | GPMC_CONFIG1_WAIT_WRITE_MON
 261                        | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
 262                        | GPMC_CONFIG1_READTYPE_ASYNC
 263                        | GPMC_CONFIG1_WRITETYPE_ASYNC
 264                        | GPMC_CONFIG1_DEVICESIZE_16
 265                        | GPMC_CONFIG1_DEVICETYPE_NOR
 266                        | GPMC_CONFIG1_MUXADDDATA);
 267
 268
 269        /* SYNC region, primarily for DMA */
 270        status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
 271                                &tusb_resources[1].start);
 272        if (status < 0) {
 273                printk(error, 2, status);
 274                return status;
 275        }
 276        tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
 277        sync_cs = sync;
 278        gpmc_cs_write_reg(sync, GPMC_CS_CONFIG1,
 279                          GPMC_CONFIG1_READMULTIPLE_SUPP
 280                        | GPMC_CONFIG1_READTYPE_SYNC
 281                        | GPMC_CONFIG1_WRITEMULTIPLE_SUPP
 282                        | GPMC_CONFIG1_WRITETYPE_SYNC
 283                        | GPMC_CONFIG1_CLKACTIVATIONTIME(1)
 284                        | GPMC_CONFIG1_PAGE_LEN(2)
 285                        | GPMC_CONFIG1_WAIT_READ_MON
 286                        | GPMC_CONFIG1_WAIT_WRITE_MON
 287                        | GPMC_CONFIG1_WAIT_PIN_SEL(waitpin)
 288                        | GPMC_CONFIG1_DEVICESIZE_16
 289                        | GPMC_CONFIG1_DEVICETYPE_NOR
 290                        | GPMC_CONFIG1_MUXADDDATA
 291                        /* fclk divider gets set later */
 292                        );
 293
 294        /* IRQ */
 295        status = gpio_request(irq, "TUSB6010 irq");
 296        if (status < 0) {
 297                printk(error, 3, status);
 298                return status;
 299        }
 300        gpio_direction_input(irq);
 301        tusb_resources[2].start = irq + IH_GPIO_BASE;
 302
 303        /* set up memory timings ... can speed them up later */
 304        if (!ps_refclk) {
 305                printk(error, 4, status);
 306                return -ENODEV;
 307        }
 308        refclk_psec = ps_refclk;
 309        status = tusb6010_platform_retime(1);
 310        if (status < 0) {
 311                printk(error, 5, status);
 312                return status;
 313        }
 314
 315        /* finish device setup ... */
 316        if (!data) {
 317                printk(error, 6, status);
 318                return -ENODEV;
 319        }
 320        tusb_device.dev.platform_data = data;
 321
 322        /* REVISIT let the driver know what DMA channels work */
 323        if (!dmachan)
 324                tusb_device.dev.dma_mask = NULL;
 325        else {
 326                /* assume OMAP 2420 ES2.0 and later */
 327                if (dmachan & (1 << 0))
 328                        omap_cfg_reg(AA10_242X_DMAREQ0);
 329                if (dmachan & (1 << 1))
 330                        omap_cfg_reg(AA6_242X_DMAREQ1);
 331                if (dmachan & (1 << 2))
 332                        omap_cfg_reg(E4_242X_DMAREQ2);
 333                if (dmachan & (1 << 3))
 334                        omap_cfg_reg(G4_242X_DMAREQ3);
 335                if (dmachan & (1 << 4))
 336                        omap_cfg_reg(D3_242X_DMAREQ4);
 337                if (dmachan & (1 << 5))
 338                        omap_cfg_reg(E3_242X_DMAREQ5);
 339        }
 340
 341        /* so far so good ... register the device */
 342        status = platform_device_register(&tusb_device);
 343        if (status < 0) {
 344                printk(error, 7, status);
 345                return status;
 346        }
 347        return 0;
 348}
 349