1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*46dd6078SRandy Dunlap /*
369ebb222SKristoffer Ericson * arch/arm/mac-sa1100/jornada720_ssp.c
469ebb222SKristoffer Ericson *
569ebb222SKristoffer Ericson * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
669ebb222SKristoffer Ericson * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
769ebb222SKristoffer Ericson *
869ebb222SKristoffer Ericson * SSP driver for the HP Jornada 710/720/728
969ebb222SKristoffer Ericson */
1069ebb222SKristoffer Ericson
1169ebb222SKristoffer Ericson #include <linux/delay.h>
1269ebb222SKristoffer Ericson #include <linux/errno.h>
1369ebb222SKristoffer Ericson #include <linux/init.h>
1469ebb222SKristoffer Ericson #include <linux/kernel.h>
1569ebb222SKristoffer Ericson #include <linux/module.h>
1669ebb222SKristoffer Ericson #include <linux/platform_device.h>
1769ebb222SKristoffer Ericson #include <linux/sched.h>
183169663aSRussell King #include <linux/io.h>
1969ebb222SKristoffer Ericson
20a09e64fbSRussell King #include <mach/hardware.h>
21a09e64fbSRussell King #include <mach/jornada720.h>
2258005b32SKristoffer Ericson #include <asm/hardware/ssp.h>
2369ebb222SKristoffer Ericson
2469ebb222SKristoffer Ericson static DEFINE_SPINLOCK(jornada_ssp_lock);
2569ebb222SKristoffer Ericson static unsigned long jornada_ssp_flags;
2669ebb222SKristoffer Ericson
2769ebb222SKristoffer Ericson /**
2869ebb222SKristoffer Ericson * jornada_ssp_reverse - reverses input byte
29*46dd6078SRandy Dunlap * @byte: input byte to reverse
3069ebb222SKristoffer Ericson *
3125985edcSLucas De Marchi * we need to reverse all data we receive from the mcu due to its physical location
3269ebb222SKristoffer Ericson * returns : 01110111 -> 11101110
3369ebb222SKristoffer Ericson */
jornada_ssp_reverse(u8 byte)341e90d0edSJoe Perches inline u8 jornada_ssp_reverse(u8 byte)
3569ebb222SKristoffer Ericson {
3669ebb222SKristoffer Ericson return
3769ebb222SKristoffer Ericson ((0x80 & byte) >> 7) |
3869ebb222SKristoffer Ericson ((0x40 & byte) >> 5) |
3969ebb222SKristoffer Ericson ((0x20 & byte) >> 3) |
4069ebb222SKristoffer Ericson ((0x10 & byte) >> 1) |
4169ebb222SKristoffer Ericson ((0x08 & byte) << 1) |
4269ebb222SKristoffer Ericson ((0x04 & byte) << 3) |
4369ebb222SKristoffer Ericson ((0x02 & byte) << 5) |
4469ebb222SKristoffer Ericson ((0x01 & byte) << 7);
4569ebb222SKristoffer Ericson };
4669ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_reverse);
4769ebb222SKristoffer Ericson
4869ebb222SKristoffer Ericson /**
4969ebb222SKristoffer Ericson * jornada_ssp_byte - waits for ready ssp bus and sends byte
50*46dd6078SRandy Dunlap * @byte: input byte to transmit
5169ebb222SKristoffer Ericson *
5269ebb222SKristoffer Ericson * waits for fifo buffer to clear and then transmits, if it doesn't then we will
5369ebb222SKristoffer Ericson * timeout after <timeout> rounds. Needs mcu running before its called.
5469ebb222SKristoffer Ericson *
5569ebb222SKristoffer Ericson * returns : %mcu output on success
563ac49a1cSJean Delvare * : %-ETIMEDOUT on timeout
5769ebb222SKristoffer Ericson */
jornada_ssp_byte(u8 byte)5869ebb222SKristoffer Ericson int jornada_ssp_byte(u8 byte)
5969ebb222SKristoffer Ericson {
6069ebb222SKristoffer Ericson int timeout = 400000;
6169ebb222SKristoffer Ericson u16 ret;
6269ebb222SKristoffer Ericson
6369ebb222SKristoffer Ericson while ((GPLR & GPIO_GPIO10)) {
6469ebb222SKristoffer Ericson if (!--timeout) {
6569ebb222SKristoffer Ericson printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
6669ebb222SKristoffer Ericson return -ETIMEDOUT;
6769ebb222SKristoffer Ericson }
6869ebb222SKristoffer Ericson cpu_relax();
6969ebb222SKristoffer Ericson }
7069ebb222SKristoffer Ericson
7169ebb222SKristoffer Ericson ret = jornada_ssp_reverse(byte) << 8;
7269ebb222SKristoffer Ericson
7369ebb222SKristoffer Ericson ssp_write_word(ret);
7469ebb222SKristoffer Ericson ssp_read_word(&ret);
7569ebb222SKristoffer Ericson
7669ebb222SKristoffer Ericson return jornada_ssp_reverse(ret);
7769ebb222SKristoffer Ericson };
7869ebb222SKristoffer Ericson EXPORT_SYMBOL(jornada_ssp_byte);
7969ebb222SKristoffer Ericson
8069ebb222SKristoffer Ericson /**
8169ebb222SKristoffer Ericson * jornada_ssp_inout - decide if input is command or trading byte
82*46dd6078SRandy Dunlap * @byte: input byte to send (may be %TXDUMMY)
8369ebb222SKristoffer Ericson *
8469ebb222SKristoffer Ericson * returns : (jornada_ssp_byte(byte)) on success
853ac49a1cSJean Delvare * : %-ETIMEDOUT on timeout failure
8669ebb222SKristoffer Ericson */
jornada_ssp_inout(u8 byte)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 */
jornada_ssp_start(void)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 */
jornada_ssp_end(void)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
jornada_ssp_probe(struct platform_device * dev)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
jornada_ssp_remove(struct platform_device * dev)18174a5b94bSUwe Kleine-König static void 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 };
18869ebb222SKristoffer Ericson
18969ebb222SKristoffer Ericson struct platform_driver jornadassp_driver = {
19069ebb222SKristoffer Ericson .probe = jornada_ssp_probe,
19174a5b94bSUwe Kleine-König .remove_new = jornada_ssp_remove,
19269ebb222SKristoffer Ericson .driver = {
19369ebb222SKristoffer Ericson .name = "jornada_ssp",
19469ebb222SKristoffer Ericson },
19569ebb222SKristoffer Ericson };
19669ebb222SKristoffer Ericson
jornada_ssp_init(void)19769ebb222SKristoffer Ericson static int __init jornada_ssp_init(void)
19869ebb222SKristoffer Ericson {
19969ebb222SKristoffer Ericson return platform_driver_register(&jornadassp_driver);
20069ebb222SKristoffer Ericson }
201b3945bcbSLinus Walleij
202b3945bcbSLinus Walleij module_init(jornada_ssp_init);
203