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 24 static DEFINE_SPINLOCK(jornada_ssp_lock); 25 static 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 */ 33 inline 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 }; 45 EXPORT_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 */ 56 int 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 }; 76 EXPORT_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 */ 84 int 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 }; 103 EXPORT_SYMBOL(jornada_ssp_inout); 104 105 /** 106 * jornada_ssp_start - enable mcu 107 * 108 */ 109 void 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 }; 116 EXPORT_SYMBOL(jornada_ssp_start); 117 118 /** 119 * jornada_ssp_end - disable mcu and turn off lock 120 * 121 */ 122 void jornada_ssp_end(void) 123 { 124 GPSR = GPIO_GPIO25; 125 spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags); 126 return; 127 }; 128 EXPORT_SYMBOL(jornada_ssp_end); 129 130 static 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 178 static 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 187 struct platform_driver jornadassp_driver = { 188 .probe = jornada_ssp_probe, 189 .remove = jornada_ssp_remove, 190 .driver = { 191 .name = "jornada_ssp", 192 }, 193 }; 194 195 static int __init jornada_ssp_init(void) 196 { 197 return platform_driver_register(&jornadassp_driver); 198 } 199 200 module_init(jornada_ssp_init); 201