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