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 * @byte: input byte to reverse 30 * 31 * we need to reverse all data we receive from the mcu due to its physical location 32 * returns : 01110111 -> 11101110 33 */ 34 inline u8 jornada_ssp_reverse(u8 byte) 35 { 36 return 37 ((0x80 & byte) >> 7) | 38 ((0x40 & byte) >> 5) | 39 ((0x20 & byte) >> 3) | 40 ((0x10 & byte) >> 1) | 41 ((0x08 & byte) << 1) | 42 ((0x04 & byte) << 3) | 43 ((0x02 & byte) << 5) | 44 ((0x01 & byte) << 7); 45 }; 46 EXPORT_SYMBOL(jornada_ssp_reverse); 47 48 /** 49 * jornada_ssp_byte - waits for ready ssp bus and sends byte 50 * @byte: input byte to transmit 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 * @byte: input byte to send (may be %TXDUMMY) 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 void 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 }; 188 189 struct platform_driver jornadassp_driver = { 190 .probe = jornada_ssp_probe, 191 .remove_new = 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