aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sa1100/jornada56x_asic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-sa1100/jornada56x_asic.c')
-rw-r--r--arch/arm/mach-sa1100/jornada56x_asic.c341
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;
+}