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 26 static DEFINE_SPINLOCK(jornada_ssp_lock); 27 static unsigned long jornada_ssp_flags; 28 29 /** 30 * jornada_ssp_reverse - reverses input byte 31 * 32 * we need to reverse all data we receive from the mcu due to its physical location 33 * returns : 01110111 -> 11101110 34 */ 35 u8 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 }; 47 EXPORT_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 */ 58 int 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 }; 78 EXPORT_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 */ 86 int 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 }; 105 EXPORT_SYMBOL(jornada_ssp_inout); 106 107 /** 108 * jornada_ssp_start - enable mcu 109 * 110 */ 111 void 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 }; 118 EXPORT_SYMBOL(jornada_ssp_start); 119 120 /** 121 * jornada_ssp_end - disable mcu and turn off lock 122 * 123 */ 124 void jornada_ssp_end(void) 125 { 126 GPSR = GPIO_GPIO25; 127 spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags); 128 return; 129 }; 130 EXPORT_SYMBOL(jornada_ssp_end); 131 132 static 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 180 static int jornada_ssp_remove(struct platform_device *dev) 181 { 182 /* Note that this doesn't 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 189 struct platform_driver jornadassp_driver = { 190 .probe = jornada_ssp_probe, 191 .remove = jornada_ssp_remove, 192 .driver = { 193 .name = "jornada_ssp", 194 }, 195 }; 196 197 static int __init jornada_ssp_init(void) 198 { 199 return platform_driver_register(&jornadassp_driver); 200 } 201 202 module_init(jornada_ssp_init); 203