linux-old/arch/arm/mach-sa1100/adsbitsyplus.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-sa1100/adsbitsyplus.c
   3 *
   4 * Author: Robert Whaley
   5 *
   6 * This file comes from adsbitsy.c of Woojung Huh <whuh@applieddata.net>
   7 *
   8 * Pieces specific to the ADS Bitsy Plus
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/init.h>
  16#include <linux/sched.h>
  17#include <linux/interrupt.h>
  18#include <linux/ptrace.h>
  19#include <linux/delay.h>
  20#include <linux/serial_core.h>
  21
  22#include <asm/hardware.h>
  23#include <asm/hardware/sa1111.h>
  24#include <asm/setup.h>
  25#include <asm/irq.h>
  26
  27#include <asm/mach/irq.h>
  28#include <asm/mach/arch.h>
  29#include <asm/mach/map.h>
  30#include <asm/mach/serial_sa1100.h>
  31
  32#include <asm/arch/irq.h>
  33
  34#include "generic.h"
  35#include "sa1111.h"
  36
  37/* unfortunately, we can't detect the difference between REV 2 and REV A
  38   connector boards.  So by convention, the registers.txt file is used
  39   to set a byte to either 0x02 or 0x0a to make this distinction.  The
  40   bootloader must detect this by default we assume rev A since most boards
  41   will be rev A */
  42
  43static int adsbitsyplus_connector_board_rev_number = 0xA;
  44
  45static int __init adsbitsyplus_connector_board_rev_setup(char *str)
  46{
  47        adsbitsyplus_connector_board_rev_number = simple_strtol(str,NULL,0);
  48        return 1;
  49}
  50
  51int adsbitsyplus_connector_board_rev(void)
  52{
  53        static int only_once = 1;
  54        if (only_once) {
  55                printk(KERN_INFO "Bitsy Connector Board REV: %#x\n", adsbitsyplus_connector_board_rev_number);
  56                only_once = 0;
  57        }
  58        return adsbitsyplus_connector_board_rev_number;
  59}
  60
  61static int __init adsbitsyplus_init(void)
  62{
  63        int ret;
  64
  65        if (!machine_is_adsbitsyplus())
  66                return -ENODEV;
  67
  68        /*
  69         * Ensure that the memory bus request/grant signals are setup,
  70         * and the grant is held in its inactive state
  71         */
  72        sa1110_mb_disable();
  73
  74        /* Bitsy uses GPIO pins for SPI interface to AVR
  75         * Bitsy Plus uses the standard pins instead.
  76         * it also needs to reset the AVR when booting
  77         */
  78
  79        PPAR &= ~PPAR_SSPGPIO;
  80        ADS_CPLD_SUPPC |= ADS_SUPPC_AVR_WKP;
  81        mdelay(100);
  82        ADS_CPLD_SUPPC &= ~ADS_SUPPC_AVR_WKP;
  83
  84        /*
  85         * Reset SA1111
  86         */
  87        GPCR |= GPIO_GPIO26;
  88        udelay(1000);
  89        GPSR |= GPIO_GPIO26;
  90
  91#ifndef CONFIG_LEDS_TIMER
  92        // Set Serial port 1 RTS and DTR Low during sleep
  93        PGSR |= GPIO_GPIO15 | GPIO_GPIO20;
  94#else
  95        // only RTS (because DTR is also the LED
  96        // which should be off during sleep);
  97        PGSR |= GPIO_GPIO15;
  98#endif
  99
 100        // Set Serial port 3RTS Low during sleep
 101        PGSR |= GPIO_GPIO19;
 102
 103        /*
 104         * Probe for SA1111.
 105         */
 106        ret = sa1111_probe(ADSBITSYPLUS_SA1111_BASE);
 107        if (ret < 0)
 108                return ret;
 109
 110        /*
 111         * We found it.  Wake the chip up.
 112         */
 113        sa1111_wake();
 114
 115        /*
 116         * The SDRAM configuration of the SA1110 and the SA1111 must
 117         * match.  This is very important to ensure that SA1111 accesses
 118         * don't corrupt the SDRAM.  Note that this ungates the SA1111's
 119         * MBGNT signal, so we must have called sa1110_mb_disable()
 120         * beforehand.
 121         */
 122        sa1111_configure_smc(1,
 123                             FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
 124                             FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
 125
 126        /*
 127         * We only need to turn on DCLK whenever we want to use the
 128         * DMA.  It can otherwise be held firmly in the off position.
 129         */
 130        SKPCR |= SKPCR_DCLKEN;
 131
 132        /*
 133         * Enable the SA1110 memory bus request and grant signals.
 134         */
 135        sa1110_mb_enable();
 136
 137        set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_RISING_EDGE);
 138        sa1111_init_irq(IRQ_GPIO0);
 139
 140        return 0;
 141}
 142
 143__initcall(adsbitsyplus_init);
 144
 145static void __init adsbitsyplus_init_irq(void)
 146{
 147        /* First the standard SA1100 IRQs */
 148        sa1100_init_irq();
 149}
 150
 151/*
 152 * Resume SA1111 when system wakes up
 153 */
 154void adsbitsyplus_sa1111_wake(unsigned long pa_dwr)
 155{
 156        // Turn ON SA1111
 157        GPCR |= GPIO_GPIO26;
 158        mdelay(1);
 159        GPSR |= GPIO_GPIO26;
 160
 161        GAFR |= GPIO_32_768kHz;
 162        GPDR |= GPIO_32_768kHz;
 163        TUCR = TUCR_3_6864MHz;
 164
 165        SBI_SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN;
 166        udelay(100);
 167        SBI_SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN;
 168
 169        GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
 170        GPDR |= GPIO_MBGNT;
 171        GPDR &= ~GPIO_MBREQ;
 172        TUCR |= TUCR_MR;
 173
 174        sa1111_configure_smc(1,
 175                             FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
 176                             FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
 177        SKPCR |= SKPCR_DCLKEN;
 178
 179        // Reset PCMCIA
 180        PCCR = 0xFF;
 181        mdelay(100);
 182        PA_DDR = 0x00;
 183        // PA_DWR = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
 184        // PA_DWR = GPIO_GPIO0 | GPIO_GPIO2 | GPIO_GPIO3;
 185        PA_DWR = pa_dwr;
 186        PCCR = ~(PCCR_S0_RST | PCCR_S1_RST);
 187
 188#ifdef CONFIG_USB_OHCI_SA1111
 189        // Turn ON clock
 190        SKPCR |= SKPCR_UCLKEN;
 191        udelay(100);
 192
 193        // force a RESET
 194        USB_RESET = 0x01;
 195        USB_RESET |= 0x02;
 196        udelay(100);
 197
 198        // Set Power Sense and Control Line
 199        USB_RESET = 0;
 200        USB_RESET = USB_RESET_PWRSENSELOW;
 201        USB_STATUS = 0;
 202        udelay(10);
 203#endif
 204}
 205
 206
 207static struct map_desc adsbitsyplus_io_desc[] __initdata = {
 208 /* virtual     physical    length      domain     r  w  c  b */
 209  { 0xe8000000, 0x08000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 1 */
 210  { 0xf0000000, 0x3C000000, 0x00004000, DOMAIN_IO, 0, 1, 0, 0 }, /* 91C1111 */
 211  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
 212  { 0xf1000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Controller */
 213  LAST_DESC
 214};
 215
 216/* Use this to see when all uarts are shutdown.  Or all are closed.
 217 * We can only turn off RS232 chip if either of these are true.
 218 */
 219
 220static int uart_wake_count[3] = {1, 1, 1};
 221
 222enum {UART_SHUTDOWN, UART_WAKEUP};
 223
 224static void update_uart_counts(int line, int state)
 225{
 226        switch (state) {
 227        case UART_WAKEUP:
 228                uart_wake_count[line]++;
 229                break;
 230        case UART_SHUTDOWN:
 231                uart_wake_count[line]--;
 232                break;
 233        }
 234}
 235
 236static int adsbitsyplus_uart_open(struct uart_port *port, struct uart_info *info)
 237{
 238        if (port->mapbase == _Ser1UTCR0) {
 239                Ser1SDCR0 |= SDCR0_UART;
 240        } else if (port->mapbase == _Ser2UTCR0) {
 241                Ser2UTCR4 = Ser2HSCR0 = 0;
 242        }
 243        return 0;
 244}
 245
 246void adsbitsyplus_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 247{
 248        // state has ACPI D0-D3
 249        // ACPI D0        : resume from suspend
 250        // ACPI D1-D3 : enter to a suspend state
 251        if (port->mapbase == _Ser1UTCR0) {
 252                if (state) {
 253                        update_uart_counts(1, UART_SHUTDOWN);
 254                        // disable uart
 255                        Ser1UTCR3 = 0;
 256                }
 257                else {
 258                        update_uart_counts(1, UART_WAKEUP);
 259                }
 260        }
 261        else if (port->mapbase == _Ser2UTCR0) {
 262                if (state) {
 263                        update_uart_counts(2, UART_SHUTDOWN);
 264                        // disable uart
 265                        Ser2UTCR3 = 0;
 266                        Ser2HSCR0 = 0;
 267                }
 268                else {
 269                        update_uart_counts(2, UART_WAKEUP);
 270                }
 271        }
 272        else if (port->mapbase == _Ser3UTCR0) {
 273                if (state) {
 274                        update_uart_counts(0, UART_SHUTDOWN);
 275                        // disable uart
 276                        Ser3UTCR3 = 0;
 277                }
 278                else {
 279                        update_uart_counts(0, UART_WAKEUP);
 280                }
 281        }
 282        if (state == 0) {
 283                // Turn power on if uarts are awake
 284                if (uart_wake_count[0] + uart_wake_count[1] != 0) {
 285                        // make sure RS-232 is turned on if 1 or 3 are open
 286                        ADS_CPLD_PCON |= ADS_PCON_COM1_3_ON;
 287                }
 288                if (uart_wake_count[2] != 0) {
 289                        if (adsbitsyplus_connector_board_rev() >= 0x0a)
 290                                ADS_CPLD_PCON |= ADS_PCON_CONN_B_PE2;
 291                }
 292        }
 293        else {
 294                // Turn power off if uarts are asleep
 295                if (uart_wake_count[0] + uart_wake_count[1] == 0) {
 296                        // save power if we are sleeping
 297                        ADS_CPLD_PCON &= ~ADS_PCON_COM1_3_ON;
 298                        GAFR &= ~(GPIO_GPIO15 | GPIO_GPIO19 | GPIO_GPIO20);
 299                        GPDR |= GPIO_GPIO15 | GPIO_GPIO19 | GPIO_GPIO20;
 300                }
 301                if (uart_wake_count[2] == 0) {
 302                        if (adsbitsyplus_connector_board_rev() >= 0x0a)
 303                                ADS_CPLD_PCON &= ~ADS_PCON_CONN_B_PE2;
 304                }
 305        }
 306}
 307
 308static void adsbitsyplus_set_mctrl(struct uart_port *port, u_int mctrl)
 309{
 310        // note: only ports 1 and 3 have modem control
 311        if (port->mapbase == _Ser1UTCR0) {
 312                if (mctrl & TIOCM_RTS)
 313                        // Set RTS High
 314                        GPCR = GPIO_GPIO15;
 315                else
 316                        // Set RTS LOW
 317                        GPSR = GPIO_GPIO15;
 318                if (mctrl & TIOCM_DTR)
 319                        // Set DTR High
 320                        GPCR = GPIO_GPIO20;
 321                else
 322                        // Set DTR Low
 323                        GPSR = GPIO_GPIO20;
 324        } else if (port->mapbase == _Ser3UTCR0) {
 325                if (mctrl & TIOCM_RTS)
 326                        // Set RTS High
 327                        GPCR = GPIO_GPIO19;
 328                else
 329                        // Set RTS LOW
 330                        GPSR = GPIO_GPIO19;
 331        }
 332}
 333
 334static u_int adsbitsyplus_get_mctrl(struct uart_port *port)
 335{
 336        u_int ret = 0;
 337
 338        // note: only ports 1 and 3 have modem control
 339        if (port->mapbase == _Ser1UTCR0) {
 340                if (!(GPLR & GPIO_GPIO14))
 341                        ret |= TIOCM_CTS;
 342                if (!(GPLR & GPIO_GPIO24))
 343                        ret |= TIOCM_DSR;
 344                if (!(GPLR & GPIO_GPIO16))
 345                        ret |= TIOCM_RI;
 346                if (!(GPLR & GPIO_GPIO17))
 347                        ret |= TIOCM_CD;
 348        } else if (port->mapbase == _Ser3UTCR0) {
 349                if (!(GPLR & GPIO_GPIO18))
 350                        ret |= TIOCM_CTS;
 351        }
 352
 353        return ret;
 354}
 355
 356static struct sa1100_port_fns adsbitsyplus_port_fns __initdata = {
 357        .set_mctrl =    adsbitsyplus_set_mctrl,
 358        .get_mctrl =    adsbitsyplus_get_mctrl,
 359        .open =         adsbitsyplus_uart_open,
 360        .pm =           adsbitsyplus_uart_pm,
 361};
 362
 363static void __init adsbitsyplus_map_io(void)
 364{
 365        sa1100_map_io();
 366        iotable_init(adsbitsyplus_io_desc);
 367
 368        sa1100_register_uart_fns(&adsbitsyplus_port_fns);
 369        sa1100_register_uart(0, 3);
 370        sa1100_register_uart(1, 1);
 371
 372        // don't register if you want to use IRDA
 373#ifndef CONFIG_SA1100_FIR
 374        sa1100_register_uart(2, 2);
 375#endif
 376
 377        // COM1 Set RTS and DTR Output
 378        GPDR |= GPIO_GPIO15 | GPIO_GPIO20;
 379        // Set CTS, DSR, RI and CD Input
 380        GPDR &= ~(GPIO_GPIO14 | GPIO_GPIO24 | GPIO_GPIO16 | GPIO_GPIO17);
 381
 382        // COM3 Set RTS Output
 383        GPDR |= GPIO_GPIO19;
 384        // Set CTS Input
 385        GPDR &= ~GPIO_GPIO18;
 386}
 387
 388__setup("adsbitsyplus_conn_board_rev=", adsbitsyplus_connector_board_rev_setup);
 389
 390MACHINE_START(ADSBITSYPLUS, "ADS Bitsy Plus")
 391        BOOT_PARAMS(0xc000003c)
 392        BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 393        MAPIO(adsbitsyplus_map_io)
 394        INITIRQ(adsbitsyplus_init_irq)
 395MACHINE_END
 396
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.