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