diff options
Diffstat (limited to 'arch/arm/mach-sa1100/jornada56x_asic.c')
-rw-r--r-- | arch/arm/mach-sa1100/jornada56x_asic.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/arch/arm/mach-sa1100/jornada56x_asic.c b/arch/arm/mach-sa1100/jornada56x_asic.c new file mode 100644 index 00000000000000..916843187aae16 --- /dev/null +++ b/arch/arm/mach-sa1100/jornada56x_asic.c @@ -0,0 +1,341 @@ +/* + * linux/arch/arm/mach-sa1100/jornada56x_asic.c + * + * HP Jornada560 Series init code + * + * Copyright (C) 2008 Michael J Kaye <mjkaye@ippimail.com> + * Based on jornada56x.c from the Handhelds.org tree, copyright Alex Lange, + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <asm/arch/jornada56x.h> + + +/************************************ + * * + * Jornada 56x Microwire functions * + * * + ************************************/ +int microwire_data[8]; + + +#define ASIC_INT_DELAY 10 /* Poll every 10 milliseconds */ +enum {PCR_GET_VALUE=1, PCR_SET_VALUE, PCR_BIT_SET, PCR_BIT_CLEAR}; + + + +void SetPMUPCRRegister(long arg_action, long arg_value) +{ + long this_pcr; + + /* Read PCR and remove the unwanted bit 6 */ + this_pcr = (((JORNADA_PCR & 0xff80) >>1) | (JORNADA_PCR & 0x3f)); + + this_pcr &= ~(JORNADA_MUX_CLK0 | JORNADA_MUX_CLK1); + if (this_pcr & JORNADA_SM_CLK_EN) + this_pcr |= JORNADA_MUX_CLK1; + else if (this_pcr & JORNADA_MMC_CLK_EN) + this_pcr |= JORNADA_MUX_CLK0; + switch (arg_action) { + case PCR_SET_VALUE: + this_pcr = arg_value; + break; + case PCR_BIT_SET: /* enable controller */ + if(arg_value & JORNADA_SM_CLK_EN) { /* smart card controller */ + this_pcr &= ~(JORNADA_MUX_CLK0 | JORNADA_MUX_CLK1); + this_pcr |= JORNADA_MUX_CLK1; + } + else if(arg_value & JORNADA_MMC_CLK_EN) { /* mmc controller */ + this_pcr &= ~(JORNADA_MUX_CLK0 | JORNADA_MUX_CLK1); + this_pcr |= JORNADA_MUX_CLK0; + } + this_pcr |= arg_value; + break; + case PCR_BIT_CLEAR: /* disable controller */ + /* smart card or mmc controller */ + if (arg_value & (JORNADA_SM_CLK_EN | JORNADA_MMC_CLK_EN)) + this_pcr &= ~(JORNADA_MUX_CLK0 | JORNADA_MUX_CLK1); + this_pcr &= ~arg_value; + break; + case PCR_GET_VALUE: + default: + break; + } + JORNADA_PCR = this_pcr; +} + +void jornada_microwire_init(void) +{ + JORNADA_GPIOAFR |= JORNADA_GP_MW; + udelay(1); + JORNADA_MWFTR = (8 << JORNADA_MWFTR_V_TFT) + | (8 << JORNADA_MWFTR_V_RFT); /* 0x108 */ + udelay(1); + SetPMUPCRRegister(PCR_BIT_SET, JORNADA_MW_CLK_EN); + udelay(1); + JORNADA_MWCR = JORNADA_MW_EN | JORNADA_DSS_16_BIT + | (8 << JORNADA_MWCR_V_SCR) /* 0xa07 */ + | JORNADA_FIFO_RST; /* reset FIFO */ + udelay(1); + JORNADA_MWCR &= ~JORNADA_FIFO_RST; + /* set FIFO interrupt levels to 8 for each of Rx, Tx */ + udelay(1); + JORNADA_MWFTR = (8 << JORNADA_MWFTR_V_TFT) + | (8 << JORNADA_MWFTR_V_RFT); /* 0x108 */ +} + +void jornada_microwire_start(void) +{ +int retry = 90000; + while(retry-- && (JORNADA_MWFSR & JORNADA_MW_RNE)); /* empty out existing data */ +} + +void jornada_microwire_read(int *value1, int *value2) +{ + int i,retry = 1000000; + while (retry-- && !(JORNADA_MWFSR & JORNADA_MW_RFS)); + + for (i = 0; i < 8; i++) + microwire_data[i] = (JORNADA_MWDR & 0xffff) >> 4; + + *value1 = (microwire_data[0] + microwire_data[1] + microwire_data[2] + microwire_data[3]) / 4; + *value2 = (microwire_data[4] + microwire_data[5] + microwire_data[6] + microwire_data[7]) / 4; +} + + +void jornada56x_asic_setup(void) +{ + JORNADA_SCR &= ~JORNADA_ASIC_SLEEP_EN; /* wake up the ASIC */ + udelay(3); + JORNADA_GPIOAFR = JORNADA_GP_PWM1; + JORNADA_SCR |= JORNADA_RCLK_EN; + + mdelay(1); + + SetPMUPCRRegister(PCR_BIT_SET,(JORNADA_GPIO_INT_CLK_EN|JORNADA_PWM1CLK_EN)); + + JORNADA_PWM1_CKDR = 0; + JORNADA_PWM2_CKDR = 0; + + mdelay(2); + + JORNADA_GPBPSR = 0x001B; + JORNADA_GPCPSR = 0x31C0; + JORNADA_GPDPSR = 0xAD99; + + JORNADA_GPBPCR = 0x3E24; + JORNADA_GPCPCR = 0x0002; + JORNADA_GPDPCR = 0x5264; + JORNADA_GPDPSR = JORNADA_RS232_ON; /* enable rs232 transceiver */ + JORNADA_GPDPSR = JORNADA_CF_POWER_OFF; /* turn power off to CF */ + + JORNADA_GPBPSDR = 0x81FF; + JORNADA_GPCPSDR = 0xB96F; + JORNADA_GPDPSDR = 0xFBFF; + + JORNADA_GPBPSLR = 0x00D0; + JORNADA_GPCPSLR = 0x0000; + JORNADA_GPDPSLR = 0xA198; + + JORNADA_GPBPFDR = 0x81FF; + JORNADA_GPCPFDR = 0xB96F; + JORNADA_GPDPFDR = 0xFBFF; + + JORNADA_GPBPFLR = 0x01D0; + JORNADA_GPCPFLR = 0x0000; + JORNADA_GPDPFLR = 0xA198; + + JORNADA_GPBPDR = 0x01FF; + JORNADA_GPCPDR = 0x37C2; + JORNADA_GPDPDR = 0xFFFF; + + JORNADA_GPBPCR = 0x1c0; /* Buttons: row lines all output 0 */ + JORNADA_GPBPDR |= 0x1c0; /* Buttons: turn row lines into outputs */ + + mdelay(2); /* Delay 2 milliseconds. */ + JORNADA_INT_EN |= JORNADA_GPIO_B_INT | JORNADA_GPIO_C_INT; + + jornada_microwire_init(); + + /* Clear screen here */ + JORNADA_GPDPCR = GPIO_GPIO5; + JORNADA_GPDPCR = GPIO_GPIO13; /* Turn on power to panel */ + JORNADA_GPDPSR = GPIO_GPIO14; /* force GPIO-D14 to high */ + mdelay(100); +} + +/* + * Jornada 56x ASIC interrupt support. + */ +static void irq_ack_low(unsigned int irq) +{ + JORNADA_INT_STAT = (1 << (irq - IRQ_MMC_MAIN)); +} + +static void irq_mask_low(unsigned int irq) +{ + JORNADA_INT_EN &= ~(1 << (irq - IRQ_MMC_MAIN)); +} + +static void irq_unmask_low(unsigned int irq) +{ + JORNADA_INT_EN |= (1 << (irq - IRQ_MMC_MAIN)); +} + +static struct irq_chip irq_low = { + .ack = irq_ack_low, + .mask = irq_mask_low, + .unmask = irq_unmask_low, +}; + +static void irq_ack_high(unsigned int irq) +{ + JORNADA_INT_STAT2 = (1 << (irq - IRQ_UART_MAIN)); +} + +static void irq_mask_high(unsigned int irq) +{ + JORNADA_INT_EN2 &= ~(1 << (irq - IRQ_UART_MAIN)); +} + +static void irq_unmask_high(unsigned int irq) +{ + JORNADA_INT_EN2 |= (1 << (irq - IRQ_UART_MAIN)); +} + +static struct irq_chip irq_high = { + .ack = irq_ack_high, + .mask = irq_mask_high, + .unmask = irq_unmask_high, +}; + +static void irq_ack_gpiob(unsigned int irq) +{ + JORNADA_GPIOB_STAT = (1 << (irq - IRQ_GPIOB_B0)); +} + +static void irq_mask_gpiob(unsigned int irq) +{ + JORNADA_GPIOB_FE_EN &= ~(1 << (irq - IRQ_GPIOB_B0)); +} + +static void irq_unmask_gpiob(unsigned int irq) +{ + JORNADA_GPIOB_FE_EN |= (1 << (irq - IRQ_GPIOB_B0)); +} + +static struct irq_chip irq_gpiob = { + .ack = irq_ack_gpiob, + .mask = irq_mask_gpiob, + .unmask = irq_unmask_gpiob, +}; + +static void irq_ack_gpioc(unsigned int irq) +{ + JORNADA_GPIOC_STAT = (1 << (irq - IRQ_GPIOC_C0)); +} + +static void irq_mask_gpioc(unsigned int irq) +{ + JORNADA_GPIOC_FE_EN &= ~(1 << (irq - IRQ_GPIOC_C0)); +} + +static void irq_unmask_gpioc(unsigned int irq) +{ + JORNADA_GPIOC_FE_EN |= (1 << (irq - IRQ_GPIOC_C0)); +} + +static struct irq_chip irq_gpioc = { + .ack = irq_ack_gpioc, + .mask = irq_mask_gpioc, + .unmask = irq_unmask_gpioc, +}; + +extern asmlinkage void asm_do_IRQ(int irq); + +void __init jornada56x_asic_init_irq(void) +{ + unsigned int irq; + +/* Should this be replaced with a request_resource() */ +/* alloc_irq_space(64); */ + + JORNADA_INT_EN = 0; + JORNADA_INT_STAT = 0xffff; + JORNADA_INT_EN2 = 0; + JORNADA_INT_STAT2 = 0xffff; + JORNADA_GPIOB_FE_EN = 0; + JORNADA_GPIOB_RE_EN = 0; + JORNADA_GPIOB_STAT = 0xffff; + JORNADA_GPIOC_FE_EN = 0; + JORNADA_GPIOC_RE_EN = 0; + JORNADA_GPIOC_STAT = 0xffff; + + for (irq = IRQ_MMC_MAIN; irq <= IRQ_MMC_MAIN + 15; irq++) { + set_irq_chip(irq, &irq_low); + set_irq_handler(irq, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + for (irq = IRQ_UART_MAIN; irq <= IRQ_UART_MAIN + 15; irq++) { + set_irq_chip(irq, &irq_high); + set_irq_handler(irq, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + for (irq = IRQ_GPIOB_B0; irq <= IRQ_GPIOB_B0 + 15; irq++) { + set_irq_chip(irq, &irq_gpiob); + set_irq_handler(irq, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + for (irq = IRQ_GPIOC_C0; irq <= IRQ_GPIOC_C0 + 15; irq++) { + set_irq_chip(irq, &irq_gpioc); + set_irq_handler(irq, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } +} + + +irqreturn_t jornada56x_IRQ_demux(int irq, void *dev_id) +{ +unsigned long stat0, stat1, statb, statc; +int i, found_one; + + do { + found_one = 0; + stat0 = JORNADA_INT_STAT & 0xffff & JORNADA_INT_EN + & ~(JORNADA_GPIO_B_INT | JORNADA_GPIO_C_INT); + stat1 = JORNADA_INT_STAT2 & 0xffff & JORNADA_INT_EN2; + statb = JORNADA_GPIOB_STAT & 0xffff & JORNADA_GPIOB_FE_EN; + statc = JORNADA_GPIOC_STAT & 0xffff & JORNADA_GPIOC_FE_EN; + #define CHECK_STAT(A,B) \ + for (i = A; B; i++, B >>= 1) \ + if (B & 1) { \ + found_one = 1; \ + asm_do_IRQ(i); \ + } + CHECK_STAT(IRQ_MMC_MAIN, stat0); + CHECK_STAT(IRQ_UART_MAIN, stat1); + CHECK_STAT(IRQ_GPIOB_B0, statb); + CHECK_STAT(IRQ_GPIOC_C0, statc); + } while(found_one); + + return IRQ_HANDLED; +} |