stork.c 8.48 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
/*
 * linux/arch/arm/mach-sa1100/stork.c
 *
 *     Copyright (C) 2001 Ken Gordon
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/delay.h>

#include <asm/hardware.h>
#include <asm/setup.h>
#include <asm/keyboard.h>

#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h>
#include <linux/serial_core.h>

#include "generic.h"


#define STORK_VM_BASE_CS1 0xf0000000		/* where we get mapped (virtual) */
#define STORK_VM_OFF_CS1 0x08000000             /* where we started mapping (physical) */
#define STORK_VM_ADJUST_CS1 (STORK_VM_BASE_CS1-STORK_VM_OFF_CS1) /* add to the phys to get virt */

#define STORK_VM_BASE_CS2 0xf1000000		/* where we get mapped (virtual) */
#define STORK_VM_OFF_CS2  0x10000000             /* where we started mapping (physical) */
#define STORK_VM_ADJUST_CS2 (STORK_VM_BASE_CS2-STORK_VM_OFF_CS2) /* add to the phys to get virt */

static int debug = 0;

static int storkLatchA = 0;
static int storkLatchB = 0;
static int storkLCDCPLD[4] = { 0, 0, 0, 0};

int
storkSetLatchA(int bits)
{
    int ret = storkLatchA;
    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1);

    storkLatchA |= bits;
    *latch = storkLatchA;
    return ret;
}

int
storkClearLatchA(int bits)
{
    int ret = storkLatchA;
    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1);

    storkLatchA &= ~bits;
    *latch = storkLatchA;
    return ret;
}

int
storkSetLCDCPLD(int which, int bits)
{
    int ret = storkLCDCPLD[which];
    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);

    storkLCDCPLD[which] |= bits;
    *latch = storkLCDCPLD[which];
    return ret;
}


/* NB we don't shadow these 'cos there is no relation between the data written and the data read */
/* ie the read registers are read only and the write registers write only */

int
storkGetLCDCPLD(int which)
{
    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);
    return *latch;
}

int
storkClearLCDCPLD(int which, int bits)
{
    int ret = storkLCDCPLD[which];
    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);

    storkLCDCPLD[which] &= ~bits;
    *latch = storkLCDCPLD[which];
    return ret;
}

int
storkSetLatchB(int bits)
{
    int ret = storkLatchB;
    char buf[100];

    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1);
    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
    if (debug) printk(buf);

    storkLatchB |= bits;
    *latch = storkLatchB;
    return ret;
}

int
storkClearLatchB(int bits)
{
    int ret = storkLatchB;
    char buf[100];

    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1);
    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
    if (debug) printk(buf);

    storkLatchB &= ~bits;
    *latch = storkLatchB;
    return ret;
}

void
storkSetGPIO(int bits)
{
    char buf[100];

    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
    if (debug) printk(buf);
    GPSR = bits;
}

void
storkClearGPIO(int bits)
{
    char buf[100];

    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
    if (debug) printk(buf);
    GPCR = bits;
}

int
storkGetGPIO()
{
    char buf[100];

    int bits = GPLR;

    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
    if (debug) printk(buf);

    return bits;
}

/* this will return the current state of the hardware ANDED with the given bits
   so NE => at least one bit was set, but maybe not all of them! */

int
storkTestGPIO(int bits)
{
    int val = storkGetGPIO();
    char buf[100];

    sprintf(buf, "%s: bits %04x val %04x\n", __FUNCTION__, bits, val);
    if (debug) printk(buf);

    return (val & bits);
}

/* NB the touch screen and the d to a use the same data and clock out pins */

static void storkClockTS(void)
{
    storkSetLatchB(STORK_TOUCH_SCREEN_DCLK);
    udelay(10);			 /* hmm wait 200ns (min) - ok this ought to be udelay(1) but that doesn't get */
182
				 /* consistent values so I'm using 10 (urgh) */
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
    storkClearLatchB(STORK_TOUCH_SCREEN_DCLK);
    udelay(10);
}


int				/* there is always a 12 bit read after the write! */
storkClockByteToTS(int byte)
{
    int timeout = 10000;   /* stuff is meant to happen in 60ns */
    int bit;
    int result = 0;

    if (debug) printk("storkClockByteToTS: %02x\n", byte);

    storkClearLatchB(STORK_TOUCH_SCREEN_CS);  /* slect touch screen */

    while (timeout-- > 0)
        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0)
            break;

    if (timeout < 0) {
        printk("storkClockBitToTS: GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r");
/* ignore error for now        return; */
    }

/* clock out the given byte */

    for (bit = 0x80; bit > 0; bit = bit >> 1) {

        if ((bit & byte) == 0)
            storkClearLatchB(STORK_TOUCH_SCREEN_DIN);
        else
            storkSetLatchB(STORK_TOUCH_SCREEN_DIN);

        storkClockTS();
    }

    storkClockTS();  /* will be busy for at a clock  (at least) */

    for (timeout = 10000; timeout >= 0; timeout--)
        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0)
            break;

    if (timeout < 0) {
        printk("storkClockBitToTS: 2nd GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r");
/* ignore error for now        return; */
    }

/* clock in the result */

    for (bit = 0x0800; bit > 0; bit = bit >> 1) {

        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_DATA))
            result |= bit;

        storkClockTS();
    }

    storkSetLatchB(STORK_TOUCH_SCREEN_CS);  /* unselect touch screen */

    return result;
}

void
storkClockShortToDtoA(int word)
{
    int bit;

    storkClearLatchB(STORK_DA_CS);  /* select D to A */

/* clock out the given byte */

    for (bit = 0x8000; bit > 0; bit = bit >> 1) {

        if ((bit & word) == 0)
            storkClearLatchB(STORK_TOUCH_SCREEN_DIN);
        else
            storkSetLatchB(STORK_TOUCH_SCREEN_DIN);

        storkClockTS();
    }

    storkSetLatchB(STORK_DA_CS);  /* unselect D to A */

/* set DTOA#_LOAD low then high (min 20ns) to transfer value to D to A */
    storkClearLatchB(STORK_DA_LD);
    storkSetLatchB(STORK_DA_LD);
}



void
storkInitTSandDtoA(void)
{
    storkClearLatchB(STORK_TOUCH_SCREEN_DCLK | STORK_TOUCH_SCREEN_DIN);
    storkSetLatchB(STORK_TOUCH_SCREEN_CS | STORK_DA_CS | STORK_DA_LD);
    storkClockByteToTS(0xE2);	 	/* turn on the reference */
    storkClockShortToDtoA(0x8D00);	/* turn on the contrast */
    storkClockShortToDtoA(0x0A00);	/* turn on the brightness */
}

Russell King's avatar
Russell King committed
284 285 286 287 288 289 290 291 292 293 294
static void stork_lcd_power(int on)
{
	if (on) {
		storkSetLCDCPLD(0, 1);
		storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
	} else {
		storkSetLCDCPLD(0, 0);
		storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
	}
}

295
struct map_desc stork_io_desc[] __initdata = {
296 297 298 299
 /* virtual     physical    length      type */
  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, MT_DEVICE }, /* EGPIO 0 */
  { 0xf1000000, 0x10000000, 0x02800000, MT_DEVICE }, /* static memory bank 2 */
  { 0xf3800000, 0x40000000, 0x00800000, MT_DEVICE }  /* static memory bank 4 */
300 301 302 303 304 305
};

int __init
stork_map_io(void)
{
    sa1100_map_io();
306
    iotable_init(stork_io_desc, ARRAY_SIZE(stork_io_desc));
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

    sa1100_register_uart(0, 1);	/* com port */
    sa1100_register_uart(1, 2);
    sa1100_register_uart(2, 3);

    printk("Stork driver initing latches\r\n");

    storkClearLatchB(STORK_RED_LED);	/* let's have the red LED on please */
    storkSetLatchB(STORK_YELLOW_LED);
    storkSetLatchB(STORK_GREEN_LED);
    storkSetLatchA(STORK_BATTERY_CHARGER_ON);
    storkSetLatchA(STORK_LCD_5V_POWER_ON);
    storkSetLatchA(STORK_LCD_3V3_POWER_ON);

    storkInitTSandDtoA();

Russell King's avatar
Russell King committed
323 324
    sa1100fb_lcd_power = stork_lcd_power;

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    return 0;
}


MACHINE_START(STORK, "Stork Technologies prototype")
	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
	BOOT_PARAMS(0xc0000100)
	MAPIO(stork_map_io)
	INITIRQ(sa1100_init_irq)
MACHINE_END


EXPORT_SYMBOL(storkTestGPIO);
EXPORT_SYMBOL(storkSetGPIO);
EXPORT_SYMBOL(storkClearGPIO);
EXPORT_SYMBOL(storkSetLatchA);
EXPORT_SYMBOL(storkClearLatchA);
EXPORT_SYMBOL(storkSetLatchB);
EXPORT_SYMBOL(storkClearLatchB);
EXPORT_SYMBOL(storkClockByteToTS);
EXPORT_SYMBOL(storkClockShortToDtoA);
EXPORT_SYMBOL(storkGetLCDCPLD);
EXPORT_SYMBOL(storkSetLCDCPLD);