aboutsummaryrefslogblamecommitdiffstats
path: root/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
blob: fd033bb4342fc37f928bece12fcfb969fead5610 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14












                                                                 
 
                          
                         
                      
 
                   




























                                                          
                                            



                                          
                                                                          




                                            
                                                         
                                           
                                                    
















































                                                                           
                                                       






                                                       
/* arch/arm/mach-lh7a40x/irq-lpd7a40x.c
 *
 *  Copyright (C) 2004 Coastal Environmental Systems
 *  Copyright (C) 2004 Logic Product Development
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  version 2 as published by the Free Software Foundation.
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>

#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <mach/irqs.h>

#include "common.h"

static void lh7a40x_ack_cpld_irq (u32 irq)
{
	/* CPLD doesn't have ack capability */
}

static void lh7a40x_mask_cpld_irq (u32 irq)
{
	switch (irq) {
	case IRQ_LPD7A40X_ETH_INT:
		CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4;
		break;
	case IRQ_LPD7A400_TS:
		CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8;
		break;
	}
}

static void lh7a40x_unmask_cpld_irq (u32 irq)
{
	switch (irq) {
	case IRQ_LPD7A40X_ETH_INT:
		CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4;
		break;
	case IRQ_LPD7A400_TS:
		CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8;
		break;
	}
}

static struct irq_chip lh7a40x_cpld_chip = {
	.name	= "CPLD",
	.ack	= lh7a40x_ack_cpld_irq,
	.mask	= lh7a40x_mask_cpld_irq,
	.unmask	= lh7a40x_unmask_cpld_irq,
};

static void lh7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
{
	unsigned int mask = CPLD_INTERRUPTS;

	desc->chip->ack (irq);

	if ((mask & 0x1) == 0)	/* WLAN */
		generic_handle_irq(IRQ_LPD7A40X_ETH_INT);

	if ((mask & 0x2) == 0)	/* Touch */
		generic_handle_irq(IRQ_LPD7A400_TS);

	desc->chip->unmask (irq); /* Level-triggered need this */
}


  /* IRQ initialization */

void __init lh7a40x_init_board_irq (void)
{
	int irq;

		/* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
		                 PF7 supports the CPLD.
		   Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
		                 PF3 supports the CPLD.
		   (Some) LPD7A404 prerelease boards report a version
		   number of 0x16, but we force an override since the
		   hardware is of the newer variety.
		*/

	unsigned char cpld_version = CPLD_REVISION;
	int pinCPLD;

#if defined CONFIG_MACH_LPD7A404
	cpld_version = 0x34;	/* Override, for now */
#endif
	pinCPLD = (cpld_version == 0x28) ? 7 : 3;

		/* First, configure user controlled GPIOF interrupts  */

	GPIO_PFDD	&= ~0x0f; /* PF0-3 are inputs */
	GPIO_INTTYPE1	&= ~0x0f; /* PF0-3 are level triggered */
	GPIO_INTTYPE2	&= ~0x0f; /* PF0-3 are active low */
	barrier ();
	GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */

		/* Then, configure CPLD interrupt */

	CPLD_INTERRUPTS	=   0x0c; /* Disable all CPLD interrupts */
	GPIO_PFDD	&= ~(1 << pinCPLD); /* Make input */
	GPIO_INTTYPE1	|=  (1 << pinCPLD); /* Edge triggered */
	GPIO_INTTYPE2	&= ~(1 << pinCPLD); /* Active low */
	barrier ();
	GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */

		/* Cascade CPLD interrupts */

	for (irq = IRQ_BOARD_START;
	     irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
		set_irq_chip (irq, &lh7a40x_cpld_chip);
		set_irq_handler (irq, handle_edge_irq);
		set_irq_flags (irq, IRQF_VALID);
	}

	set_irq_chained_handler ((cpld_version == 0x28)
				 ? IRQ_CPLD_V28
				 : IRQ_CPLD_V34,
				 lh7a40x_cpld_handler);
}
t;Simple test 8: write 8 bytes, read back 8 bytes garbage " "in 16bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) pr_warning("Simple test 8: FAILURE: spi_write_then_read() " "failed with status %d\n", status); else pr_info("Simple test 8: SUCCESS!\n"); pr_info("Simple test 9: write 14 bytes, read back 14 bytes garbage " "in 16bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) pr_warning("Simple test 9: FAILURE: failed with status %d " "(probably FIFO overrun)\n", status); else pr_info("Simple test 9: SUCCESS!\n"); pr_info("Simple test 10: write %d bytes with spi_write(), " "read %d bytes garbage with spi_read() in 16bit mode\n", DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) pr_warning("Simple test 10 step 1: FAILURE: spi_write() " "failed with status %d (probably FIFO overrun)\n", status); else pr_info("Simple test 10 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) pr_warning("Simple test 10 step 2: FAILURE: spi_read() " "failed with status %d (probably FIFO overrun)\n", status); else pr_info("Simple test 10: SUCCESS!\n"); status = sprintf(buf, "loop test complete\n"); kfree(bigrxbuf_virtual); kfree(bigtxbuf_virtual); out: mutex_unlock(&p_dummy->lock); return status; } static DEVICE_ATTR(looptest, S_IRUGO, dummy_looptest, NULL); static int __devinit pl022_dummy_probe(struct spi_device *spi) { struct dummy *p_dummy; int status; dev_info(&spi->dev, "probing dummy SPI device\n"); p_dummy = kzalloc(sizeof *p_dummy, GFP_KERNEL); if (!p_dummy) return -ENOMEM; dev_set_drvdata(&spi->dev, p_dummy); mutex_init(&p_dummy->lock); /* sysfs hook */ status = device_create_file(&spi->dev, &dev_attr_looptest); if (status) { dev_dbg(&spi->dev, "device_create_file looptest failure.\n"); goto out_dev_create_looptest_failed; } return 0; out_dev_create_looptest_failed: dev_set_drvdata(&spi->dev, NULL); kfree(p_dummy); return status; } static int __devexit pl022_dummy_remove(struct spi_device *spi) { struct dummy *p_dummy = dev_get_drvdata(&spi->dev); dev_info(&spi->dev, "removing dummy SPI device\n"); device_remove_file(&spi->dev, &dev_attr_looptest); dev_set_drvdata(&spi->dev, NULL); kfree(p_dummy); return 0; } static struct spi_driver pl022_dummy_driver = { .driver = { .name = "spi-dummy", .owner = THIS_MODULE, }, .probe = pl022_dummy_probe, .remove = __devexit_p(pl022_dummy_remove), }; static int __init pl022_init_dummy(void) { return spi_register_driver(&pl022_dummy_driver); } static void __exit pl022_exit_dummy(void) { spi_unregister_driver(&pl022_dummy_driver); } module_init(pl022_init_dummy); module_exit(pl022_exit_dummy); MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); MODULE_DESCRIPTION("PL022 SSP/SPI DUMMY Linux driver"); MODULE_LICENSE("GPL");