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 27 static DEFINE_SPINLOCK(jornada_ssp_lock); 28 static 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 */ 36 u8 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 }; 48 EXPORT_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 */ 59 int 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 }; 79 EXPORT_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 */ 87 int 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 }; 106 EXPORT_SYMBOL(jornada_ssp_inout); 107 108 /** 109 * jornada_ssp_start - enable mcu 110 * 111 */ 112 void 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 }; 119 EXPORT_SYMBOL(jornada_ssp_start); 120 121 /** 122 * jornada_ssp_end - disable mcu and turn off lock 123 * 124 */ 125 void jornada_ssp_end(void) 126 { 127 GPSR = GPIO_GPIO25; 128 spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags); 129 return; 130 }; 131 EXPORT_SYMBOL(jornada_ssp_end); 132 133 static 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 181 static 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 190 struct platform_driver jornadassp_driver = { 191 .probe = jornada_ssp_probe, 192 .remove = jornada_ssp_remove, 193 .driver = { 194 .name = "jornada_ssp", 195 }, 196 }; 197 198 static int __init jornada_ssp_init(void) 199 { 200 return platform_driver_register(&jornadassp_driver); 201 } 202 203 module_init(jornada_ssp_init); 204