169ebb222SKristoffer Ericson /** 269ebb222SKristoffer Ericson * arch/arm/mac-sa1100/jornada720_ssp.c 369ebb222SKristoffer Ericson * 469ebb222SKristoffer Ericson * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> 569ebb222SKristoffer Ericson * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> 669ebb222SKristoffer Ericson * 769ebb222SKristoffer Ericson * This program is free software; you can redistribute it and/or modify 869ebb222SKristoffer Ericson * it under the terms of the GNU General Public License version 2 as 969ebb222SKristoffer Ericson * published by the Free Software Foundation. 1069ebb222SKristoffer Ericson * 1169ebb222SKristoffer Ericson * SSP driver for the HP Jornada 710/720/728 1269ebb222SKristoffer Ericson */ 1369ebb222SKristoffer Ericson 1469ebb222SKristoffer Ericson #include <linux/delay.h> 1569ebb222SKristoffer Ericson #include <linux/errno.h> 1669ebb222SKristoffer Ericson #include <linux/init.h> 1769ebb222SKristoffer Ericson #include <linux/kernel.h> 1869ebb222SKristoffer Ericson #include <linux/module.h> 1969ebb222SKristoffer Ericson #include <linux/platform_device.h> 2069ebb222SKristoffer Ericson #include <linux/sched.h> 213169663aSRussell King #include <linux/io.h> 2269ebb222SKristoffer Ericson 23a09e64fbSRussell King #include <mach/hardware.h> 24a09e64fbSRussell King #include <mach/jornada720.h> 2558005b32SKristoffer Ericson #include <asm/hardware/ssp.h> 2669ebb222SKristoffer Ericson 2769ebb222SKristoffer Ericson static DEFINE_SPINLOCK(jornada_ssp_lock); 2869ebb222SKristoffer Ericson static unsigned long jornada_ssp_flags; 2969ebb222SKristoffer Ericson 3069ebb222SKristoffer Ericson /** 3169ebb222SKristoffer Ericson * jornada_ssp_reverse - reverses input byte 3269ebb222SKristoffer Ericson * 3325985edcSLucas De Marchi * we need to reverse all data we receive from the mcu due to its physical location 3469ebb222SKristoffer Ericson * returns : 01110111 -> 11101110 3569ebb222SKristoffer Ericson */ 361e90d0edSJoe Perches inline u8 jornada_ssp_reverse(u8 byte) 3769ebb222SKristoffer Ericson { 3869ebb222SKristoffer Ericson return 3969ebb222SKristoffer Ericson ((0x80 & byte) >> 7) | 4069ebb222SKristoffer Ericson ((0x40 & byte) >> 5) | 4169ebb222SKristoffer Ericson ((0x20 & byte) >> 3) | 4269ebb222SKristoffer Ericson ((0x10 & byte) >> 1) | 4369ebb222SKristoffer Ericson ((0x08 & byte) << 1) | 4469ebb222SKristoffer Ericson ((0x04 & byte) << 3) | 4569ebb222SKristoffer Ericson ((0x02 & byte) << 5) | 4669ebb222SKristoffer Ericson ((0x01 & byte) << 7); 4769ebb222SKristoffer Ericson }; 4869ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_reverse); 4969ebb222SKristoffer Ericson 5069ebb222SKristoffer Ericson /** 5169ebb222SKristoffer Ericson * jornada_ssp_byte - waits for ready ssp bus and sends byte 5269ebb222SKristoffer Ericson * 5369ebb222SKristoffer Ericson * waits for fifo buffer to clear and then transmits, if it doesn't then we will 5469ebb222SKristoffer Ericson * timeout after <timeout> rounds. Needs mcu running before its called. 5569ebb222SKristoffer Ericson * 5669ebb222SKristoffer Ericson * returns : %mcu output on success 573ac49a1cSJean Delvare * : %-ETIMEDOUT on timeout 5869ebb222SKristoffer Ericson */ 5969ebb222SKristoffer Ericson int jornada_ssp_byte(u8 byte) 6069ebb222SKristoffer Ericson { 6169ebb222SKristoffer Ericson int timeout = 400000; 6269ebb222SKristoffer Ericson u16 ret; 6369ebb222SKristoffer Ericson 6469ebb222SKristoffer Ericson while ((GPLR & GPIO_GPIO10)) { 6569ebb222SKristoffer Ericson if (!--timeout) { 6669ebb222SKristoffer Ericson printk(KERN_WARNING "SSP: timeout while waiting for transmit\n"); 6769ebb222SKristoffer Ericson return -ETIMEDOUT; 6869ebb222SKristoffer Ericson } 6969ebb222SKristoffer Ericson cpu_relax(); 7069ebb222SKristoffer Ericson } 7169ebb222SKristoffer Ericson 7269ebb222SKristoffer Ericson ret = jornada_ssp_reverse(byte) << 8; 7369ebb222SKristoffer Ericson 7469ebb222SKristoffer Ericson ssp_write_word(ret); 7569ebb222SKristoffer Ericson ssp_read_word(&ret); 7669ebb222SKristoffer Ericson 7769ebb222SKristoffer Ericson return jornada_ssp_reverse(ret); 7869ebb222SKristoffer Ericson }; 7969ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_byte); 8069ebb222SKristoffer Ericson 8169ebb222SKristoffer Ericson /** 8269ebb222SKristoffer Ericson * jornada_ssp_inout - decide if input is command or trading byte 8369ebb222SKristoffer Ericson * 8469ebb222SKristoffer Ericson * returns : (jornada_ssp_byte(byte)) on success 853ac49a1cSJean Delvare * : %-ETIMEDOUT on timeout failure 8669ebb222SKristoffer Ericson */ 8769ebb222SKristoffer Ericson int jornada_ssp_inout(u8 byte) 8869ebb222SKristoffer Ericson { 8969ebb222SKristoffer Ericson int ret, i; 9069ebb222SKristoffer Ericson 9169ebb222SKristoffer Ericson /* true means command byte */ 9269ebb222SKristoffer Ericson if (byte != TXDUMMY) { 9369ebb222SKristoffer Ericson ret = jornada_ssp_byte(byte); 9469ebb222SKristoffer Ericson /* Proper return to commands is TxDummy */ 9569ebb222SKristoffer Ericson if (ret != TXDUMMY) { 9669ebb222SKristoffer Ericson for (i = 0; i < 256; i++)/* flushing bus */ 9769ebb222SKristoffer Ericson if (jornada_ssp_byte(TXDUMMY) == -1) 9869ebb222SKristoffer Ericson break; 9969ebb222SKristoffer Ericson return -ETIMEDOUT; 10069ebb222SKristoffer Ericson } 10169ebb222SKristoffer Ericson } else /* Exchange TxDummy for data */ 10269ebb222SKristoffer Ericson ret = jornada_ssp_byte(TXDUMMY); 10369ebb222SKristoffer Ericson 10469ebb222SKristoffer Ericson return ret; 10569ebb222SKristoffer Ericson }; 10669ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_inout); 10769ebb222SKristoffer Ericson 10869ebb222SKristoffer Ericson /** 10969ebb222SKristoffer Ericson * jornada_ssp_start - enable mcu 11069ebb222SKristoffer Ericson * 11169ebb222SKristoffer Ericson */ 11258005b32SKristoffer Ericson void jornada_ssp_start(void) 11369ebb222SKristoffer Ericson { 11469ebb222SKristoffer Ericson spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags); 11569ebb222SKristoffer Ericson GPCR = GPIO_GPIO25; 11669ebb222SKristoffer Ericson udelay(50); 11758005b32SKristoffer Ericson return; 11869ebb222SKristoffer Ericson }; 11969ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_start); 12069ebb222SKristoffer Ericson 12169ebb222SKristoffer Ericson /** 12269ebb222SKristoffer Ericson * jornada_ssp_end - disable mcu and turn off lock 12369ebb222SKristoffer Ericson * 12469ebb222SKristoffer Ericson */ 12558005b32SKristoffer Ericson void jornada_ssp_end(void) 12669ebb222SKristoffer Ericson { 12769ebb222SKristoffer Ericson GPSR = GPIO_GPIO25; 12869ebb222SKristoffer Ericson spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags); 12958005b32SKristoffer Ericson return; 13069ebb222SKristoffer Ericson }; 13169ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_end); 13269ebb222SKristoffer Ericson 133351a102dSGreg Kroah-Hartman static int jornada_ssp_probe(struct platform_device *dev) 13469ebb222SKristoffer Ericson { 13569ebb222SKristoffer Ericson int ret; 13669ebb222SKristoffer Ericson 13769ebb222SKristoffer Ericson GPSR = GPIO_GPIO25; 13869ebb222SKristoffer Ericson 13969ebb222SKristoffer Ericson ret = ssp_init(); 14069ebb222SKristoffer Ericson 14169ebb222SKristoffer Ericson /* worked fine, lets not bother with anything else */ 14269ebb222SKristoffer Ericson if (!ret) { 14369ebb222SKristoffer Ericson printk(KERN_INFO "SSP: device initialized with irq\n"); 14469ebb222SKristoffer Ericson return ret; 14569ebb222SKristoffer Ericson } 14669ebb222SKristoffer Ericson 14769ebb222SKristoffer Ericson printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n"); 14869ebb222SKristoffer Ericson 14969ebb222SKristoffer Ericson /* init of Serial 4 port */ 15069ebb222SKristoffer Ericson Ser4MCCR0 = 0; 15169ebb222SKristoffer Ericson Ser4SSCR0 = 0x0387; 15269ebb222SKristoffer Ericson Ser4SSCR1 = 0x18; 15369ebb222SKristoffer Ericson 15469ebb222SKristoffer Ericson /* clear out any left over data */ 15569ebb222SKristoffer Ericson ssp_flush(); 15669ebb222SKristoffer Ericson 15769ebb222SKristoffer Ericson /* enable MCU */ 15869ebb222SKristoffer Ericson jornada_ssp_start(); 15969ebb222SKristoffer Ericson 16069ebb222SKristoffer Ericson /* see if return value makes sense */ 16169ebb222SKristoffer Ericson ret = jornada_ssp_inout(GETBRIGHTNESS); 16269ebb222SKristoffer Ericson 16369ebb222SKristoffer Ericson /* seems like it worked, just feed it with TxDummy to get rid of data */ 164219e3dcdSKristoffer Ericson if (ret == TXDUMMY) 16569ebb222SKristoffer Ericson jornada_ssp_inout(TXDUMMY); 16669ebb222SKristoffer Ericson 16769ebb222SKristoffer Ericson jornada_ssp_end(); 16869ebb222SKristoffer Ericson 16969ebb222SKristoffer Ericson /* failed, lets just kill everything */ 17069ebb222SKristoffer Ericson if (ret == -ETIMEDOUT) { 17169ebb222SKristoffer Ericson printk(KERN_WARNING "SSP: attempts failed, bailing\n"); 17269ebb222SKristoffer Ericson ssp_exit(); 17369ebb222SKristoffer Ericson return -ENODEV; 17469ebb222SKristoffer Ericson } 17569ebb222SKristoffer Ericson 17669ebb222SKristoffer Ericson /* all fine */ 17769ebb222SKristoffer Ericson printk(KERN_INFO "SSP: device initialized\n"); 17869ebb222SKristoffer Ericson return 0; 17969ebb222SKristoffer Ericson }; 18069ebb222SKristoffer Ericson 18169ebb222SKristoffer Ericson static int jornada_ssp_remove(struct platform_device *dev) 18269ebb222SKristoffer Ericson { 18325985edcSLucas De Marchi /* Note that this doesn't actually remove the driver, since theres nothing to remove 18469ebb222SKristoffer Ericson * It just makes sure everything is turned off */ 18569ebb222SKristoffer Ericson GPSR = GPIO_GPIO25; 18669ebb222SKristoffer Ericson ssp_exit(); 18769ebb222SKristoffer Ericson return 0; 18869ebb222SKristoffer Ericson }; 18969ebb222SKristoffer Ericson 19069ebb222SKristoffer Ericson struct platform_driver jornadassp_driver = { 19169ebb222SKristoffer Ericson .probe = jornada_ssp_probe, 19269ebb222SKristoffer Ericson .remove = jornada_ssp_remove, 19369ebb222SKristoffer Ericson .driver = { 19469ebb222SKristoffer Ericson .name = "jornada_ssp", 19569ebb222SKristoffer Ericson }, 19669ebb222SKristoffer Ericson }; 19769ebb222SKristoffer Ericson 19869ebb222SKristoffer Ericson static int __init jornada_ssp_init(void) 19969ebb222SKristoffer Ericson { 20069ebb222SKristoffer Ericson return platform_driver_register(&jornadassp_driver); 20169ebb222SKristoffer Ericson } 202b3945bcbSLinus Walleij 203b3945bcbSLinus Walleij module_init(jornada_ssp_init); 204