Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /**
0003  *  arch/arm/mac-sa1100/jornada720_ssp.c
0004  *
0005  *  Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
0006  *   Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
0007  *
0008  *  SSP driver for the HP Jornada 710/720/728
0009  */
0010 
0011 #include <linux/delay.h>
0012 #include <linux/errno.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/sched.h>
0018 #include <linux/io.h>
0019 
0020 #include <mach/hardware.h>
0021 #include <mach/jornada720.h>
0022 #include <asm/hardware/ssp.h>
0023 
0024 static DEFINE_SPINLOCK(jornada_ssp_lock);
0025 static unsigned long jornada_ssp_flags;
0026 
0027 /**
0028  * jornada_ssp_reverse - reverses input byte
0029  *
0030  * we need to reverse all data we receive from the mcu due to its physical location
0031  * returns : 01110111 -> 11101110
0032  */
0033 inline u8 jornada_ssp_reverse(u8 byte)
0034 {
0035     return
0036         ((0x80 & byte) >> 7) |
0037         ((0x40 & byte) >> 5) |
0038         ((0x20 & byte) >> 3) |
0039         ((0x10 & byte) >> 1) |
0040         ((0x08 & byte) << 1) |
0041         ((0x04 & byte) << 3) |
0042         ((0x02 & byte) << 5) |
0043         ((0x01 & byte) << 7);
0044 };
0045 EXPORT_SYMBOL(jornada_ssp_reverse);
0046 
0047 /**
0048  * jornada_ssp_byte - waits for ready ssp bus and sends byte
0049  *
0050  * waits for fifo buffer to clear and then transmits, if it doesn't then we will
0051  * timeout after <timeout> rounds. Needs mcu running before its called.
0052  *
0053  * returns : %mcu output on success
0054  *     : %-ETIMEDOUT on timeout
0055  */
0056 int jornada_ssp_byte(u8 byte)
0057 {
0058     int timeout = 400000;
0059     u16 ret;
0060 
0061     while ((GPLR & GPIO_GPIO10)) {
0062         if (!--timeout) {
0063             printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
0064             return -ETIMEDOUT;
0065         }
0066         cpu_relax();
0067     }
0068 
0069     ret = jornada_ssp_reverse(byte) << 8;
0070 
0071     ssp_write_word(ret);
0072     ssp_read_word(&ret);
0073 
0074     return jornada_ssp_reverse(ret);
0075 };
0076 EXPORT_SYMBOL(jornada_ssp_byte);
0077 
0078 /**
0079  * jornada_ssp_inout - decide if input is command or trading byte
0080  *
0081  * returns : (jornada_ssp_byte(byte)) on success
0082  *         : %-ETIMEDOUT on timeout failure
0083  */
0084 int jornada_ssp_inout(u8 byte)
0085 {
0086     int ret, i;
0087 
0088     /* true means command byte */
0089     if (byte != TXDUMMY) {
0090         ret = jornada_ssp_byte(byte);
0091         /* Proper return to commands is TxDummy */
0092         if (ret != TXDUMMY) {
0093             for (i = 0; i < 256; i++)/* flushing bus */
0094                 if (jornada_ssp_byte(TXDUMMY) == -1)
0095                     break;
0096             return -ETIMEDOUT;
0097         }
0098     } else /* Exchange TxDummy for data */
0099         ret = jornada_ssp_byte(TXDUMMY);
0100 
0101     return ret;
0102 };
0103 EXPORT_SYMBOL(jornada_ssp_inout);
0104 
0105 /**
0106  * jornada_ssp_start - enable mcu
0107  *
0108  */
0109 void jornada_ssp_start(void)
0110 {
0111     spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
0112     GPCR = GPIO_GPIO25;
0113     udelay(50);
0114     return;
0115 };
0116 EXPORT_SYMBOL(jornada_ssp_start);
0117 
0118 /**
0119  * jornada_ssp_end - disable mcu and turn off lock
0120  *
0121  */
0122 void jornada_ssp_end(void)
0123 {
0124     GPSR = GPIO_GPIO25;
0125     spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
0126     return;
0127 };
0128 EXPORT_SYMBOL(jornada_ssp_end);
0129 
0130 static int jornada_ssp_probe(struct platform_device *dev)
0131 {
0132     int ret;
0133 
0134     GPSR = GPIO_GPIO25;
0135 
0136     ret = ssp_init();
0137 
0138     /* worked fine, lets not bother with anything else */
0139     if (!ret) {
0140         printk(KERN_INFO "SSP: device initialized with irq\n");
0141         return ret;
0142     }
0143 
0144     printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n");
0145 
0146     /* init of Serial 4 port */
0147     Ser4MCCR0 = 0;
0148     Ser4SSCR0 = 0x0387;
0149     Ser4SSCR1 = 0x18;
0150 
0151     /* clear out any left over data */
0152     ssp_flush();
0153 
0154     /* enable MCU */
0155     jornada_ssp_start();
0156 
0157     /* see if return value makes sense */
0158     ret = jornada_ssp_inout(GETBRIGHTNESS);
0159 
0160     /* seems like it worked, just feed it with TxDummy to get rid of data */
0161     if (ret == TXDUMMY)
0162         jornada_ssp_inout(TXDUMMY);
0163 
0164     jornada_ssp_end();
0165 
0166     /* failed, lets just kill everything */
0167     if (ret == -ETIMEDOUT) {
0168         printk(KERN_WARNING "SSP: attempts failed, bailing\n");
0169         ssp_exit();
0170         return -ENODEV;
0171     }
0172 
0173     /* all fine */
0174     printk(KERN_INFO "SSP: device initialized\n");
0175     return 0;
0176 };
0177 
0178 static int jornada_ssp_remove(struct platform_device *dev)
0179 {
0180     /* Note that this doesn't actually remove the driver, since theres nothing to remove
0181      * It just makes sure everything is turned off */
0182     GPSR = GPIO_GPIO25;
0183     ssp_exit();
0184     return 0;
0185 };
0186 
0187 struct platform_driver jornadassp_driver = {
0188     .probe  = jornada_ssp_probe,
0189     .remove = jornada_ssp_remove,
0190     .driver = {
0191         .name   = "jornada_ssp",
0192     },
0193 };
0194 
0195 static int __init jornada_ssp_init(void)
0196 {
0197     return platform_driver_register(&jornadassp_driver);
0198 }
0199 
0200 module_init(jornada_ssp_init);