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