linux/arch/arm/mach-sa1100/jornada720_ssp.c
<<
>>
Prefs
   1/**
   2 *  arch/arm/mac-sa1100/jornada720_ssp.c
   3 *
   4 *  Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
   5 *   Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
   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 as
   9 * published by the Free Software Foundation.
  10 *
  11 *  SSP driver for the HP Jornada 710/720/728
  12 */
  13
  14#include <linux/delay.h>
  15#include <linux/errno.h>
  16#include <linux/init.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/platform_device.h>
  20#include <linux/sched.h>
  21#include <linux/io.h>
  22
  23#include <mach/hardware.h>
  24#include <mach/jornada720.h>
  25#include <asm/hardware/ssp.h>
  26
  27static DEFINE_SPINLOCK(jornada_ssp_lock);
  28static unsigned long jornada_ssp_flags;
  29
  30/**
  31 * jornada_ssp_reverse - reverses input byte
  32 *
  33 * we need to reverse all data we receive from the mcu due to its physical location
  34 * returns : 01110111 -> 11101110
  35 */
  36u8 inline jornada_ssp_reverse(u8 byte)
  37{
  38        return
  39                ((0x80 & byte) >> 7) |
  40                ((0x40 & byte) >> 5) |
  41                ((0x20 & byte) >> 3) |
  42                ((0x10 & byte) >> 1) |
  43                ((0x08 & byte) << 1) |
  44                ((0x04 & byte) << 3) |
  45                ((0x02 & byte) << 5) |
  46                ((0x01 & byte) << 7);
  47};
  48EXPORT_SYMBOL(jornada_ssp_reverse);
  49
  50/**
  51 * jornada_ssp_byte - waits for ready ssp bus and sends byte
  52 *
  53 * waits for fifo buffer to clear and then transmits, if it doesn't then we will
  54 * timeout after <timeout> rounds. Needs mcu running before its called.
  55 *
  56 * returns : %mcu output on success
  57 *         : %-ETIMEDOUT on timeout
  58 */
  59int jornada_ssp_byte(u8 byte)
  60{
  61        int timeout = 400000;
  62        u16 ret;
  63
  64        while ((GPLR & GPIO_GPIO10)) {
  65                if (!--timeout) {
  66                        printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
  67                        return -ETIMEDOUT;
  68                }
  69                cpu_relax();
  70        }
  71
  72        ret = jornada_ssp_reverse(byte) << 8;
  73
  74        ssp_write_word(ret);
  75        ssp_read_word(&ret);
  76
  77        return jornada_ssp_reverse(ret);
  78};
  79EXPORT_SYMBOL(jornada_ssp_byte);
  80
  81/**
  82 * jornada_ssp_inout - decide if input is command or trading byte
  83 *
  84 * returns : (jornada_ssp_byte(byte)) on success
  85 *         : %-ETIMEDOUT on timeout failure
  86 */
  87int jornada_ssp_inout(u8 byte)
  88{
  89        int ret, i;
  90
  91        /* true means command byte */
  92        if (byte != TXDUMMY) {
  93                ret = jornada_ssp_byte(byte);
  94                /* Proper return to commands is TxDummy */
  95                if (ret != TXDUMMY) {
  96                        for (i = 0; i < 256; i++)/* flushing bus */
  97                                if (jornada_ssp_byte(TXDUMMY) == -1)
  98                                        break;
  99                        return -ETIMEDOUT;
 100                }
 101        } else /* Exchange TxDummy for data */
 102                ret = jornada_ssp_byte(TXDUMMY);
 103
 104        return ret;
 105};
 106EXPORT_SYMBOL(jornada_ssp_inout);
 107
 108/**
 109 * jornada_ssp_start - enable mcu
 110 *
 111 */
 112void jornada_ssp_start(void)
 113{
 114        spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
 115        GPCR = GPIO_GPIO25;
 116        udelay(50);
 117        return;
 118};
 119EXPORT_SYMBOL(jornada_ssp_start);
 120
 121/**
 122 * jornada_ssp_end - disable mcu and turn off lock
 123 *
 124 */
 125void jornada_ssp_end(void)
 126{
 127        GPSR = GPIO_GPIO25;
 128        spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
 129        return;
 130};
 131EXPORT_SYMBOL(jornada_ssp_end);
 132
 133static int jornada_ssp_probe(struct platform_device *dev)
 134{
 135        int ret;
 136
 137        GPSR = GPIO_GPIO25;
 138
 139        ret = ssp_init();
 140
 141        /* worked fine, lets not bother with anything else */
 142        if (!ret) {
 143                printk(KERN_INFO "SSP: device initialized with irq\n");
 144                return ret;
 145        }
 146
 147        printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n");
 148
 149        /* init of Serial 4 port */
 150        Ser4MCCR0 = 0;
 151        Ser4SSCR0 = 0x0387;
 152        Ser4SSCR1 = 0x18;
 153
 154        /* clear out any left over data */
 155        ssp_flush();
 156
 157        /* enable MCU */
 158        jornada_ssp_start();
 159
 160        /* see if return value makes sense */
 161        ret = jornada_ssp_inout(GETBRIGHTNESS);
 162
 163        /* seems like it worked, just feed it with TxDummy to get rid of data */
 164        if (ret == TXDUMMY)
 165                jornada_ssp_inout(TXDUMMY);
 166
 167        jornada_ssp_end();
 168
 169        /* failed, lets just kill everything */
 170        if (ret == -ETIMEDOUT) {
 171                printk(KERN_WARNING "SSP: attempts failed, bailing\n");
 172                ssp_exit();
 173                return -ENODEV;
 174        }
 175
 176        /* all fine */
 177        printk(KERN_INFO "SSP: device initialized\n");
 178        return 0;
 179};
 180
 181static int jornada_ssp_remove(struct platform_device *dev)
 182{
 183        /* Note that this doesn't actually remove the driver, since theres nothing to remove
 184         * It just makes sure everything is turned off */
 185        GPSR = GPIO_GPIO25;
 186        ssp_exit();
 187        return 0;
 188};
 189
 190struct platform_driver jornadassp_driver = {
 191        .probe  = jornada_ssp_probe,
 192        .remove = jornada_ssp_remove,
 193        .driver = {
 194                .name   = "jornada_ssp",
 195        },
 196};
 197
 198static int __init jornada_ssp_init(void)
 199{
 200        return platform_driver_register(&jornadassp_driver);
 201}
 202
 203module_init(jornada_ssp_init);
 204