smedia-glamo.patch
authormokopatches <mokopatches@openmoko.org>
Wed, 19 Nov 2008 17:03:14 +0000 (17:03 +0000)
committerwarmcat <andy@warmcat.com>
Wed, 19 Nov 2008 17:03:14 +0000 (17:03 +0000)
[ FIXME:
 include/asm-arm/arch-s3c2410/irqs.h shouldn't contain device-specific
 changes. ]

This is a Linux kernel driver for the Smedia Glamo336x / Glamo337x
multi-function peripheral device.

Signed-off-by: Harald Welte <laforge@openmoko.org>
15 files changed:
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/glamo/Kconfig [new file with mode: 0644]
drivers/mfd/glamo/Makefile [new file with mode: 0644]
drivers/mfd/glamo/glamo-core.c [new file with mode: 0644]
drivers/mfd/glamo/glamo-core.h [new file with mode: 0644]
drivers/mfd/glamo/glamo-fb.c [new file with mode: 0644]
drivers/mfd/glamo/glamo-gpio.c [new file with mode: 0644]
drivers/mfd/glamo/glamo-lcm-spi.c [new file with mode: 0644]
drivers/mfd/glamo/glamo-regs.h [new file with mode: 0644]
drivers/mfd/glamo/glamo-spi-gpio.c [new file with mode: 0644]
include/asm-arm/arch-s3c2410/irqs.h [new file with mode: 0644]
include/linux/glamo-gpio.h [new file with mode: 0644]
include/linux/glamofb.h [new file with mode: 0644]
include/linux/spi/glamo.h [new file with mode: 0644]

index 2572773..10e5b2c 100644 (file)
@@ -153,6 +153,8 @@ config MFD_WM8350_I2C
          I2C as the control interface.  Additional options must be
          selected to enable support for the functionality of the chip.
 
+source "drivers/mfd/glamo/Kconfig"
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
index 9a5ad8a..b917368 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_MFD_SM501)                += sm501.o
 obj-$(CONFIG_MFD_ASIC3)                += asic3.o
+obj-$(CONFIG_MFD_GLAMO)                += glamo/
 
 obj-$(CONFIG_HTC_EGPIO)                += htc-egpio.o
 obj-$(CONFIG_HTC_PASIC3)       += htc-pasic3.o
diff --git a/drivers/mfd/glamo/Kconfig b/drivers/mfd/glamo/Kconfig
new file mode 100644 (file)
index 0000000..b99f2b2
--- /dev/null
@@ -0,0 +1,35 @@
+config MFD_GLAMO
+       bool "Smedia Glamo 336x/337x support"
+       help
+         This enables the core driver for the Smedia Glamo 336x/337x
+         multi-function device.  It includes irq_chip demultiplex as
+         well as clock / power management and GPIO support.
+
+config MFD_GLAMO_FB
+       tristate "Smedia Glamo 336x/337x framebuffer support"
+       depends on FB && MFD_GLAMO
+       help
+         Frame buffer driver for the LCD controller in the Smedia Glamo
+         336x/337x.
+
+         This driver is also available as a module ( = code which can be
+         inserted and removed from the running kernel whenever you want). The
+         module will be called glamofb. If you want to compile it as a module,
+         say M here and read <file:Documentation/modules.txt>.
+
+         If unsure, say N.
+
+config MFD_GLAMO_SPI_GPIO
+       tristate "Glamo GPIO SPI bitbang support"
+       depends on MFD_GLAMO
+       help
+         Enable a bitbanging SPI adapter driver for the Smedia Glamo.
+
+config MFD_GLAMO_SPI_FB
+       tristate "Glamo LCM control channel SPI support"
+       depends on MFD_GLAMO_FB
+       help
+         Enable a bitbanging SPI adapter driver for the Smedia Glamo LCM
+        control channel.  This SPI interface is frequently used to
+        interconnect the LCM control interface.
+
diff --git a/drivers/mfd/glamo/Makefile b/drivers/mfd/glamo/Makefile
new file mode 100644 (file)
index 0000000..fb53982
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the Smedia Glamo framebuffer driver
+#
+
+obj-$(CONFIG_MFD_GLAMO)                        += glamo-core.o glamo-gpio.o
+obj-$(CONFIG_MFD_GLAMO_SPI)            += glamo-spi.o
+obj-$(CONFIG_MFD_GLAMO_SPI_GPIO)       += glamo-spi-gpio.o
+
+obj-$(CONFIG_MFD_GLAMO_FB)             += glamo-fb.o
+obj-$(CONFIG_MFD_GLAMO_SPI_FB)         += glamo-lcm-spi.o
+
diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c
new file mode 100644 (file)
index 0000000..acf545f
--- /dev/null
@@ -0,0 +1,1151 @@
+/* Smedia Glamo 336x/337x driver
+ *
+ * (C) 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/glamofb.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include "glamo-regs.h"
+#include "glamo-core.h"
+
+#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
+
+static struct glamo_core *glamo_handle;
+
+static inline void __reg_write(struct glamo_core *glamo,
+                               u_int16_t reg, u_int16_t val)
+{
+       writew(val, glamo->base + reg);
+}
+
+static inline u_int16_t __reg_read(struct glamo_core *glamo,
+                                  u_int16_t reg)
+{
+       return readw(glamo->base + reg);
+}
+
+static void __reg_set_bit_mask(struct glamo_core *glamo,
+                               u_int16_t reg, u_int16_t mask,
+                               u_int16_t val)
+{
+       u_int16_t tmp;
+
+       val &= mask;
+
+       tmp = __reg_read(glamo, reg);
+       tmp &= ~mask;
+       tmp |= val;
+       __reg_write(glamo, reg, tmp);
+}
+
+static void reg_set_bit_mask(struct glamo_core *glamo,
+                               u_int16_t reg, u_int16_t mask,
+                               u_int16_t val)
+{
+       spin_lock(&glamo->lock);
+       __reg_set_bit_mask(glamo, reg, mask, val);
+       spin_unlock(&glamo->lock);
+}
+
+static inline void __reg_set_bit(struct glamo_core *glamo,
+                                u_int16_t reg, u_int16_t bit)
+{
+       __reg_set_bit_mask(glamo, reg, bit, 0xffff);
+}
+
+static inline void __reg_clear_bit(struct glamo_core *glamo,
+                                  u_int16_t reg, u_int16_t bit)
+{
+       __reg_set_bit_mask(glamo, reg, bit, 0);
+}
+
+static inline void glamo_vmem_write(struct glamo_core *glamo, u_int32_t addr,
+                                   u_int16_t *src, int len)
+{
+       if (addr & 0x0001 || (unsigned long)src & 0x0001 || len & 0x0001) {
+               dev_err(&glamo->pdev->dev, "unaligned write(0x%08x, 0x%p, "
+                       "0x%x)!!\n", addr, src, len);
+       }
+
+}
+
+static inline void glamo_vmem_read(struct glamo_core *glamo, u_int16_t *buf,
+                                  u_int32_t addr, int len)
+{
+       if (addr & 0x0001 || (unsigned long) buf & 0x0001 || len & 0x0001) {
+               dev_err(&glamo->pdev->dev, "unaligned read(0x%p, 0x08%x, "
+                       "0x%x)!!\n", buf, addr, len);
+       }
+
+
+}
+
+/***********************************************************************
+ * resources of sibling devices
+ ***********************************************************************/
+
+#if 0
+static struct resource glamo_core_resources[] = {
+       {
+               .start  = GLAMO_REGOFS_GENERIC,
+               .end    = GLAMO_REGOFS_GENERIC + 0x400,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = 0,
+               .end    = 0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device glamo_core_dev = {
+       .name           = "glamo-core",
+       .resource       = &glamo_core_resources,
+       .num_resources  = ARRAY_SIZE(glamo_core_resources),
+};
+#endif
+
+static struct resource glamo_jpeg_resources[] = {
+       {
+               .start  = GLAMO_REGOFS_JPEG,
+               .end    = GLAMO_REGOFS_MPEG - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_GLAMO_JPEG,
+               .end    = IRQ_GLAMO_JPEG,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device glamo_jpeg_dev = {
+       .name           = "glamo-jpeg",
+       .resource       = glamo_jpeg_resources,
+       .num_resources  = ARRAY_SIZE(glamo_jpeg_resources),
+};
+
+static struct resource glamo_mpeg_resources[] = {
+       {
+               .start  = GLAMO_REGOFS_MPEG,
+               .end    = GLAMO_REGOFS_LCD - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_GLAMO_MPEG,
+               .end    = IRQ_GLAMO_MPEG,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device glamo_mpeg_dev = {
+       .name           = "glamo-mpeg",
+       .resource       = glamo_mpeg_resources,
+       .num_resources  = ARRAY_SIZE(glamo_mpeg_resources),
+};
+
+static struct resource glamo_2d_resources[] = {
+       {
+               .start  = GLAMO_REGOFS_2D,
+               .end    = GLAMO_REGOFS_3D - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_GLAMO_2D,
+               .end    = IRQ_GLAMO_2D,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device glamo_2d_dev = {
+       .name           = "glamo-2d",
+       .resource       = glamo_2d_resources,
+       .num_resources  = ARRAY_SIZE(glamo_2d_resources),
+};
+
+static struct resource glamo_3d_resources[] = {
+       {
+               .start  = GLAMO_REGOFS_3D,
+               .end    = GLAMO_REGOFS_END - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device glamo_3d_dev = {
+       .name           = "glamo-3d",
+       .resource       = glamo_3d_resources,
+       .num_resources  = ARRAY_SIZE(glamo_3d_resources),
+};
+
+static struct platform_device glamo_spigpio_dev = {
+       .name           = "glamo-spi-gpio",
+};
+
+static struct resource glamo_fb_resources[] = {
+       /* FIXME: those need to be incremented by parent base */
+       {
+               .name   = "glamo-fb-regs",
+               .start  = GLAMO_REGOFS_LCD,
+               .end    = GLAMO_REGOFS_MMC - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "glamo-fb-mem",
+               .start  = GLAMO_OFFSET_FB,
+               .end    = GLAMO_OFFSET_FB + GLAMO_FB_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device glamo_fb_dev = {
+       .name           = "glamo-fb",
+       .resource       = glamo_fb_resources,
+       .num_resources  = ARRAY_SIZE(glamo_fb_resources),
+};
+
+static struct resource glamo_mmc_resources[] = {
+       {
+               /* FIXME: those need to be incremented by parent base */
+               .start  = GLAMO_REGOFS_MMC,
+               .end    = GLAMO_REGOFS_MPROC0 - 1,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = IRQ_GLAMO_MMC,
+               .end    = IRQ_GLAMO_MMC,
+               .flags  = IORESOURCE_IRQ,
+       }, { /* our data buffer for MMC transfers */
+               .start  = GLAMO_OFFSET_FB + GLAMO_FB_SIZE,
+               .end    = GLAMO_OFFSET_FB + GLAMO_FB_SIZE +
+                                 GLAMO_MMC_BUFFER_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       },
+};
+
+static struct platform_device glamo_mmc_dev = {
+       .name           = "glamo-mci",
+       .resource       = glamo_mmc_resources,
+       .num_resources  = ARRAY_SIZE(glamo_mmc_resources),
+};
+
+struct glamo_mci_pdata glamo_mci_def_pdata = {
+       .gpio_detect            = 0,
+       .glamo_set_mci_power    = NULL, /* filled in from MFD platform data */
+       .ocr_avail              = MMC_VDD_32_33,
+       .glamo_irq_is_wired     = NULL, /* filled in from MFD platform data */
+};
+EXPORT_SYMBOL_GPL(glamo_mci_def_pdata);
+
+
+
+static void mangle_mem_resources(struct resource *res, int num_res,
+                                struct resource *parent)
+{
+       int i;
+
+       for (i = 0; i < num_res; i++) {
+               if (res[i].flags != IORESOURCE_MEM)
+                       continue;
+               res[i].start += parent->start;
+               res[i].end += parent->start;
+               res[i].parent = parent;
+       }
+}
+
+/***********************************************************************
+ * IRQ demultiplexer
+ ***********************************************************************/
+#define irq2glamo(x)   (x - IRQ_GLAMO(0))
+
+static void glamo_ack_irq(unsigned int irq)
+{
+       /* clear interrupt source */
+       __reg_write(glamo_handle, GLAMO_REG_IRQ_CLEAR,
+                   1 << irq2glamo(irq));
+}
+
+static void glamo_mask_irq(unsigned int irq)
+{
+       u_int16_t tmp;
+
+       /* clear bit in enable register */
+       tmp = __reg_read(glamo_handle, GLAMO_REG_IRQ_ENABLE);
+       tmp &= ~(1 << irq2glamo(irq));
+       __reg_write(glamo_handle, GLAMO_REG_IRQ_ENABLE, tmp);
+}
+
+static void glamo_unmask_irq(unsigned int irq)
+{
+       u_int16_t tmp;
+
+       /* set bit in enable register */
+       tmp = __reg_read(glamo_handle, GLAMO_REG_IRQ_ENABLE);
+       tmp |= (1 << irq2glamo(irq));
+       __reg_write(glamo_handle, GLAMO_REG_IRQ_ENABLE, tmp);
+}
+
+static struct irq_chip glamo_irq_chip = {
+       .ack    = glamo_ack_irq,
+       .mask   = glamo_mask_irq,
+       .unmask = glamo_unmask_irq,
+};
+
+static void glamo_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       spin_lock(&desc->lock);
+
+       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+
+       if (unlikely(desc->status & IRQ_INPROGRESS)) {
+               desc->status |= (IRQ_PENDING | IRQ_MASKED);
+               desc->chip->mask(irq);
+               desc->chip->ack(irq);
+               goto out_unlock;
+       }
+
+       kstat_cpu(cpu).irqs[irq]++;
+       desc->chip->ack(irq);
+       desc->status |= IRQ_INPROGRESS;
+
+       do {
+               u_int16_t irqstatus;
+               int i;
+
+               if (unlikely((desc->status &
+                               (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
+                               (IRQ_PENDING | IRQ_MASKED))) {
+                       /* dealing with pending IRQ, unmasking */
+                       desc->chip->unmask(irq);
+                       desc->status &= ~IRQ_MASKED;
+               }
+
+               desc->status &= ~IRQ_PENDING;
+
+               /* read IRQ status register */
+               irqstatus = __reg_read(glamo_handle, GLAMO_REG_IRQ_STATUS);
+               for (i = 0; i < 9; i++)
+                       if (irqstatus & (1 << i))
+                               desc_handle_irq(IRQ_GLAMO(i),
+                                   irq_desc+IRQ_GLAMO(i));
+
+       } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+
+       desc->status &= ~IRQ_INPROGRESS;
+
+out_unlock:
+       spin_unlock(&desc->lock);
+}
+
+/***********************************************************************
+ * 'engine' support
+ ***********************************************************************/
+
+int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+       spin_lock(&glamo->lock);
+       switch (engine) {
+       case GLAMO_ENGINE_LCD:
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_LCD,
+                           GLAMO_CLOCK_LCD_EN_M5CLK |
+                           GLAMO_CLOCK_LCD_EN_DHCLK |
+                           GLAMO_CLOCK_LCD_EN_DMCLK |
+                           GLAMO_CLOCK_LCD_EN_DCLK |
+                           GLAMO_CLOCK_LCD_DG_M5CLK |
+                           GLAMO_CLOCK_LCD_DG_DMCLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1,
+                           GLAMO_CLOCK_GEN51_EN_DIV_DHCLK |
+                           GLAMO_CLOCK_GEN51_EN_DIV_DMCLK |
+                           GLAMO_CLOCK_GEN51_EN_DIV_DCLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
+                           GLAMO_HOSTBUS2_MMIO_EN_LCD,
+                           0xffff);
+               break;
+       case GLAMO_ENGINE_MMC:
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MMC,
+                                  GLAMO_CLOCK_MMC_EN_M9CLK |
+                                  GLAMO_CLOCK_MMC_EN_TCLK |
+                                  GLAMO_CLOCK_MMC_DG_M9CLK |
+                                  GLAMO_CLOCK_MMC_DG_TCLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
+                                  GLAMO_HOSTBUS2_MMIO_EN_MMC,
+                                  GLAMO_HOSTBUS2_MMIO_EN_MMC);
+               break;
+       case GLAMO_ENGINE_2D:
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_2D,
+                                  GLAMO_CLOCK_2D_EN_M7CLK |
+                                  GLAMO_CLOCK_2D_EN_GCLK |
+                                  GLAMO_CLOCK_2D_DG_M7CLK |
+                                  GLAMO_CLOCK_2D_DG_GCLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
+                                  GLAMO_HOSTBUS2_MMIO_EN_2D,
+                                  GLAMO_HOSTBUS2_MMIO_EN_2D);
+               break;
+       case GLAMO_ENGINE_CMDQ:
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_2D,
+                                  GLAMO_CLOCK_2D_EN_M6CLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_HOSTBUS(2),
+                                  GLAMO_HOSTBUS2_MMIO_EN_CQ,
+                                  GLAMO_HOSTBUS2_MMIO_EN_CQ);
+               break;
+       /* FIXME: Implementation */
+       default:
+               break;
+       }
+       spin_unlock(&glamo->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(glamo_engine_enable);
+
+int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+       spin_lock(&glamo->lock);
+       switch (engine) {
+       /* FIXME: Implementation */
+       default:
+               break;
+       }
+       spin_unlock(&glamo->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(glamo_engine_disable);
+
+struct glamo_script reset_regs[] = {
+       [GLAMO_ENGINE_LCD] = {
+               GLAMO_REG_CLOCK_LCD, GLAMO_CLOCK_LCD_RESET
+       },
+#if 0
+       [GLAMO_ENGINE_HOST] = {
+               GLAMO_REG_CLOCK_HOST, GLAMO_CLOCK_HOST_RESET
+       },
+       [GLAMO_ENGINE_MEM] = {
+               GLAMO_REG_CLOCK_MEM, GLAMO_CLOCK_MEM_RESET
+       },
+#endif
+       [GLAMO_ENGINE_MMC] = {
+               GLAMO_REG_CLOCK_MMC, GLAMO_CLOCK_MMC_RESET
+       },
+       [GLAMO_ENGINE_2D] = {
+               GLAMO_REG_CLOCK_2D, GLAMO_CLOCK_2D_RESET
+       },
+       [GLAMO_ENGINE_JPEG] = {
+               GLAMO_REG_CLOCK_JPEG, GLAMO_CLOCK_JPEG_RESET
+       },
+};
+
+void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine)
+{
+       struct glamo_script *rst;
+
+       if (engine >= ARRAY_SIZE(reset_regs)) {
+               dev_warn(&glamo->pdev->dev, "unknown engine %u ", engine);
+               return;
+       }
+
+       rst = &reset_regs[engine];
+
+       spin_lock(&glamo->lock);
+       __reg_set_bit(glamo, rst->reg, rst->val);
+       spin_unlock(&glamo->lock);
+
+       msleep(1);
+
+       spin_lock(&glamo->lock);
+       __reg_clear_bit(glamo, rst->reg, rst->val);
+       spin_unlock(&glamo->lock);
+
+       msleep(1);
+}
+EXPORT_SYMBOL_GPL(glamo_engine_reset);
+
+enum glamo_pll {
+       GLAMO_PLL1,
+       GLAMO_PLL2,
+};
+
+static int glamo_pll_rate(struct glamo_core *glamo,
+                         enum glamo_pll pll)
+{
+       u_int16_t reg;
+       unsigned int div = 512;
+       /* FIXME: move osci into platform_data */
+       unsigned int osci = 32768;
+
+       if (osci == 32768)
+               div = 1;
+
+       switch (pll) {
+       case GLAMO_PLL1:
+               reg = __reg_read(glamo, GLAMO_REG_PLL_GEN1);
+               break;
+       case GLAMO_PLL2:
+               reg = __reg_read(glamo, GLAMO_REG_PLL_GEN3);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return (osci/div)*reg;
+}
+
+int glamo_engine_reclock(struct glamo_core *glamo,
+                        enum glamo_engine engine,
+                        int ps)
+{
+       int pll, khz;
+       u_int16_t reg, mask, val = 0;
+
+       if (!ps)
+               return 0;
+
+       switch (engine) {
+       case GLAMO_ENGINE_LCD:
+               pll = GLAMO_PLL1;
+               reg = GLAMO_REG_CLOCK_GEN7;
+               mask = 0xff;
+               break;
+       default:
+               dev_warn(&glamo->pdev->dev,
+                        "reclock of engine 0x%x not supported\n", engine);
+               return -EINVAL;
+               break;
+       }
+
+       pll = glamo_pll_rate(glamo, pll);
+       khz = 1000000000UL / ps;
+
+       if (khz)
+               val = (pll / khz) / 1000;
+
+       dev_dbg(&glamo->pdev->dev,
+                       "PLL %d, kHZ %d, div %d\n", pll, khz, val);
+
+       if (val) {
+               val--;
+               reg_set_bit_mask(glamo, reg, mask, val);
+               msleep(5); /* wait some time to stabilize */
+
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(glamo_engine_reclock);
+
+/***********************************************************************
+ * script support
+ ***********************************************************************/
+
+int glamo_run_script(struct glamo_core *glamo, struct glamo_script *script,
+                    int len, int may_sleep)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               struct glamo_script *line = &script[i];
+
+               switch (line->reg) {
+               case 0xffff:
+                       return 0;
+               case 0xfffe:
+                       if (may_sleep)
+                               msleep(line->val);
+                       else
+                               mdelay(line->val);
+                       break;
+               case 0xfffd:
+                       /* spin until PLLs lock */
+                       while ((__reg_read(glamo, GLAMO_REG_PLL_GEN5) & 3) != 3)
+                               ;
+                       break;
+               default:
+                       __reg_write(glamo, script[i].reg, script[i].val);
+                       break;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(glamo_run_script);
+
+static struct glamo_script glamo_init_script[] = {
+       { GLAMO_REG_CLOCK_HOST,         0x1000 },
+               { 0xfffe, 2 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x1000 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x2000 },
+       { GLAMO_REG_CLOCK_LCD,          0x1000 },
+       { GLAMO_REG_CLOCK_MMC,          0x1000 },
+       { GLAMO_REG_CLOCK_ISP,          0x1000 },
+       { GLAMO_REG_CLOCK_ISP,          0x3000 },
+       { GLAMO_REG_CLOCK_JPEG,         0x1000 },
+       { GLAMO_REG_CLOCK_3D,           0x1000 },
+       { GLAMO_REG_CLOCK_3D,           0x3000 },
+       { GLAMO_REG_CLOCK_2D,           0x1000 },
+       { GLAMO_REG_CLOCK_2D,           0x3000 },
+       { GLAMO_REG_CLOCK_RISC1,        0x1000 },
+       { GLAMO_REG_CLOCK_MPEG,         0x3000 },
+       { GLAMO_REG_CLOCK_MPEG,         0x3000 },
+       { GLAMO_REG_CLOCK_MPROC,        0x1000 /*0x100f*/ },
+               { 0xfffe, 2 },
+       { GLAMO_REG_CLOCK_HOST,         0x0000 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x0000 },
+       { GLAMO_REG_CLOCK_LCD,          0x0000 },
+       { GLAMO_REG_CLOCK_MMC,          0x0000 },
+#if 0
+/* unused engines must be left in reset to stop MMC block read "blackouts" */
+       { GLAMO_REG_CLOCK_ISP,          0x0000 },
+       { GLAMO_REG_CLOCK_ISP,          0x0000 },
+       { GLAMO_REG_CLOCK_JPEG,         0x0000 },
+       { GLAMO_REG_CLOCK_3D,           0x0000 },
+       { GLAMO_REG_CLOCK_3D,           0x0000 },
+       { GLAMO_REG_CLOCK_2D,           0x0000 },
+       { GLAMO_REG_CLOCK_2D,           0x0000 },
+       { GLAMO_REG_CLOCK_RISC1,        0x0000 },
+       { GLAMO_REG_CLOCK_MPEG,         0x0000 },
+       { GLAMO_REG_CLOCK_MPEG,         0x0000 },
+#endif
+       { GLAMO_REG_PLL_GEN1,           0x05db },       /* 48MHz */
+       { GLAMO_REG_PLL_GEN3,           0x09c3 },       /* 80MHz */
+               { 0xfffd, 0 },
+       /*
+        * b9 of this register MUST be zero to get any interrupts on INT#
+        * the other set bits enable all the engine interrupt sources
+        */
+       { GLAMO_REG_IRQ_ENABLE,         0x01ff },
+       { GLAMO_REG_CLOCK_GEN6,         0x2000 },
+       { GLAMO_REG_CLOCK_GEN7,         0x0101 },
+       { GLAMO_REG_CLOCK_GEN8,         0x0100 },
+       { GLAMO_REG_CLOCK_HOST,         0x000d },
+       { 0x200,        0x0ef0 },
+       { 0x202,        0x07ff },
+       { 0x212,        0x0000 },
+       { 0x214,        0x4000 },
+       { 0x216,        0xf00e },
+       { GLAMO_REG_MEM_TYPE,           0x0874 }, /* 8MB, 16 word pg wr+rd */
+       { GLAMO_REG_MEM_GEN,            0xafaf }, /* 63 grants min + max */
+       /*
+        * the register below originally 0x0108 makes unreliable Glamo MMC
+        * write operations.  Cranked to 0x05ad to add a wait state, the
+        * unreliability is not seen after 4GB of write / read testing
+        */
+       { GLAMO_REG_MEM_TIMING1,        0x0108 },
+       { GLAMO_REG_MEM_TIMING2,        0x0010 }, /* Taa = 3 MCLK */
+       { GLAMO_REG_MEM_TIMING3,        0x0000 },
+       { GLAMO_REG_MEM_TIMING4,        0x0000 }, /* CE1# delay fall/rise */
+       { GLAMO_REG_MEM_TIMING5,        0x0000 }, /* UB# LB# */
+       { GLAMO_REG_MEM_TIMING6,        0x0000 }, /* OE# */
+       { GLAMO_REG_MEM_TIMING7,        0x0000 }, /* WE# */
+       { GLAMO_REG_MEM_TIMING8,        0x1002 }, /* MCLK delay, was 0x1000 */
+       { GLAMO_REG_MEM_TIMING9,        0x6006 },
+       { GLAMO_REG_MEM_TIMING10,       0x00ff },
+       { GLAMO_REG_MEM_TIMING11,       0x0001 },
+       { GLAMO_REG_MEM_POWER1,         0x0020 },
+       { GLAMO_REG_MEM_POWER2,         0x0000 },
+       { GLAMO_REG_MEM_DRAM1,          0x0000 },
+               { 0xfffe, 1 },
+       { GLAMO_REG_MEM_DRAM1,          0xc100 },
+               { 0xfffe, 1 },
+       { GLAMO_REG_MEM_DRAM1,          0xe100 },
+       { GLAMO_REG_MEM_DRAM2,          0x01d6 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x000b },
+};
+
+static struct glamo_script glamo_resume_script[] = {
+       { GLAMO_REG_IRQ_ENABLE,         0x01ff },
+       { GLAMO_REG_CLOCK_GEN6,         0x2000 },
+       { GLAMO_REG_CLOCK_GEN7,         0x0001 }, /* 0101 */
+       { GLAMO_REG_CLOCK_GEN8,         0x0100 },
+       { GLAMO_REG_CLOCK_HOST,         0x000d },
+       { 0x200,        0x0ef0 },
+       { 0x202,        0x07ff },
+       { 0x212,        0x0000 },
+       { 0x214,        0x4000 },
+       { 0x216,        0xf00e },
+       { GLAMO_REG_MEM_TYPE,           0x0874 }, /* 8MB, 16 word pg wr+rd */
+       { GLAMO_REG_MEM_GEN,            0xafaf }, /* 63 grants min + max */
+
+       { GLAMO_REG_MEM_TIMING1,        0x0108 },
+       { GLAMO_REG_MEM_TIMING2,        0x0010 }, /* Taa = 3 MCLK */
+       { GLAMO_REG_MEM_TIMING3,        0x0000 },
+       { GLAMO_REG_MEM_TIMING4,        0x0000 }, /* CE1# delay fall/rise */
+       { GLAMO_REG_MEM_TIMING5,        0x0000 }, /* UB# LB# */
+       { GLAMO_REG_MEM_TIMING6,        0x0000 }, /* OE# */
+       { GLAMO_REG_MEM_TIMING7,        0x0000 }, /* WE# */
+       { GLAMO_REG_MEM_TIMING8,        0x1002 }, /* MCLK delay, was 0x1000 */
+       { GLAMO_REG_MEM_TIMING9,        0x6006 },
+       { GLAMO_REG_MEM_TIMING10,       0x00ff },
+       { GLAMO_REG_MEM_TIMING11,       0x0001 },
+       { GLAMO_REG_MEM_POWER1,         0x0020 },
+       { GLAMO_REG_MEM_POWER2,         0x0000 },
+       { GLAMO_REG_MEM_DRAM1,          0x0000 },
+               { 0xfffe, 1 },
+       { GLAMO_REG_MEM_DRAM1,          0xc100 },
+               { 0xfffe, 1 },
+       { GLAMO_REG_MEM_DRAM1,          0xe100 },
+       { GLAMO_REG_MEM_DRAM2,          0x01d6 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x000b },
+};
+
+#if 0 /* MM370 */
+static const struct glamo_script regs_vram_2mb = {
+       { GLAMO_REG_CLOCK_MEMORY,       0x3aaa },
+               { 0xfffe, 50 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x0aaa },
+               { 0xfffe, 3 },
+       { GLAMO_REG_MEM_POWER1,         0x0020 },
+       { 0x033a,                       0x0000 },
+       { 0x033c,                       0x0000 },
+       { 0x033e,                       0x0000 },
+       { 0x0340,                       0x0000 },
+       { 0x0342,                       0x0000 },
+       { 0x0344,                       0x0000 },
+       { 0x0346,                       0x0240 },
+       { GLAMO_REG_MEM_TIMING8,        0x1016 },
+       { GLAMO_REG_MEM_TIMING9,        0x6067 },
+       { GLAMO_REG_MEM_TIMING10,       0x00ff },
+       { GLAMO_REG_MEM_TIMING11,       0x0030 },
+       { GLAMO_REG_MEM_GEN,            0x3fff },
+       { GLAMO_REG_MEM_GEN,            0xafaf },
+       { GLAMO_REG_MEM_TIMING1,        0x0108 },
+       { GLAMO_REG_MEM_TIMING2,        0x0010 },
+       { GLAMO_REG_MEM_DRAM1,          0x0a00 },
+               { 0xfffe, 3 },
+       { GLAMO_REG_MEM_DRAM1,          0xe200 },
+               { 0xfffe, 1 },
+};
+
+static const struct glamo_script regs_vram_8mb = {
+       { GLAMO_REG_CLOCK_MEMORY,       0x3aaa },
+               { 0xfffe, 50 },
+       { GLAMO_REG_CLOCK_MEMORY,       0x0aaa },
+               { 0xfffe, 3 },
+       { GLAMO_REG_MEM_POWER1,         0x0020 },
+       { 0x033a,                       0x45cf },
+       { 0x033c,                       0x4240 },
+       { 0x033e,                       0x53e0 },
+       { 0x0340,                       0x1401 },
+       { 0x0342,                       0x0c44 },
+       { 0x0344,                       0x1d0b },
+       { 0x0346,                       0x25ac },
+       { 0x0348,                       0x1953 },
+               { 0xfffe, 1 },
+       { GLAMO_REG_MEM_TYPE,           0x087a },
+       { GLAMO_REG_MEM_DRAM2,          0x01d6 },
+       { GLAMO_REG_MEM_TIMING8,        0x1060 },
+       { GLAMO_REG_MEM_TIMING9,        0x6067 },
+       { GLAMO_REG_MEM_TIMING10,       0x00ff },
+       { GLAMO_REG_MEM_TIMING11,       0x0030 },
+       { GLAMO_REG_MEM_GEN,            0x3fff },
+       { GLAMO_REG_MEM_GEN,            0xafaf },
+       { GLAMO_REG_MEM_TIMING1,        0x3108 },
+       { GLAMO_REG_MEM_TIMING2,        0x0010 },
+       { GLAMO_REG_MEM_DRAM1,          0x0a00 },
+               { 0xfffe, 3 },
+       { GLAMO_REG_MEM_DRAM1,          0xe200 },
+               { 0xfffe, 1 },
+};
+#endif
+
+enum glamo_power {
+       GLAMO_POWER_ON,
+       GLAMO_POWER_STANDBY,
+       GLAMO_POWER_SUSPEND,
+};
+
+static void glamo_power(struct glamo_core *glamo,
+                       enum glamo_power new_state)
+{
+       spin_lock(&glamo->lock);
+
+       switch (new_state) {
+       case GLAMO_POWER_ON:
+               /* power up PLL1 and PLL2 */
+               __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN6, 0x0001, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0x0000);
+
+               /* spin until PLL1 and PLL2 lock */
+               while ((__reg_read(glamo, GLAMO_REG_PLL_GEN5) & 3) != 3)
+                       ;
+
+               /* enable memory clock and get it out of deep pwrdown */
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+                                  GLAMO_CLOCK_MEM_EN_MOCACLK, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
+                                  GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0x0000);
+               __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
+                                  GLAMO_MEM_DRAM1_SELF_REFRESH, 0x0000);
+
+               glamo_run_script(glamo, glamo_resume_script,
+                                ARRAY_SIZE(glamo_resume_script), 0);
+
+               break;
+       case GLAMO_POWER_STANDBY:
+               /* enable memory self-refresh */
+               __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
+                                  GLAMO_MEM_DRAM1_SELF_REFRESH, 0xffff);
+               /* stop memory clock */
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+                                  GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
+               /* power down PLL2 and then PLL1 */
+               __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
+               break;
+       case GLAMO_POWER_SUSPEND:
+               __reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
+                                  GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0xffff);
+               /* stop memory clock */
+               __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
+                                  GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
+               /* power down PLL2 and then PLL1 */
+               __reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
+               __reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
+               break;
+       }
+
+       spin_unlock(&glamo->lock);
+}
+
+#if 0
+#define MEMDETECT_RETRY        6
+static unsigned int detect_memsize(struct glamo_core *glamo)
+{
+       int i;
+
+       /*static const u_int16_t pattern[] = {
+               0x1111, 0x8a8a, 0x2222, 0x7a7a,
+               0x3333, 0x6a6a, 0x4444, 0x5a5a,
+               0x5555, 0x4a4a, 0x6666, 0x3a3a,
+               0x7777, 0x2a2a, 0x8888, 0x1a1a
+       }; */
+
+       for (i = 0; i < MEMDETECT_RETRY; i++) {
+               switch (glamo->type) {
+               case 3600:
+                       __reg_write(glamo, GLAMO_REG_MEM_TYPE, 0x0072);
+                       __reg_write(glamo, GLAMO_REG_MEM_DRAM1, 0xc100);
+                       break;
+               case 3650:
+                       switch (glamo->revision) {
+                       case GLAMO_CORE_REV_A0:
+                               if (i & 1)
+                                       __reg_write(glamo, GLAMO_REG_MEM_TYPE,
+                                                   0x097a);
+                               else
+                                       __reg_write(glamo, GLAMO_REG_MEM_TYPE,
+                                                   0x0173);
+
+                               __reg_write(glamo, GLAMO_REG_MEM_DRAM1, 0x0000);
+                               msleep(1);
+                               __reg_write(glamo, GLAMO_REG_MEM_DRAM1, 0xc100);
+                               break;
+                       default:
+                               if (i & 1)
+                                       __reg_write(glamo, GLAMO_REG_MEM_TYPE,
+                                                   0x0972);
+                               else
+                                       __reg_write(glamo, GLAMO_REG_MEM_TYPE,
+                                                   0x0872);
+
+                               __reg_write(glamo, GLAMO_REG_MEM_DRAM1, 0x0000);
+                               msleep(1);
+                               __reg_write(glamo, GLAMO_REG_MEM_DRAM1, 0xe100);
+                               break;
+                       }
+                       break;
+               case 3700:
+                       /* FIXME */
+               default:
+                       break;
+               }
+
+#if 0
+               /* FIXME: finish implementation */
+               for (j = 0; j < 8; j++) {
+                       __
+#endif
+       }
+
+       return 0;
+}
+#endif
+
+/* Find out if we can support this version of the Glamo chip */
+static int glamo_supported(struct glamo_core *glamo)
+{
+       u_int16_t dev_id, rev_id; /*, memsize; */
+
+       dev_id = __reg_read(glamo, GLAMO_REG_DEVICE_ID);
+       rev_id = __reg_read(glamo, GLAMO_REG_REVISION_ID);
+
+       switch (dev_id) {
+       case 0x3650:
+               switch (rev_id) {
+               case GLAMO_CORE_REV_A2:
+                       break;
+               case GLAMO_CORE_REV_A0:
+               case GLAMO_CORE_REV_A1:
+               case GLAMO_CORE_REV_A3:
+                       dev_warn(&glamo->pdev->dev, "untested core revision "
+                                "%04x, your mileage may vary\n", rev_id);
+                       break;
+               default:
+                       dev_warn(&glamo->pdev->dev, "unknown glamo revision "
+                                "%04x, your mileage may vary\n", rev_id);
+                       /* maybe should abort ? */
+               }
+               break;
+       case 0x3600:
+       case 0x3700:
+       default:
+               dev_err(&glamo->pdev->dev, "unsupported Glamo device %04x\n",
+                       dev_id);
+               return 0;
+       }
+
+       dev_info(&glamo->pdev->dev, "Detected Glamo core %04x Revision %04x "
+                "(%uHz CPU / %uHz Memory)\n", dev_id, rev_id,
+                glamo_pll_rate(glamo, GLAMO_PLL1),
+                glamo_pll_rate(glamo, GLAMO_PLL2));
+
+       return 1;
+}
+
+
+static int __init glamo_probe(struct platform_device *pdev)
+{
+       int rc, irq;
+       struct glamo_core *glamo;
+
+       if (glamo_handle) {
+               dev_err(&pdev->dev,
+                       "This driver supports only one instance\n");
+               return -EBUSY;
+       }
+
+       glamo = kmalloc(GFP_KERNEL, sizeof(*glamo));
+       if (!glamo)
+               return -ENOMEM;
+
+       spin_lock_init(&glamo->lock);
+       glamo_handle = glamo;
+       glamo->pdev = pdev;
+       glamo->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       glamo->irq = platform_get_irq(pdev, 0);
+       glamo->pdata = pdev->dev.platform_data;
+       if (!glamo->mem || !glamo->pdata) {
+               dev_err(&pdev->dev, "platform device with no MEM/PDATA ?\n");
+               rc = -ENOENT;
+               goto out_free;
+       }
+
+       /* register a number of sibling devices whoise IOMEM resources
+        * are siblings of pdev's IOMEM resource */
+#if 0
+       glamo_core_dev.dev.parent = &pdev.dev;
+       mangle_mem_resources(glamo_core_dev.resources,
+                            glamo_core_dev.num_resources, glamo->mem);
+       glamo_core_dev.resources[1].start = glamo->irq;
+       glamo_core_dev.resources[1].end = glamo->irq;
+       platform_device_register(&glamo_core_dev);
+#endif
+       /* only remap the generic, hostbus and memory controller registers */
+       glamo->base = ioremap(glamo->mem->start, GLAMO_REGOFS_VIDCAP);
+       if (!glamo->base) {
+               dev_err(&pdev->dev, "failed to ioremap() memory region\n");
+               goto out_free;
+       }
+
+       /* bring MCI specific stuff over from our MFD platform data */
+       glamo_mci_def_pdata.glamo_set_mci_power =
+                                       glamo->pdata->glamo_set_mci_power;
+       glamo_mci_def_pdata.glamo_irq_is_wired =
+                                       glamo->pdata->glamo_irq_is_wired;
+
+       glamo_mmc_dev.dev.parent = &pdev->dev;
+       /* we need it later to give to the engine enable and disable */
+       glamo_mci_def_pdata.pglamo = glamo;
+       mangle_mem_resources(glamo_mmc_dev.resource,
+                            glamo_mmc_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_mmc_dev);
+
+       glamo_2d_dev.dev.parent = &pdev->dev;
+       mangle_mem_resources(glamo_2d_dev.resource,
+                            glamo_2d_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_2d_dev);
+
+       glamo_3d_dev.dev.parent = &pdev->dev;
+       mangle_mem_resources(glamo_3d_dev.resource,
+                            glamo_3d_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_3d_dev);
+
+       glamo_jpeg_dev.dev.parent = &pdev->dev;
+       mangle_mem_resources(glamo_jpeg_dev.resource,
+                            glamo_jpeg_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_jpeg_dev);
+
+       glamo_mpeg_dev.dev.parent = &pdev->dev;
+       mangle_mem_resources(glamo_mpeg_dev.resource,
+                            glamo_mpeg_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_mpeg_dev);
+
+       glamo->pdata->glamo = glamo;
+       glamo_fb_dev.dev.parent = &pdev->dev;
+       glamo_fb_dev.dev.platform_data = glamo->pdata;
+       mangle_mem_resources(glamo_fb_dev.resource,
+                            glamo_fb_dev.num_resources, glamo->mem);
+       platform_device_register(&glamo_fb_dev);
+
+       glamo->pdata->spigpio_info->glamo = glamo;
+       glamo_spigpio_dev.dev.parent = &pdev->dev;
+       glamo_spigpio_dev.dev.platform_data = glamo->pdata->spigpio_info;
+       platform_device_register(&glamo_spigpio_dev);
+
+       /* only request the generic, hostbus and memory controller MMIO */
+       glamo->mem = request_mem_region(glamo->mem->start,
+                                       GLAMO_REGOFS_VIDCAP, "glamo-core");
+       if (!glamo->mem) {
+               dev_err(&pdev->dev, "failed to request memory region\n");
+               goto out_free;
+       }
+
+       if (!glamo_supported(glamo)) {
+               dev_err(&pdev->dev, "This Glamo is not supported\n");
+               goto out_free;
+       }
+
+       platform_set_drvdata(pdev, glamo);
+
+       dev_dbg(&glamo->pdev->dev, "running init script\n");
+       glamo_run_script(glamo, glamo_init_script,
+                        ARRAY_SIZE(glamo_init_script), 1);
+
+       dev_info(&glamo->pdev->dev, "Glamo core now %uHz CPU / %uHz Memory)\n",
+                glamo_pll_rate(glamo, GLAMO_PLL1),
+                glamo_pll_rate(glamo, GLAMO_PLL2));
+
+       for (irq = IRQ_GLAMO(0); irq <= IRQ_GLAMO(8); irq++) {
+               set_irq_chip(irq, &glamo_irq_chip);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       if (glamo->pdata->glamo_irq_is_wired &&
+           !glamo->pdata->glamo_irq_is_wired()) {
+               set_irq_chained_handler(glamo->irq, glamo_irq_demux_handler);
+               set_irq_type(glamo->irq, IRQT_FALLING);
+               glamo->irq_works = 1;
+       } else
+               glamo->irq_works = 0;
+       return 0;
+
+out_free:
+       glamo_handle = NULL;
+       kfree(glamo);
+       return rc;
+}
+
+static int glamo_remove(struct platform_device *pdev)
+{
+       struct glamo_core *glamo = platform_get_drvdata(pdev);
+       int irq;
+
+       disable_irq(glamo->irq);
+       set_irq_chained_handler(glamo->irq, NULL);
+
+       for (irq = IRQ_GLAMO(0); irq <= IRQ_GLAMO(8); irq++) {
+               set_irq_flags(irq, 0);
+               set_irq_chip(irq, NULL);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+       platform_device_unregister(&glamo_fb_dev);
+       platform_device_unregister(&glamo_mmc_dev);
+       iounmap(glamo->base);
+       release_mem_region(glamo->mem->start, GLAMO_REGOFS_VIDCAP);
+       glamo_handle = NULL;
+       kfree(glamo);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int glamo_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int glamo_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define glamo_suspend NULL
+#define glamo_resume  NULL
+#endif
+
+static struct platform_driver glamo_driver = {
+       .probe          = glamo_probe,
+       .remove         = glamo_remove,
+       .suspend        = glamo_suspend,
+       .resume         = glamo_resume,
+       .driver         = {
+               .name   = "glamo3362",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __devinit glamo_init(void)
+{
+       return platform_driver_register(&glamo_driver);
+}
+
+static void __exit glamo_cleanup(void)
+{
+       platform_driver_unregister(&glamo_driver);
+}
+
+module_init(glamo_init);
+module_exit(glamo_cleanup);
+
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+MODULE_DESCRIPTION("Smedia Glamo 336x/337x core/resource driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h
new file mode 100644 (file)
index 0000000..cf89f03
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __GLAMO_CORE_H
+#define __GLAMO_CORE_H
+
+#include <asm/system.h>
+
+
+/* for the time being, we put the on-screen framebuffer into the lowest
+ * VRAM space.  This should make the code easily compatible with the various
+ * 2MB/4MB/8MB variants of the Smedia chips */
+#define GLAMO_OFFSET_VRAM      0x800000
+#define GLAMO_OFFSET_FB        (GLAMO_OFFSET_VRAM)
+
+/* we only allocate the minimum possible size for the framebuffer to make
+ * sure we have sufficient memory for other functions of the chip */
+//#define GLAMO_FB_SIZE        (640*480*4)     /* == 0x12c000 */
+#define GLAMO_INTERNAL_RAM_SIZE 0x800000
+#define GLAMO_MMC_BUFFER_SIZE (64 * 1024)
+#define GLAMO_FB_SIZE  (GLAMO_INTERNAL_RAM_SIZE - GLAMO_MMC_BUFFER_SIZE)
+
+
+struct glamo_core {
+       int irq;
+       int irq_works; /* 0 means PCB does not support Glamo IRQ */
+       struct resource *mem;
+       struct resource *mem_core;
+       void __iomem *base;
+       struct platform_device *pdev;
+       struct glamofb_platform_data *pdata;
+       u_int16_t type;
+       u_int16_t revision;
+       spinlock_t lock;
+};
+
+struct glamo_script {
+       u_int16_t reg;
+       u_int16_t val;
+};
+
+int glamo_run_script(struct glamo_core *glamo,
+                    struct glamo_script *script, int len, int may_sleep);
+
+enum glamo_engine {
+       GLAMO_ENGINE_CAPTURE,
+       GLAMO_ENGINE_ISP,
+       GLAMO_ENGINE_JPEG,
+       GLAMO_ENGINE_MPEG_ENC,
+       GLAMO_ENGINE_MPEG_DEC,
+       GLAMO_ENGINE_LCD,
+       GLAMO_ENGINE_CMDQ,
+       GLAMO_ENGINE_2D,
+       GLAMO_ENGINE_3D,
+       GLAMO_ENGINE_MMC,
+       GLAMO_ENGINE_MICROP0,
+       GLAMO_ENGINE_RISC,
+       GLAMO_ENGINE_MICROP1_MPEG_ENC,
+       GLAMO_ENGINE_MICROP1_MPEG_DEC,
+#if 0
+       GLAMO_ENGINE_H264_DEC,
+       GLAMO_ENGINE_RISC1,
+       GLAMO_ENGINE_SPI,
+#endif
+       __NUM_GLAMO_ENGINES
+};
+
+struct glamo_mci_pdata {
+       struct glamo_core * pglamo;
+       unsigned int    gpio_detect;
+       unsigned int    gpio_wprotect;
+       unsigned long   ocr_avail;
+       void            (*glamo_set_mci_power)(unsigned char power_mode,
+                                    unsigned short vdd);
+       int             (*glamo_irq_is_wired)(void);
+};
+
+
+static inline void glamo_reg_access_delay(void)
+{
+       int n;
+
+       for (n = 0; n != 2; n++)
+               nop();
+}
+
+
+int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine);
+int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine);
+void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine);
+int glamo_engine_reclock(struct glamo_core *glamo,
+                        enum glamo_engine engine, int ps);
+
+#endif /* __GLAMO_CORE_H */
diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c
new file mode 100644 (file)
index 0000000..394a0ad
--- /dev/null
@@ -0,0 +1,822 @@
+/* Smedia Glamo 336x/337x driver
+ *
+ * (C) 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <linux/glamofb.h>
+
+#include "glamo-regs.h"
+#include "glamo-core.h"
+
+#ifdef DEBUG
+#define GLAMO_LOG(...)
+#else
+#define GLAMO_LOG(...) \
+do { \
+       printk(KERN_DEBUG "in %s:%s:%d", __FILE__, __func__, __LINE__); \
+       printk(KERN_DEBUG __VA_ARGS__); \
+} while (0);
+#endif
+
+
+#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
+
+struct glamofb_handle {
+       struct fb_info *fb;
+       struct device *dev;
+       struct resource *reg;
+       struct resource *fb_res;
+       char __iomem *base;
+       struct glamofb_platform_data *mach_info;
+       char __iomem *cursor_addr;
+       u_int32_t pseudo_pal[16];
+};
+
+/* 'sibling' spi device for lcm init */
+static struct platform_device glamo_spi_dev = {
+       .name           = "glamo-lcm-spi",
+};
+
+
+static int reg_read(struct glamofb_handle *glamo,
+                          u_int16_t reg)
+{
+       glamo_reg_access_delay();
+       return readw(glamo->base + reg);
+}
+
+static void reg_write(struct glamofb_handle *glamo,
+                            u_int16_t reg, u_int16_t val)
+{
+       glamo_reg_access_delay();
+       writew(val, glamo->base + reg);
+}
+
+static struct glamo_script glamo_regs[] = {
+       { GLAMO_REG_LCD_MODE1, 0x0020 },
+       /* no display rotation, no hardware cursor, no dither, no gamma,
+        * no retrace flip, vsync low-active, hsync low active,
+        * no TVCLK, no partial display, hw dest color from fb,
+        * no partial display mode, LCD1, software flip,  */
+       { GLAMO_REG_LCD_MODE2, 0x1020 },
+         /* no video flip, no ptr, no ptr, dhclk,
+          * normal mode,  no cpuif,
+          * res, serial msb first, single fb, no fr ctrl,
+          * cpu if bits all zero, no crc
+          * 0000 0000 0010  0000 */
+       { GLAMO_REG_LCD_MODE3, 0x0b40 },
+         /* src data rgb565, res, 18bit rgb666
+          * 000 01 011 0100 0000 */
+       { GLAMO_REG_LCD_POLARITY, 0x440c },
+         /* DE high active, no cpu/lcd if, cs0 force low, a0 low active,
+          * np cpu if, 9bit serial data, sclk rising edge latch data
+          * 01 00 0 100 0 000 01 0 0 */
+       { GLAMO_REG_LCD_A_BASE1, 0x0000 }, /* display A base address 15:0 */
+       { GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */
+};
+
+static int glamofb_run_script(struct glamofb_handle *glamo,
+                               struct glamo_script *script, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               struct glamo_script *line = &script[i];
+
+               if (line->reg == 0xffff)
+                       return 0;
+               else if (line->reg == 0xfffe)
+                       msleep(line->val);
+               else
+                       reg_write(glamo, script[i].reg, script[i].val);
+       }
+
+       return 0;
+}
+
+static int glamofb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct glamofb_handle *glamo = info->par;
+
+       if (var->yres > glamo->mach_info->yres.max)
+               var->yres = glamo->mach_info->yres.max;
+       else if (var->yres < glamo->mach_info->yres.min)
+               var->yres = glamo->mach_info->yres.min;
+
+       if (var->xres > glamo->mach_info->xres.max)
+               var->xres = glamo->mach_info->xres.max;
+       else if (var->xres < glamo->mach_info->xres.min)
+               var->xres = glamo->mach_info->xres.min;
+
+       if (var->bits_per_pixel > glamo->mach_info->bpp.max)
+               var->bits_per_pixel = glamo->mach_info->bpp.max;
+       else if (var->bits_per_pixel < glamo->mach_info->bpp.min)
+               var->bits_per_pixel = glamo->mach_info->bpp.min;
+
+       /* FIXME: set rgb positions */
+       switch (var->bits_per_pixel) {
+       case 16:
+               switch (reg_read(glamo, GLAMO_REG_LCD_MODE3) & 0xc000) {
+               case GLAMO_LCD_SRC_RGB565:
+                       var->red.offset         = 11;
+                       var->green.offset       = 5;
+                       var->blue.offset        = 0;
+                       var->red.length         = 5;
+                       var->green.length       = 6;
+                       var->blue.length        = 5;
+                       var->transp.length      = 0;
+                       break;
+               case GLAMO_LCD_SRC_ARGB1555:
+                       var->transp.offset      = 15;
+                       var->red.offset         = 10;
+                       var->green.offset       = 5;
+                       var->blue.offset        = 0;
+                       var->transp.length      = 1;
+                       var->red.length         = 5;
+                       var->green.length       = 5;
+                       var->blue.length        = 5;
+                       break;
+               case GLAMO_LCD_SRC_ARGB4444:
+                       var->transp.offset      = 12;
+                       var->red.offset         = 8;
+                       var->green.offset       = 4;
+                       var->blue.offset        = 0;
+                       var->transp.length      = 4;
+                       var->red.length         = 4;
+                       var->green.length       = 4;
+                       var->blue.length        = 4;
+                       break;
+               }
+               break;
+       case 24:
+       case 32:
+       default:
+               /* The Smedia Glamo doesn't support anything but 16bit color */
+               printk(KERN_ERR
+                      "Smedia driver does not [yet?] support 24/32bpp\n");
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+static void reg_set_bit_mask(struct glamofb_handle *glamo,
+                            u_int16_t reg, u_int16_t mask,
+                            u_int16_t val)
+{
+       u_int16_t tmp;
+
+       val &= mask;
+
+       tmp = reg_read(glamo, reg);
+       tmp &= ~mask;
+       tmp |= val;
+       reg_write(glamo, reg, tmp);
+}
+
+#define GLAMO_LCD_WIDTH_MASK 0x03FF
+#define GLAMO_LCD_HEIGHT_MASK 0x03FF
+#define GLAMO_LCD_PITCH_MASK 0x07FE
+#define GLAMO_LCD_HV_TOTAL_MASK 0x03FF
+#define GLAMO_LCD_HV_RETR_START_MASK 0x03FF
+#define GLAMO_LCD_HV_RETR_END_MASK 0x03FF
+#define GLAMO_LCD_HV_RETR_DISP_START_MASK 0x03FF
+#define GLAMO_LCD_HV_RETR_DISP_END_MASK 0x03FF
+
+enum orientation {
+    ORIENTATION_PORTRAIT,
+    ORIENTATION_LANDSCAPE
+};
+
+
+static void rotate_lcd(struct glamofb_handle *glamo,
+                       __u32 rotation)
+{
+       int glamo_rot;
+
+       switch (rotation) {
+               case FB_ROTATE_UR:
+                       glamo_rot = GLAMO_LCD_ROT_MODE_0;
+                       break;
+               case FB_ROTATE_CW:
+                       glamo_rot = GLAMO_LCD_ROT_MODE_90;
+                       break;
+               case FB_ROTATE_UD:
+                       glamo_rot = GLAMO_LCD_ROT_MODE_180;
+                       break;
+               case FB_ROTATE_CCW:
+                       glamo_rot = GLAMO_LCD_ROT_MODE_270;
+                       break;
+               default:
+                       glamo_rot = GLAMO_LCD_ROT_MODE_0;
+                       break;
+       }
+       glamofb_cmd_mode(glamo, 1);
+       reg_set_bit_mask(glamo,
+                        GLAMO_REG_LCD_WIDTH,
+                        GLAMO_LCD_ROT_MODE_MASK,
+                        glamo_rot);
+       reg_set_bit_mask(glamo,
+                        GLAMO_REG_LCD_MODE1,
+                        GLAMO_LCD_MODE1_ROTATE_EN,
+                        (glamo_rot != GLAMO_LCD_ROT_MODE_0)?
+                                GLAMO_LCD_MODE1_ROTATE_EN : 0);
+       glamofb_cmd_mode(glamo, 0);
+}
+
+static enum orientation get_orientation(struct fb_var_screeninfo *var)
+{
+       GLAMO_LOG("mark\n")
+       if (var->xres <= var->yres) {
+               GLAMO_LOG("portrait\n")
+               return ORIENTATION_PORTRAIT;
+       }
+       GLAMO_LOG("landscape\n")
+       return ORIENTATION_LANDSCAPE;
+}
+
+static int will_orientation_change(struct fb_var_screeninfo *var)
+{
+       enum  orientation orient = get_orientation(var);
+       switch (orient) {
+               case ORIENTATION_LANDSCAPE:
+                       if (var->rotate == FB_ROTATE_UR || var->rotate == FB_ROTATE_UD)
+                               return 1;
+                       break;
+               case ORIENTATION_PORTRAIT:
+                       if (var->rotate == FB_ROTATE_CW || var->rotate == FB_ROTATE_CCW)
+                               return 1;
+                       break;
+       }
+       return 0;
+}
+
+static void glamofb_update_lcd_controller(struct glamofb_handle *glamo,
+                                         struct fb_var_screeninfo *var)
+{
+       int sync, bp, disp, fp, total, xres, yres, pitch, orientation_changing;
+
+       GLAMO_LOG("enter: glamo:%#x, var:%#x\n", (unsigned)glamo, (unsigned)var);
+       if (!glamo || !var)
+               return;
+
+       glamofb_cmd_mode(glamo, 1);
+
+       if (var->pixclock)
+               glamo_engine_reclock(glamo->mach_info->glamo,
+                                    GLAMO_ENGINE_LCD,
+                                    var->pixclock);
+
+       xres = var->xres;
+       yres = var->yres;
+       GLAMO_LOG("xres:%d, yres:%d, rotate:%d\n", xres, yres, var->rotate);
+
+       /*
+        * figure out if orientation is going to change
+        */
+       orientation_changing = will_orientation_change(var);
+       GLAMO_LOG("orientation_changing:%d\n", orientation_changing);
+
+        /*
+         * adjust the pitch according to new orientation to come
+         */
+        if (orientation_changing) {
+               pitch = var->yres * var->bits_per_pixel / 8;
+        } else {
+               pitch = var->xres * var->bits_per_pixel / 8;
+        }
+       GLAMO_LOG("pitch:%d\n", pitch);
+
+       /*
+        * set the awaiten LCD geometry
+        */
+       reg_set_bit_mask(glamo,
+                        GLAMO_REG_LCD_WIDTH,
+                        GLAMO_LCD_WIDTH_MASK,
+                        xres);
+       reg_set_bit_mask(glamo,
+                        GLAMO_REG_LCD_HEIGHT,
+                        GLAMO_LCD_HEIGHT_MASK,
+                        yres);
+       reg_set_bit_mask(glamo,
+                        GLAMO_REG_LCD_PITCH,
+                        GLAMO_LCD_PITCH_MASK,
+                        pitch);
+
+       GLAMO_LOG("mark:\n");
+       /*
+        * honour the rotation request
+        */
+       rotate_lcd(glamo, var->rotate);
+
+       /*
+        * update the reported geometry
+        * of the framebuffer.
+        */
+       if (orientation_changing) {
+               var->xres_virtual = var->xres = yres;
+               var->yres_virtual = var->yres = xres;
+       } else {
+               var->xres_virtual = var->xres = xres;
+               var->yres_virtual = var->yres = yres;
+       }
+
+       GLAMO_LOG("reported res:(%d,%d)\n", var->xres, var->yres);
+       /*
+        * update scannout timings
+        */
+       sync = 0;
+       bp = sync + var->hsync_len;
+       disp = bp + var->left_margin;
+       fp = disp + xres;
+       total = fp + var->right_margin;
+
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_TOTAL,
+                        GLAMO_LCD_HV_TOTAL_MASK, total);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_RETR_START,
+                        GLAMO_LCD_HV_RETR_START_MASK, sync);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_RETR_END,
+                        GLAMO_LCD_HV_RETR_END_MASK, bp);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_DISP_START,
+                         GLAMO_LCD_HV_RETR_DISP_START_MASK, disp);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_HORIZ_DISP_END,
+                        GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
+
+       GLAMO_LOG("mark:\n");
+
+       sync = 0;
+       bp = sync + var->vsync_len;
+       disp = bp + var->upper_margin;
+       fp = disp + yres;
+       total = fp + var->lower_margin;
+
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_TOTAL,
+                        GLAMO_LCD_HV_TOTAL_MASK, total);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_RETR_START,
+                         GLAMO_LCD_HV_RETR_START_MASK, sync);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_RETR_END,
+                        GLAMO_LCD_HV_RETR_END_MASK, bp);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_DISP_START,
+                        GLAMO_LCD_HV_RETR_DISP_START_MASK, disp);
+       reg_set_bit_mask(glamo, GLAMO_REG_LCD_VERT_DISP_END,
+                        GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
+
+       GLAMO_LOG("mark:\n");
+       glamofb_cmd_mode(glamo, 0);
+
+       GLAMO_LOG("leave:\n");
+}
+
+static int glamofb_set_par(struct fb_info *info)
+{
+       struct glamofb_handle *glamo = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+               break;
+       default:
+               printk("Smedia driver doesn't support != 16bpp\n");
+               return -EINVAL;
+       }
+
+       info->fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+
+       glamofb_update_lcd_controller(glamo, var);
+
+       return 0;
+}
+
+static int glamofb_blank(int blank_mode, struct fb_info *info)
+{
+       /* FIXME */
+       return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+static int glamofb_setcolreg(unsigned regno,
+                            unsigned red, unsigned green, unsigned blue,
+                            unsigned transp, struct fb_info *info)
+{
+       struct glamofb_handle *glamo = info->par;
+       unsigned int val;
+
+       switch (glamo->fb->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+       case FB_VISUAL_DIRECTCOLOR:
+               /* true-colour, use pseuo-palette */
+
+               if (regno < 16) {
+                       u32 *pal = glamo->fb->pseudo_palette;
+
+                       val  = chan_to_field(red, &glamo->fb->var.red);
+                       val |= chan_to_field(green, &glamo->fb->var.green);
+                       val |= chan_to_field(blue, &glamo->fb->var.blue);
+
+                       pal[regno] = val;
+               };
+               break;
+       default:
+               return 1; /* unknown type */
+       }
+
+       return 0;
+}
+
+static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+       struct glamofb_handle *glamo = info->par;
+       u_int16_t reg;
+
+       if (cursor->image.depth > 2)
+               return -EINVAL;
+
+       reg = reg_read(glamo, GLAMO_REG_LCD_MODE1);
+
+       if (cursor->enable)
+               reg_write(glamo, GLAMO_REG_LCD_MODE1,
+                         reg | GLAMO_LCD_MODE1_CURSOR_EN);
+       else
+               reg_write(glamo, GLAMO_REG_LCD_MODE1,
+                         reg & ~GLAMO_LCD_MODE1_CURSOR_EN);
+
+       if (cursor->set & FB_CUR_SETPOS) {
+               reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_POS,
+                         cursor->image.dx);
+               reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_POS,
+                         cursor->image.dy);
+       }
+
+       if (cursor->set & FB_CUR_SETCMAP) {
+               /* FIXME */
+       }
+
+       if (cursor->set & FB_CUR_SETSIZE ||
+           cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
+               int x, y, op;
+               const unsigned char *pcol = cursor->image.data;
+               const unsigned char *pmsk = cursor->mask;
+               void __iomem *dst = glamo->cursor_addr;
+               unsigned char dcol = 0;
+               unsigned char dmsk = 0;
+
+               reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE,
+                         cursor->image.width);
+               reg_write(glamo, GLAMO_REG_LCD_CURSOR_PITCH,
+                         cursor->image.width * 2);
+               reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE,
+                         cursor->image.height);
+
+               for (op = 0; op < (cursor->image.width *
+                                  cursor->image.height * 2)/8; op += 4)
+                       writel(0x0, dst + op);
+
+               for (y = 0; y < cursor->image.height; y++) {
+                       for (x = 0; x < cursor->image.width; x++) {
+                               if ((x % 8) == 0) {
+                                       dcol = *pcol++;
+                                       dmsk = *pmsk++;
+                               } else {
+                                       dcol >>= 1;
+                                       dmsk >>= 1;
+                               }
+
+                               if (dmsk & 1) {
+                                       unsigned int op;
+
+                                       op = (dcol & 1) ? 1 : 3;
+                                       op <<= ((x % 4) * 2);
+
+                                       op |= readb(dst + (x / 4));
+                                       writeb(op, dst + (x / 4));
+                               }
+                       }
+               }
+       }
+}
+
+static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb)
+{
+       return reg_read(gfb, GLAMO_REG_LCD_STATUS1) & (1 << 15);
+}
+
+void glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
+{
+       dev_dbg(gfb->dev, "glamofb_cmd_mode(gfb=%p, on=%d)\n", gfb, on);
+       if (on) {
+               dev_dbg(gfb->dev, "%s: waiting for cmdq empty: ",
+                       __FUNCTION__);
+               while (!glamofb_cmdq_empty(gfb))
+                       yield();
+               dev_dbg(gfb->dev, "empty!\n");
+
+               /* display the entire frame then switch to command */
+               reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
+                         GLAMO_LCD_CMD_TYPE_DISP |
+                         GLAMO_LCD_CMD_DATA_FIRE_VSYNC);
+
+               /* wait until LCD is idle */
+               dev_dbg(gfb->dev, "waiting for LCD idle: ");
+               while (!reg_read(gfb, GLAMO_REG_LCD_STATUS2) & (1 << 12))
+                       yield();
+               dev_dbg(gfb->dev, "idle!\n");
+
+               msleep(90);
+       } else {
+               /* RGB interface needs vsync/hsync */
+               if (reg_read(gfb, GLAMO_REG_LCD_MODE3) & GLAMO_LCD_MODE3_RGB)
+                       reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
+                                 GLAMO_LCD_CMD_TYPE_DISP |
+                                 GLAMO_LCD_CMD_DATA_DISP_SYNC);
+
+               reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
+                         GLAMO_LCD_CMD_TYPE_DISP |
+                         GLAMO_LCD_CMD_DATA_DISP_FIRE);
+       }
+}
+EXPORT_SYMBOL_GPL(glamofb_cmd_mode);
+
+int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val)
+{
+       dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n",
+               __FUNCTION__);
+       while (!glamofb_cmdq_empty(gfb))
+               yield();
+       dev_dbg(gfb->dev, "idle, writing 0x%04x\n", val);
+
+       reg_write(gfb, GLAMO_REG_LCD_COMMAND1, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(glamofb_cmd_write);
+
+static struct fb_ops glamofb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = glamofb_check_var,
+       .fb_set_par     = glamofb_set_par,
+       .fb_blank       = glamofb_blank,
+       .fb_setcolreg   = glamofb_setcolreg,
+       //.fb_cursor    = glamofb_cursor,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static int glamofb_init_regs(struct glamofb_handle *glamo)
+{
+       struct fb_info *info = glamo->fb;
+
+       glamofb_check_var(&info->var, info);
+       glamofb_run_script(glamo, glamo_regs, ARRAY_SIZE(glamo_regs));
+       glamofb_set_par(info);
+
+       return 0;
+}
+
+static int __init glamofb_probe(struct platform_device *pdev)
+{
+       int rc = -EIO;
+       struct fb_info *fbinfo;
+       struct glamofb_handle *glamofb;
+       struct glamofb_platform_data *mach_info = pdev->dev.platform_data;
+
+       printk(KERN_INFO "SMEDIA Glamo frame buffer driver (C) 2007 "
+               "OpenMoko, Inc.\n");
+
+       fbinfo = framebuffer_alloc(sizeof(struct glamofb_handle), &pdev->dev);
+       if (!fbinfo)
+               return -ENOMEM;
+
+       glamofb = fbinfo->par;
+       glamofb->fb = fbinfo;
+       glamofb->dev = &pdev->dev;
+
+       strcpy(fbinfo->fix.id, "SMedia Glamo");
+
+       glamofb->reg = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                   "glamo-fb-regs");
+       if (!glamofb->reg) {
+               dev_err(&pdev->dev, "platform device with no registers?\n");
+               rc = -ENOENT;
+               goto out_free;
+       }
+
+       glamofb->fb_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                       "glamo-fb-mem");
+       if (!glamofb->fb_res) {
+               dev_err(&pdev->dev, "platform device with no memory ?\n");
+               rc = -ENOENT;
+               goto out_free;
+       }
+
+       glamofb->reg = request_mem_region(glamofb->reg->start,
+                                         RESSIZE(glamofb->reg), pdev->name);
+       if (!glamofb->reg) {
+               dev_err(&pdev->dev, "failed to request mmio region\n");
+               goto out_free;
+       }
+
+       glamofb->fb_res = request_mem_region(glamofb->fb_res->start,
+                                            mach_info->fb_mem_size,
+                                            pdev->name);
+       if (!glamofb->fb_res) {
+               dev_err(&pdev->dev, "failed to request vram region\n");
+               goto out_release_reg;
+       }
+
+       /* we want to remap only the registers required for this core
+        * driver. */
+       glamofb->base = ioremap(glamofb->reg->start, RESSIZE(glamofb->reg));
+       if (!glamofb->base) {
+               dev_err(&pdev->dev, "failed to ioremap() mmio memory\n");
+               goto out_release_fb;
+       }
+       fbinfo->fix.smem_start = (unsigned long) glamofb->fb_res->start;
+       fbinfo->fix.smem_len = mach_info->fb_mem_size;
+
+       fbinfo->screen_base = ioremap(glamofb->fb_res->start,
+                                      RESSIZE(glamofb->fb_res));
+       if (!fbinfo->screen_base) {
+               dev_err(&pdev->dev, "failed to ioremap() vram memory\n");
+               goto out_release_fb;
+       }
+
+       platform_set_drvdata(pdev, fbinfo);
+
+       glamofb->mach_info = pdev->dev.platform_data;
+
+       fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
+       fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
+       fbinfo->fix.type_aux = 0;
+       fbinfo->fix.xpanstep = 0;
+       fbinfo->fix.ypanstep = 0;
+       fbinfo->fix.ywrapstep = 0;
+       fbinfo->fix.accel = FB_ACCEL_NONE; /* FIXME */
+
+       fbinfo->var.nonstd = 0;
+       fbinfo->var.activate = FB_ACTIVATE_NOW;
+       fbinfo->var.height = mach_info->height;
+       fbinfo->var.width = mach_info->width;
+       fbinfo->var.accel_flags = 0;
+       fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
+
+       fbinfo->fbops = &glamofb_ops;
+       fbinfo->flags = FBINFO_FLAG_DEFAULT;
+       fbinfo->pseudo_palette = &glamofb->pseudo_pal;
+
+       fbinfo->var.xres = mach_info->xres.defval;
+       fbinfo->var.xres_virtual = mach_info->xres.defval;
+       fbinfo->var.yres = mach_info->yres.defval;
+       fbinfo->var.yres_virtual = mach_info->yres.defval;
+       fbinfo->var.bits_per_pixel = mach_info->bpp.defval;
+
+       fbinfo->var.pixclock = mach_info->pixclock;
+       fbinfo->var.left_margin = mach_info->left_margin;
+       fbinfo->var.right_margin = mach_info->right_margin;
+       fbinfo->var.upper_margin = mach_info->upper_margin;
+       fbinfo->var.lower_margin = mach_info->lower_margin;
+       fbinfo->var.hsync_len = mach_info->hsync_len;
+       fbinfo->var.vsync_len = mach_info->vsync_len;
+
+       memset(fbinfo->screen_base, 0, fbinfo->fix.smem_len);
+
+       glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD);
+       glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD);
+       glamofb_init_regs(glamofb);
+
+       rc = register_framebuffer(fbinfo);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "failed to register framebuffer\n");
+               goto out_unmap_fb;
+       }
+
+       if (mach_info->spi_info) {
+               /* register the sibling spi device */
+               mach_info->spi_info->glamofb_handle = glamofb;
+               glamo_spi_dev.dev.parent = &pdev->dev;
+               glamo_spi_dev.dev.platform_data = mach_info->spi_info;
+               platform_device_register(&glamo_spi_dev);
+       }
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n",
+               fbinfo->node, fbinfo->fix.id);
+
+       return 0;
+
+out_unmap_fb:
+       iounmap(fbinfo->screen_base);
+       iounmap(glamofb->base);
+out_release_fb:
+       release_mem_region(glamofb->fb_res->start, RESSIZE(glamofb->fb_res));
+out_release_reg:
+       release_mem_region(glamofb->reg->start, RESSIZE(glamofb->reg));
+out_free:
+       framebuffer_release(fbinfo);
+       return rc;
+}
+
+static int glamofb_remove(struct platform_device *pdev)
+{
+       struct glamofb_handle *glamofb = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       iounmap(glamofb->base);
+       release_mem_region(glamofb->reg->start, RESSIZE(glamofb->reg));
+       kfree(glamofb);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int glamofb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int glamofb_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define glamofb_suspend NULL
+#define glamofb_resume  NULL
+#endif
+
+static struct platform_driver glamofb_driver = {
+       .probe          = glamofb_probe,
+       .remove         = glamofb_remove,
+       .suspend        = glamofb_suspend,
+       .resume         = glamofb_resume,
+       .driver         = {
+               .name   = "glamo-fb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __devinit glamofb_init(void)
+{
+       return platform_driver_register(&glamofb_driver);
+}
+
+static void __exit glamofb_cleanup(void)
+{
+       platform_driver_unregister(&glamofb_driver);
+}
+
+module_init(glamofb_init);
+module_exit(glamofb_cleanup);
+
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+MODULE_DESCRIPTION("Smedia Glamo 336x/337x framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/glamo/glamo-gpio.c b/drivers/mfd/glamo/glamo-gpio.c
new file mode 100644 (file)
index 0000000..45d0bf9
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#include <linux/glamo-gpio.h>
+
+#include "glamo-core.h"
+#include "glamo-regs.h"
+
+void glamo_gpio_setpin(struct glamo_core *glamo, unsigned int pin,
+                      unsigned int value)
+{
+       unsigned int reg = REG_OF_GPIO(pin);
+       u_int16_t tmp;
+
+       spin_lock(&glamo->lock);
+       tmp = readw(glamo->base + reg);
+       if (value)
+               tmp |= OUTPUT_BIT(pin);
+       else
+               tmp &= ~OUTPUT_BIT(pin);
+       writew(tmp, glamo->base + reg);
+       spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL(glamo_gpio_setpin);
+
+int glamo_gpio_getpin(struct glamo_core *glamo, unsigned int pin)
+{
+       return readw(REG_OF_GPIO(pin)) & INPUT_BIT(pin) ? 1 : 0;
+}
+EXPORT_SYMBOL(glamo_gpio_getpin);
+
+void glamo_gpio_cfgpin(struct glamo_core *glamo, unsigned int pinfunc)
+{
+       unsigned int reg = REG_OF_GPIO(pinfunc);
+       u_int16_t tmp;
+
+       spin_lock(&glamo->lock);
+       tmp = readw(glamo->base + reg);
+
+       if ((pinfunc & 0x00f0) == GLAMO_GPIO_F_FUNC) {
+               /* pin is a function pin: clear gpio bit */
+               tmp &= ~FUNC_BIT(pinfunc);
+       } else {
+               /* pin is gpio: set gpio bit */
+               tmp |= FUNC_BIT(pinfunc);
+
+               if (pinfunc & GLAMO_GPIO_F_IN) {
+                       /* gpio input: set bit to disable output mode */
+                       tmp |= GPIO_OUT_BIT(pinfunc);
+               } else if (pinfunc & GLAMO_GPIO_F_OUT) {
+                       /* gpio output: clear bit to enable output mode */
+                       tmp &= ~GPIO_OUT_BIT(pinfunc);
+               }
+       }
+       writew(tmp, glamo->base + reg);
+       spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL(glamo_gpio_cfgpin);
+
diff --git a/drivers/mfd/glamo/glamo-lcm-spi.c b/drivers/mfd/glamo/glamo-lcm-spi.c
new file mode 100644 (file)
index 0000000..92cabe4
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * Smedia Glamo GPIO based SPI driver
+ *
+ * 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 driver currently only implements a minimum subset of the hardware
+ * features, esp. those features that are required to drive the jbt6k74
+ * LCM controller asic in the TD028TTEC1 LCM.
+ *
+*/
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/glamo.h>
+
+#include <linux/glamofb.h>
+
+#include <asm/hardware.h>
+
+#include "glamo-core.h"
+#include "glamo-regs.h"
+
+struct glamo_spi {
+       struct spi_bitbang      bitbang;
+       struct spi_master       *master;
+       struct glamo_spi_info   *info;
+       struct device           *dev;
+};
+
+static inline struct glamo_spi *to_gs(struct spi_device *spi)
+{
+       return spi->controller_data;
+}
+
+static int glamo_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct glamo_spi *gs = to_gs(spi);
+       unsigned int bpw;
+
+       bpw = t ? t->bits_per_word : spi->bits_per_word;
+
+       if (bpw != 9 && bpw != 8) {
+               dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void glamo_spi_chipsel(struct spi_device *spi, int value)
+{
+#if 0
+       struct glamo_spi *gs = to_gs(spi);
+
+       dev_dbg(&spi->dev, "chipsel %d: spi=%p, gs=%p, info=%p, handle=%p\n",
+               value, spi, gs, gs->info, gs->info->glamofb_handle);
+
+       glamofb_cmd_mode(gs->info->glamofb_handle, value);
+#endif
+}
+
+static int glamo_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct glamo_spi *gs = to_gs(spi);
+       const u_int16_t *ui16 = (const u_int16_t *) t->tx_buf;
+       u_int16_t nine_bits;
+       int i;
+
+       dev_dbg(&spi->dev, "txrx: tx %p, rx %p, bpw %d, len %d\n",
+               t->tx_buf, t->rx_buf, t->bits_per_word, t->len);
+
+       if (spi->bits_per_word == 9)
+               nine_bits = (1 << 9);
+       else
+               nine_bits = 0;
+
+       if (t->len > 3 * sizeof(u_int16_t)) {
+               dev_err(&spi->dev, "this driver doesn't support "
+                       "%u sized xfers\n", t->len);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < t->len/sizeof(u_int16_t); i++) {
+               /* actually transfer the data */
+#if 1
+               glamofb_cmd_write(gs->info->glamofb_handle,
+                                 GLAMO_LCD_CMD_TYPE_SERIAL | nine_bits |
+                                 (1 << 10) | (1 << 11) | (ui16[i] & 0x1ff));
+#endif
+               /* FIXME: fire ?!? */
+               if (i == 0 && (ui16[i] & 0x1ff) == 0x29) {
+                       dev_dbg(&spi->dev, "leaving command mode\n");
+                       glamofb_cmd_mode(gs->info->glamofb_handle, 0);
+               }
+       }
+
+       return t->len;
+}
+
+static int glamo_spi_setup(struct spi_device *spi)
+{
+       int ret;
+
+       if (!spi->bits_per_word)
+               spi->bits_per_word = 9;
+
+       /* FIXME: hardware can do this */
+       if (spi->mode & SPI_LSB_FIRST)
+               return -EINVAL;
+
+       ret = glamo_spi_setupxfer(spi, NULL);
+       if (ret < 0) {
+               dev_err(&spi->dev, "setupxfer returned %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(&spi->dev, "%s: mode %d, %u bpw\n",
+               __FUNCTION__, spi->mode, spi->bits_per_word);
+
+       return 0;
+}
+
+static int glamo_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct glamo_spi *sp;
+       int ret;
+       int i;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct glamo_spi));
+       if (master == NULL) {
+               dev_err(&pdev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sp = spi_master_get_devdata(master);
+       memset(sp, 0, sizeof(struct glamo_spi));
+
+       sp->master = spi_master_get(master);
+       sp->info = pdev->dev.platform_data;
+       if (!sp->info) {
+               dev_err(&pdev->dev, "can't operate without platform data\n");
+               ret = -EIO;
+               goto err_no_pdev;
+       }
+       dev_dbg(&pdev->dev, "sp->info(pdata) = %p\n", sp->info);
+
+       sp->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, sp);
+
+       sp->bitbang.master = sp->master;
+       sp->bitbang.setup_transfer = glamo_spi_setupxfer;
+       sp->bitbang.chipselect = glamo_spi_chipsel;
+       sp->bitbang.txrx_bufs = glamo_spi_txrx;
+       sp->bitbang.master->setup = glamo_spi_setup;
+
+       ret = spi_bitbang_start(&sp->bitbang);
+       if (ret)
+               goto err_no_bitbang;
+
+       /* register the chips to go with the board */
+
+       glamofb_cmd_mode(sp->info->glamofb_handle, 1);
+
+       for (i = 0; i < sp->info->board_size; i++) {
+               dev_info(&pdev->dev, "registering %p: %s\n",
+                        &sp->info->board_info[i],
+                        sp->info->board_info[i].modalias);
+
+               sp->info->board_info[i].controller_data = sp;
+               spi_new_device(master, sp->info->board_info + i);
+       }
+
+       return 0;
+
+err_no_bitbang:
+       platform_set_drvdata(pdev, NULL);
+err_no_pdev:
+       spi_master_put(sp->bitbang.master);
+err:
+       return ret;
+
+}
+
+static int glamo_spi_remove(struct platform_device *pdev)
+{
+       struct glamo_spi *sp = platform_get_drvdata(pdev);
+
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+
+       return 0;
+}
+
+#define glamo_spi_suspend NULL
+#define glamo_spi_resume NULL
+
+static struct platform_driver glamo_spi_drv = {
+       .probe          = glamo_spi_probe,
+       .remove         = glamo_spi_remove,
+       .suspend        = glamo_spi_suspend,
+       .resume         = glamo_spi_resume,
+       .driver         = {
+               .name   = "glamo-lcm-spi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init glamo_spi_init(void)
+{
+       return platform_driver_register(&glamo_spi_drv);
+}
+
+static void __exit glamo_spi_exit(void)
+{
+       platform_driver_unregister(&glamo_spi_drv);
+}
+
+module_init(glamo_spi_init);
+module_exit(glamo_spi_exit);
+
+MODULE_DESCRIPTION("Smedia Glamo 336x/337x LCM serial command SPI Driver");
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>")
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/glamo/glamo-regs.h b/drivers/mfd/glamo/glamo-regs.h
new file mode 100644 (file)
index 0000000..151cd66
--- /dev/null
@@ -0,0 +1,477 @@
+#ifndef _GLAMO_REGS_H
+#define _GLAMO_REGS_H
+
+/* Smedia Glamo 336x/337x driver
+ *
+ * (C) 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+enum glamo_regster_offsets {
+       GLAMO_REGOFS_GENERIC    = 0x0000,
+       GLAMO_REGOFS_HOSTBUS    = 0x0200,
+       GLAMO_REGOFS_MEMORY     = 0x0300,
+       GLAMO_REGOFS_VIDCAP     = 0x0400,
+       GLAMO_REGOFS_ISP        = 0x0500,
+       GLAMO_REGOFS_JPEG       = 0x0800,
+       GLAMO_REGOFS_MPEG       = 0x0c00,
+       GLAMO_REGOFS_LCD        = 0x1100,
+       GLAMO_REGOFS_MMC        = 0x1400,
+       GLAMO_REGOFS_MPROC0     = 0x1500,
+       GLAMO_REGOFS_MPROC1     = 0x1580,
+       GLAMO_REGOFS_CMDQUEUE   = 0x1600,
+       GLAMO_REGOFS_RISC       = 0x1680,
+       GLAMO_REGOFS_2D         = 0x1700,
+       GLAMO_REGOFS_3D         = 0x1b00,
+       GLAMO_REGOFS_END        = 0x2400,
+};
+
+
+enum glamo_register_generic {
+       GLAMO_REG_GCONF1        = 0x0000,
+       GLAMO_REG_GCONF2        = 0x0002,
+#define        GLAMO_REG_DEVICE_ID     GLAMO_REG_GCONF2
+       GLAMO_REG_GCONF3        = 0x0004,
+#define        GLAMO_REG_REVISION_ID   GLAMO_REG_GCONF3
+       GLAMO_REG_IRQ_GEN1      = 0x0006,
+#define GLAMO_REG_IRQ_ENABLE   GLAMO_REG_IRQ_GEN1
+       GLAMO_REG_IRQ_GEN2      = 0x0008,
+#define GLAMO_REG_IRQ_SET      GLAMO_REG_IRQ_GEN2
+       GLAMO_REG_IRQ_GEN3      = 0x000a,
+#define GLAMO_REG_IRQ_CLEAR    GLAMO_REG_IRQ_GEN3
+       GLAMO_REG_IRQ_GEN4      = 0x000c,
+#define GLAMO_REG_IRQ_STATUS   GLAMO_REG_IRQ_GEN4
+       GLAMO_REG_CLOCK_HOST    = 0x0010,
+       GLAMO_REG_CLOCK_MEMORY  = 0x0012,
+       GLAMO_REG_CLOCK_LCD     = 0x0014,
+       GLAMO_REG_CLOCK_MMC     = 0x0016,
+       GLAMO_REG_CLOCK_ISP     = 0x0018,
+       GLAMO_REG_CLOCK_JPEG    = 0x001a,
+       GLAMO_REG_CLOCK_3D      = 0x001c,
+       GLAMO_REG_CLOCK_2D      = 0x001e,
+       GLAMO_REG_CLOCK_RISC1   = 0x0020,       /* 3365 only? */
+       GLAMO_REG_CLOCK_RISC2   = 0x0022,       /* 3365 only? */
+       GLAMO_REG_CLOCK_MPEG    = 0x0024,
+       GLAMO_REG_CLOCK_MPROC   = 0x0026,
+
+       GLAMO_REG_CLOCK_GEN5_1  = 0x0030,
+       GLAMO_REG_CLOCK_GEN5_2  = 0x0032,
+       GLAMO_REG_CLOCK_GEN6    = 0x0034,
+       GLAMO_REG_CLOCK_GEN7    = 0x0036,
+       GLAMO_REG_CLOCK_GEN8    = 0x0038,
+       GLAMO_REG_CLOCK_GEN9    = 0x003a,
+       GLAMO_REG_CLOCK_GEN10   = 0x003c,
+       GLAMO_REG_CLOCK_GEN11   = 0x003e,
+       GLAMO_REG_PLL_GEN1      = 0x0040,
+       GLAMO_REG_PLL_GEN2      = 0x0042,
+       GLAMO_REG_PLL_GEN3      = 0x0044,
+       GLAMO_REG_PLL_GEN4      = 0x0046,
+       GLAMO_REG_PLL_GEN5      = 0x0048,
+       GLAMO_REG_GPIO_GEN1     = 0x0050,
+       GLAMO_REG_GPIO_GEN2     = 0x0052,
+       GLAMO_REG_GPIO_GEN3     = 0x0054,
+       GLAMO_REG_GPIO_GEN4     = 0x0056,
+       GLAMO_REG_GPIO_GEN5     = 0x0058,
+       GLAMO_REG_GPIO_GEN6     = 0x005a,
+       GLAMO_REG_GPIO_GEN7     = 0x005c,
+       GLAMO_REG_GPIO_GEN8     = 0x005e,
+       GLAMO_REG_GPIO_GEN9     = 0x0060,
+       GLAMO_REG_GPIO_GEN10    = 0x0062,
+       GLAMO_REG_DFT_GEN1      = 0x0070,
+       GLAMO_REG_DFT_GEN2      = 0x0072,
+       GLAMO_REG_DFT_GEN3      = 0x0074,
+       GLAMO_REG_DFT_GEN4      = 0x0076,
+
+       GLAMO_REG_DFT_GEN5      = 0x01e0,
+       GLAMO_REG_DFT_GEN6      = 0x01f0,
+};
+
+#define GLAMO_REG_HOSTBUS(x)   (GLAMO_REGOFS_HOSTBUS-2+(x*2))
+
+#define REG_MEM(x)             (GLAMO_REGOFS_MEMORY+(x))
+#define GLAMO_REG_MEM_TIMING(x)        (GLAMO_REG_MEM_TIMING1-2+(x*2))
+
+enum glamo_register_mem {
+       GLAMO_REG_MEM_TYPE      = REG_MEM(0x00),
+       GLAMO_REG_MEM_GEN       = REG_MEM(0x02),
+       GLAMO_REG_MEM_TIMING1   = REG_MEM(0x04),
+       GLAMO_REG_MEM_TIMING2   = REG_MEM(0x06),
+       GLAMO_REG_MEM_TIMING3   = REG_MEM(0x08),
+       GLAMO_REG_MEM_TIMING4   = REG_MEM(0x0a),
+       GLAMO_REG_MEM_TIMING5   = REG_MEM(0x0c),
+       GLAMO_REG_MEM_TIMING6   = REG_MEM(0x0e),
+       GLAMO_REG_MEM_TIMING7   = REG_MEM(0x10),
+       GLAMO_REG_MEM_TIMING8   = REG_MEM(0x12),
+       GLAMO_REG_MEM_TIMING9   = REG_MEM(0x14),
+       GLAMO_REG_MEM_TIMING10  = REG_MEM(0x16),
+       GLAMO_REG_MEM_TIMING11  = REG_MEM(0x18),
+       GLAMO_REG_MEM_POWER1    = REG_MEM(0x1a),
+       GLAMO_REG_MEM_POWER2    = REG_MEM(0x1c),
+       GLAMO_REG_MEM_LCD_BUF1  = REG_MEM(0x1e),
+       GLAMO_REG_MEM_LCD_BUF2  = REG_MEM(0x20),
+       GLAMO_REG_MEM_LCD_BUF3  = REG_MEM(0x22),
+       GLAMO_REG_MEM_LCD_BUF4  = REG_MEM(0x24),
+       GLAMO_REG_MEM_BIST1     = REG_MEM(0x26),
+       GLAMO_REG_MEM_BIST2     = REG_MEM(0x28),
+       GLAMO_REG_MEM_BIST3     = REG_MEM(0x2a),
+       GLAMO_REG_MEM_BIST4     = REG_MEM(0x2c),
+       GLAMO_REG_MEM_BIST5     = REG_MEM(0x2e),
+       GLAMO_REG_MEM_MAH1      = REG_MEM(0x30),
+       GLAMO_REG_MEM_MAH2      = REG_MEM(0x32),
+       GLAMO_REG_MEM_DRAM1     = REG_MEM(0x34),
+       GLAMO_REG_MEM_DRAM2     = REG_MEM(0x36),
+       GLAMO_REG_MEM_CRC       = REG_MEM(0x38),
+};
+
+#define GLAMO_MEM_TYPE_MASK    0x03
+
+enum glamo_reg_mem_dram1 {
+       GLAMO_MEM_DRAM1_EN_SDRAM_CLK    = (1 << 11),
+       GLAMO_MEM_DRAM1_SELF_REFRESH    = (1 << 12),
+};
+
+enum glamo_reg_mem_dram2 {
+       GLAMO_MEM_DRAM2_DEEP_PWRDOWN    = (1 << 12),
+};
+
+enum glamo_irq {
+       GLAMO_IRQ_HOSTBUS       = 0x0001,
+       GLAMO_IRQ_JPEG          = 0x0002,
+       GLAMO_IRQ_MPEG          = 0x0004,
+       GLAMO_IRQ_MPROC1        = 0x0008,
+       GLAMO_IRQ_MPROC0        = 0x0010,
+       GLAMO_IRQ_CMDQUEUE      = 0x0020,
+       GLAMO_IRQ_2D            = 0x0040,
+       GLAMO_IRQ_MMC           = 0x0080,
+       GLAMO_IRQ_RISC          = 0x0100,
+};
+
+enum glamo_reg_clock_host {
+       GLAMO_CLOCK_HOST_DG_BCLK        = 0x0001,
+       GLAMO_CLOCK_HOST_DG_M0CLK       = 0x0004,
+       GLAMO_CLOCK_HOST_RESET          = 0x1000,
+};
+
+enum glamo_reg_clock_mem {
+       GLAMO_CLOCK_MEM_DG_M1CLK        = 0x0001,
+       GLAMO_CLOCK_MEM_EN_M1CLK        = 0x0002,
+       GLAMO_CLOCK_MEM_DG_MOCACLK      = 0x0004,
+       GLAMO_CLOCK_MEM_EN_MOCACLK      = 0x0008,
+       GLAMO_CLOCK_MEM_RESET           = 0x1000,
+       GLAMO_CLOCK_MOCA_RESET          = 0x2000,
+};
+
+enum glamo_reg_clock_lcd {
+       GLAMO_CLOCK_LCD_DG_DCLK         = 0x0001,
+       GLAMO_CLOCK_LCD_EN_DCLK         = 0x0002,
+       GLAMO_CLOCK_LCD_DG_DMCLK        = 0x0004,
+       GLAMO_CLOCK_LCD_EN_DMCLK        = 0x0008,
+       //
+       GLAMO_CLOCK_LCD_EN_DHCLK        = 0x0020,
+       GLAMO_CLOCK_LCD_DG_M5CLK        = 0x0040,
+       GLAMO_CLOCK_LCD_EN_M5CLK        = 0x0080,
+       GLAMO_CLOCK_LCD_RESET           = 0x1000,
+};
+
+enum glamo_reg_clock_mmc {
+       GLAMO_CLOCK_MMC_DG_TCLK         = 0x0001,
+       GLAMO_CLOCK_MMC_EN_TCLK         = 0x0002,
+       GLAMO_CLOCK_MMC_DG_M9CLK        = 0x0004,
+       GLAMO_CLOCK_MMC_EN_M9CLK        = 0x0008,
+       GLAMO_CLOCK_MMC_RESET           = 0x1000,
+};
+
+enum glamo_reg_clock_isp {
+       GLAMO_CLOCK_ISP_DG_I1CLK        = 0x0001,
+       GLAMO_CLOCK_ISP_EN_I1CLK        = 0x0002,
+       GLAMO_CLOCK_ISP_DG_CCLK         = 0x0004,
+       GLAMO_CLOCK_ISP_EN_CCLK         = 0x0008,
+       //
+       GLAMO_CLOCK_ISP_EN_SCLK         = 0x0020,
+       GLAMO_CLOCK_ISP_DG_M2CLK        = 0x0040,
+       GLAMO_CLOCK_ISP_EN_M2CLK        = 0x0080,
+       GLAMO_CLOCK_ISP_DG_M15CLK       = 0x0100,
+       GLAMO_CLOCK_ISP_EN_M15CLK       = 0x0200,
+       GLAMO_CLOCK_ISP1_RESET          = 0x1000,
+       GLAMO_CLOCK_ISP2_RESET          = 0x2000,
+};
+
+enum glamo_reg_clock_jpeg {
+       GLAMO_CLOCK_JPEG_DG_JCLK        = 0x0001,
+       GLAMO_CLOCK_JPEG_EN_JCLK        = 0x0002,
+       GLAMO_CLOCK_JPEG_DG_M3CLK       = 0x0004,
+       GLAMO_CLOCK_JPEG_EN_M3CLK       = 0x0008,
+       GLAMO_CLOCK_JPEG_RESET          = 0x1000,
+};
+
+enum glamo_reg_clock_2d {
+       GLAMO_CLOCK_2D_DG_GCLK          = 0x0001,
+       GLAMO_CLOCK_2D_EN_GCLK          = 0x0002,
+       GLAMO_CLOCK_2D_DG_M7CLK         = 0x0004,
+       GLAMO_CLOCK_2D_EN_M7CLK         = 0x0008,
+       GLAMO_CLOCK_2D_DG_M6CLK         = 0x0010,
+       GLAMO_CLOCK_2D_EN_M6CLK         = 0x0020,
+       GLAMO_CLOCK_2D_RESET            = 0x1000,
+       GLAMO_CLOCK_2D_CQ_RESET         = 0x2000,
+};
+
+enum glamo_reg_clock_3d {
+       GLAMO_CLOCK_3D_DG_ECLK          = 0x0001,
+       GLAMO_CLOCK_3D_EN_ECLK          = 0x0002,
+       GLAMO_CLOCK_3D_DG_RCLK          = 0x0004,
+       GLAMO_CLOCK_3D_EN_RCLK          = 0x0008,
+       GLAMO_CLOCK_3D_DG_M8CLK         = 0x0010,
+       GLAMO_CLOCK_3D_EN_M8CLK         = 0x0020,
+       GLAMO_CLOCK_3D_BACK_RESET       = 0x1000,
+       GLAMO_CLOCK_3D_FRONT_RESET      = 0x2000,
+};
+
+enum glamo_reg_clock_mpeg {
+       GLAMO_CLOCK_MPEG_DG_X0CLK       = 0x0001,
+       GLAMO_CLOCK_MPEG_EN_X0CLK       = 0x0002,
+       GLAMO_CLOCK_MPEG_DG_X1CLK       = 0x0004,
+       GLAMO_CLOCK_MPEG_EN_X1CLK       = 0x0008,
+       GLAMO_CLOCK_MPEG_DG_X2CLK       = 0x0010,
+       GLAMO_CLOCK_MPEG_EN_X2CLK       = 0x0020,
+       GLAMO_CLOCK_MPEG_DG_X3CLK       = 0x0040,
+       GLAMO_CLOCK_MPEG_EN_X3CLK       = 0x0080,
+       GLAMO_CLOCK_MPEG_DG_X4CLK       = 0x0100,
+       GLAMO_CLOCK_MPEG_EN_X4CLK       = 0x0200,
+       GLAMO_CLOCK_MPEG_DG_X6CLK       = 0x0400,
+       GLAMO_CLOCK_MPEG_EN_X6CLK       = 0x0800,
+       GLAMO_CLOCK_MPEG_ENC_RESET      = 0x1000,
+       GLAMO_CLOCK_MPEG_DEC_RESET      = 0x2000,
+};
+
+enum glamo_reg_clock51 {
+       GLAMO_CLOCK_GEN51_EN_DIV_MCLK   = 0x0001,
+       GLAMO_CLOCK_GEN51_EN_DIV_SCLK   = 0x0002,
+       GLAMO_CLOCK_GEN51_EN_DIV_JCLK   = 0x0004,
+       GLAMO_CLOCK_GEN51_EN_DIV_DCLK   = 0x0008,
+       GLAMO_CLOCK_GEN51_EN_DIV_DMCLK  = 0x0010,
+       GLAMO_CLOCK_GEN51_EN_DIV_DHCLK  = 0x0020,
+       GLAMO_CLOCK_GEN51_EN_DIV_GCLK   = 0x0040,
+       GLAMO_CLOCK_GEN51_EN_DIV_TCLK   = 0x0080,
+       /* FIXME: higher bits */
+};
+
+enum glamo_reg_hostbus2 {
+       GLAMO_HOSTBUS2_MMIO_EN_ISP      = 0x0001,
+       GLAMO_HOSTBUS2_MMIO_EN_JPEG     = 0x0002,
+       GLAMO_HOSTBUS2_MMIO_EN_MPEG     = 0x0004,
+       GLAMO_HOSTBUS2_MMIO_EN_LCD      = 0x0008,
+       GLAMO_HOSTBUS2_MMIO_EN_MMC      = 0x0010,
+       GLAMO_HOSTBUS2_MMIO_EN_MICROP0  = 0x0020,
+       GLAMO_HOSTBUS2_MMIO_EN_MICROP1  = 0x0040,
+       GLAMO_HOSTBUS2_MMIO_EN_CQ       = 0x0080,
+       GLAMO_HOSTBUS2_MMIO_EN_RISC     = 0x0100,
+       GLAMO_HOSTBUS2_MMIO_EN_2D       = 0x0200,
+       GLAMO_HOSTBUS2_MMIO_EN_3D       = 0x0400,
+};
+
+/* LCD Controller */
+
+#define REG_LCD(x)     (x)
+enum glamo_reg_lcd {
+       GLAMO_REG_LCD_MODE1             = REG_LCD(0x00),
+       GLAMO_REG_LCD_MODE2             = REG_LCD(0x02),
+       GLAMO_REG_LCD_MODE3             = REG_LCD(0x04),
+       GLAMO_REG_LCD_WIDTH             = REG_LCD(0x06),
+       GLAMO_REG_LCD_HEIGHT            = REG_LCD(0x08),
+       GLAMO_REG_LCD_POLARITY          = REG_LCD(0x0a),
+       GLAMO_REG_LCD_A_BASE1           = REG_LCD(0x0c),
+       GLAMO_REG_LCD_A_BASE2           = REG_LCD(0x0e),
+       GLAMO_REG_LCD_B_BASE1           = REG_LCD(0x10),
+       GLAMO_REG_LCD_B_BASE2           = REG_LCD(0x12),
+       GLAMO_REG_LCD_C_BASE1           = REG_LCD(0x14),
+       GLAMO_REG_LCD_C_BASE2           = REG_LCD(0x16),
+       GLAMO_REG_LCD_PITCH             = REG_LCD(0x18),
+       /* RES */
+       GLAMO_REG_LCD_HORIZ_TOTAL       = REG_LCD(0x1c),
+       /* RES */
+       GLAMO_REG_LCD_HORIZ_RETR_START  = REG_LCD(0x20),
+       /* RES */
+       GLAMO_REG_LCD_HORIZ_RETR_END    = REG_LCD(0x24),
+       /* RES */
+       GLAMO_REG_LCD_HORIZ_DISP_START  = REG_LCD(0x28),
+       /* RES */
+       GLAMO_REG_LCD_HORIZ_DISP_END    = REG_LCD(0x2c),
+       /* RES */
+       GLAMO_REG_LCD_VERT_TOTAL        = REG_LCD(0x30),
+       /* RES */
+       GLAMO_REG_LCD_VERT_RETR_START   = REG_LCD(0x34),
+       /* RES */
+       GLAMO_REG_LCD_VERT_RETR_END     = REG_LCD(0x38),
+       /* RES */
+       GLAMO_REG_LCD_VERT_DISP_START   = REG_LCD(0x3c),
+       /* RES */
+       GLAMO_REG_LCD_VERT_DISP_END     = REG_LCD(0x40),
+       /* RES */
+       GLAMO_REG_LCD_POL               = REG_LCD(0x44),
+       GLAMO_REG_LCD_DATA_START        = REG_LCD(0x46),
+       GLAMO_REG_LCD_FRATE_CONTRO      = REG_LCD(0x48),
+       GLAMO_REG_LCD_DATA_CMD_HDR      = REG_LCD(0x4a),
+       GLAMO_REG_LCD_SP_START          = REG_LCD(0x4c),
+       GLAMO_REG_LCD_SP_END            = REG_LCD(0x4e),
+       GLAMO_REG_LCD_CURSOR_BASE1      = REG_LCD(0x50),
+       GLAMO_REG_LCD_CURSOR_BASE2      = REG_LCD(0x52),
+       GLAMO_REG_LCD_CURSOR_PITCH      = REG_LCD(0x54),
+       GLAMO_REG_LCD_CURSOR_X_SIZE     = REG_LCD(0x56),
+       GLAMO_REG_LCD_CURSOR_Y_SIZE     = REG_LCD(0x58),
+       GLAMO_REG_LCD_CURSOR_X_POS      = REG_LCD(0x5a),
+       GLAMO_REG_LCD_CURSOR_Y_POS      = REG_LCD(0x5c),
+       GLAMO_REG_LCD_CURSOR_PRESET     = REG_LCD(0x5e),
+       GLAMO_REG_LCD_CURSOR_FG_COLOR   = REG_LCD(0x60),
+       /* RES */
+       GLAMO_REG_LCD_CURSOR_BG_COLOR   = REG_LCD(0x64),
+       /* RES */
+       GLAMO_REG_LCD_CURSOR_DST_COLOR  = REG_LCD(0x68),
+       /* RES */
+       GLAMO_REG_LCD_STATUS1           = REG_LCD(0x80),
+       GLAMO_REG_LCD_STATUS2           = REG_LCD(0x82),
+       GLAMO_REG_LCD_STATUS3           = REG_LCD(0x84),
+       GLAMO_REG_LCD_STATUS4           = REG_LCD(0x86),
+       /* RES */
+       GLAMO_REG_LCD_COMMAND1          = REG_LCD(0xa0),
+       GLAMO_REG_LCD_COMMAND2          = REG_LCD(0xa2),
+       /* RES */
+       GLAMO_REG_LCD_WFORM_DELAY1      = REG_LCD(0xb0),
+       GLAMO_REG_LCD_WFORM_DELAY2      = REG_LCD(0xb2),
+       /* RES */
+       GLAMO_REG_LCD_GAMMA_CORR        = REG_LCD(0x100),
+       /* RES */
+       GLAMO_REG_LCD_GAMMA_R_ENTRY01   = REG_LCD(0x110),
+       GLAMO_REG_LCD_GAMMA_R_ENTRY23   = REG_LCD(0x112),
+       GLAMO_REG_LCD_GAMMA_R_ENTRY45   = REG_LCD(0x114),
+       GLAMO_REG_LCD_GAMMA_R_ENTRY67   = REG_LCD(0x116),
+       GLAMO_REG_LCD_GAMMA_R_ENTRY8    = REG_LCD(0x118),
+       /* RES */
+       GLAMO_REG_LCD_GAMMA_G_ENTRY01   = REG_LCD(0x130),
+       GLAMO_REG_LCD_GAMMA_G_ENTRY23   = REG_LCD(0x132),
+       GLAMO_REG_LCD_GAMMA_G_ENTRY45   = REG_LCD(0x134),
+       GLAMO_REG_LCD_GAMMA_G_ENTRY67   = REG_LCD(0x136),
+       GLAMO_REG_LCD_GAMMA_G_ENTRY8    = REG_LCD(0x138),
+       /* RES */
+       GLAMO_REG_LCD_GAMMA_B_ENTRY01   = REG_LCD(0x150),
+       GLAMO_REG_LCD_GAMMA_B_ENTRY23   = REG_LCD(0x152),
+       GLAMO_REG_LCD_GAMMA_B_ENTRY45   = REG_LCD(0x154),
+       GLAMO_REG_LCD_GAMMA_B_ENTRY67   = REG_LCD(0x156),
+       GLAMO_REG_LCD_GAMMA_B_ENTRY8    = REG_LCD(0x158),
+       /* RES */
+       GLAMO_REG_LCD_SRAM_DRIVING1     = REG_LCD(0x160),
+       GLAMO_REG_LCD_SRAM_DRIVING2     = REG_LCD(0x162),
+       GLAMO_REG_LCD_SRAM_DRIVING3     = REG_LCD(0x164),
+};
+
+enum glamo_reg_lcd_mode1 {
+       GLAMO_LCD_MODE1_PWRSAVE         = 0x0001,
+       GLAMO_LCD_MODE1_PARTIAL_PRT     = 0x0002,
+       GLAMO_LCD_MODE1_HWFLIP          = 0x0004,
+       GLAMO_LCD_MODE1_LCD2            = 0x0008,
+       /* RES */
+       GLAMO_LCD_MODE1_PARTIAL_MODE    = 0x0020,
+       GLAMO_LCD_MODE1_CURSOR_DSTCOLOR = 0x0040,
+       GLAMO_LCD_MODE1_PARTIAL_ENABLE  = 0x0080,
+       GLAMO_LCD_MODE1_TVCLK_IN_ENABLE = 0x0100,
+       GLAMO_LCD_MODE1_HSYNC_HIGH_ACT  = 0x0200,
+       GLAMO_LCD_MODE1_VSYNC_HIGH_ACT  = 0x0400,
+       GLAMO_LCD_MODE1_HSYNC_FLIP      = 0x0800,
+       GLAMO_LCD_MODE1_GAMMA_COR_EN    = 0x1000,
+       GLAMO_LCD_MODE1_DITHER_EN       = 0x2000,
+       GLAMO_LCD_MODE1_CURSOR_EN       = 0x4000,
+       GLAMO_LCD_MODE1_ROTATE_EN       = 0x8000,
+};
+
+enum glamo_reg_lcd_mode2 {
+       GLAMO_LCD_MODE2_CRC_CHECK_EN    = 0x0001,
+       GLAMO_LCD_MODE2_DCMD_PER_LINE   = 0x0002,
+       GLAMO_LCD_MODE2_NOUSE_BDEF      = 0x0004,
+       GLAMO_LCD_MODE2_OUT_POS_MODE    = 0x0008,
+       GLAMO_LCD_MODE2_FRATE_CTRL_EN   = 0x0010,
+       GLAMO_LCD_MODE2_SINGLE_BUFFER   = 0x0020,
+       GLAMO_LCD_MODE2_SER_LSB_TO_MSB  = 0x0040,
+       /* FIXME */
+};
+
+enum glamo_reg_lcd_mode3 {
+       /* LCD color source data format */
+       GLAMO_LCD_SRC_RGB565            = 0x0000,
+       GLAMO_LCD_SRC_ARGB1555          = 0x4000,
+       GLAMO_LCD_SRC_ARGB4444          = 0x8000,
+       /* interface type */
+       GLAMO_LCD_MODE3_LCD             = 0x1000,
+       GLAMO_LCD_MODE3_RGB             = 0x0800,
+       GLAMO_LCD_MODE3_CPU             = 0x0000,
+       /* mode */
+       GLAMO_LCD_MODE3_RGB332          = 0x0000,
+       GLAMO_LCD_MODE3_RGB444          = 0x0100,
+       GLAMO_LCD_MODE3_RGB565          = 0x0200,
+       GLAMO_LCD_MODE3_RGB666          = 0x0300,
+       /* depth */
+       GLAMO_LCD_MODE3_6BITS           = 0x0000,
+       GLAMO_LCD_MODE3_8BITS           = 0x0010,
+       GLAMO_LCD_MODE3_9BITS           = 0x0020,
+       GLAMO_LCD_MODE3_16BITS          = 0x0030,
+       GLAMO_LCD_MODE3_18BITS          = 0x0040,
+};
+
+enum glamo_lcd_rot_mode {
+        GLAMO_LCD_ROT_MODE_0            = 0x0000,
+        GLAMO_LCD_ROT_MODE_180          = 0x2000,
+        GLAMO_LCD_ROT_MODE_MIRROR       = 0x4000,
+        GLAMO_LCD_ROT_MODE_FLIP         = 0x6000,
+        GLAMO_LCD_ROT_MODE_90           = 0x8000,
+        GLAMO_LCD_ROT_MODE_270          = 0xa000,
+};
+#define GLAMO_LCD_ROT_MODE_MASK         0xe000
+
+enum glamo_lcd_cmd_type {
+       GLAMO_LCD_CMD_TYPE_DISP         = 0x0000,
+       GLAMO_LCD_CMD_TYPE_PARALLEL     = 0x4000,
+       GLAMO_LCD_CMD_TYPE_SERIAL       = 0x8000,
+       GLAMO_LCD_CMD_TYPE_SERIAL_DIRECT= 0xc000,
+};
+#define GLAMO_LCD_CMD_TYPE_MASK                0xc000
+
+enum glamo_lcd_cmds {
+       GLAMO_LCD_CMD_DATA_DISP_FIRE    = 0x00,
+       GLAMO_LCD_CMD_DATA_DISP_SYNC    = 0x01,         /* RGB only */
+       /* switch to command mode, no display */
+       GLAMO_LCD_CMD_DATA_FIRE_NO_DISP = 0x02,
+       /* display until VSYNC, switch to command */
+       GLAMO_LCD_CMD_DATA_FIRE_VSYNC   = 0x11,
+       /* display until HSYNC, switch to command */
+       GLAMO_LCD_CMD_DATA_FIRE_HSYNC   = 0x12,
+       /* display until VSYNC, 1 black frame, VSYNC, switch to command */
+       GLAMO_LCD_CMD_DATA_FIRE_VSYNC_B = 0x13,
+       /* don't care about display and switch to command */
+       GLAMO_LCD_CMD_DATA_FIRE_FREE    = 0x14,         /* RGB only */
+       /* don't care about display, keep data display but disable data,
+        * and switch to command */
+       GLAMO_LCD_CMD_DATA_FIRE_FREE_D  = 0x15,         /* RGB only */
+};
+
+enum glamo_core_revisions {
+       GLAMO_CORE_REV_A0               = 0x0000,
+       GLAMO_CORE_REV_A1               = 0x0001,
+       GLAMO_CORE_REV_A2               = 0x0002,
+       GLAMO_CORE_REV_A3               = 0x0003,
+};
+
+#endif /* _GLAMO_REGS_H */
diff --git a/drivers/mfd/glamo/glamo-spi-gpio.c b/drivers/mfd/glamo/glamo-spi-gpio.c
new file mode 100644 (file)
index 0000000..73926bd
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * Smedia Glamo GPIO based SPI driver
+ *
+ * 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 driver currently only implements a minimum subset of the hardware
+ * features, esp. those features that are required to drive the jbt6k74
+ * LCM controller asic in the TD028TTEC1 LCM.
+ *
+*/
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/glamo.h>
+
+#include <linux/glamofb.h>
+
+#include <asm/hardware.h>
+
+#include "glamo-core.h"
+#include "glamo-regs.h"
+
+struct glamo_spigpio {
+       struct spi_bitbang              bitbang;
+       struct spi_master               *master;
+       struct glamo_spigpio_info       *info;
+       struct glamo_core               *glamo;
+};
+
+static inline struct glamo_spigpio *to_sg(struct spi_device *spi)
+{
+       return spi->controller_data;
+}
+
+static inline void setsck(struct spi_device *dev, int on)
+{
+       struct glamo_spigpio *sg = to_sg(dev);
+       glamo_gpio_setpin(sg->glamo, sg->info->pin_clk, on ? 1 : 0);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+       struct glamo_spigpio *sg = to_sg(dev);
+       glamo_gpio_setpin(sg->glamo, sg->info->pin_mosi, on ? 1 : 0);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+       struct glamo_spigpio *sg = to_sg(dev);
+       if (sg->info->pin_miso)
+               return glamo_gpio_getpin(sg->glamo, sg->info->pin_miso) ? 1 : 0;
+       else
+               return 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 glamo_spigpio_txrx_mode0(struct spi_device *spi,
+                                   unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 glamo_spigpio_txrx_mode1(struct spi_device *spi,
+                                   unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 glamo_spigpio_txrx_mode2(struct spi_device *spi,
+                                   unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 glamo_spigpio_txrx_mode3(struct spi_device *spi,
+                                   unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+
+#if 0
+static int glamo_spigpio_setupxfer(struct spi_device *spi,
+                                  struct spi_transfer *t)
+{
+       struct glamo_spi *gs = to_sg(spi);
+       unsigned int bpw;
+
+       bpw = t ? t->bits_per_word : spi->bits_per_word;
+
+       if (bpw != 9 && bpw != 8) {
+               dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#endif
+
+static void glamo_spigpio_chipsel(struct spi_device *spi, int value)
+{
+       struct glamo_spigpio *gs = to_sg(spi);
+#if 0
+       dev_dbg(&spi->dev, "chipsel %d: spi=%p, gs=%p, info=%p, handle=%p\n",
+               value, spi, gs, gs->info, gs->info->glamo);
+#endif
+       glamo_gpio_setpin(gs->glamo, gs->info->pin_cs, value ? 0 : 1);
+}
+
+
+static int glamo_spigpio_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct glamo_spigpio *sp;
+       int ret;
+       int i;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct glamo_spigpio));
+       if (master == NULL) {
+               dev_err(&pdev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sp = spi_master_get_devdata(master);
+       platform_set_drvdata(pdev, sp);
+       sp->info = pdev->dev.platform_data;
+       if (!sp->info) {
+               dev_err(&pdev->dev, "can't operate without platform data\n");
+               ret = -EIO;
+               goto err_no_pdev;
+       }
+
+       master->num_chipselect = 1;
+       master->bus_num = 2; /* FIXME: use dynamic number */
+
+       sp->master = spi_master_get(master);
+       sp->glamo = sp->info->glamo;
+
+       sp->bitbang.master = sp->master;
+       sp->bitbang.chipselect = glamo_spigpio_chipsel;
+       sp->bitbang.txrx_word[SPI_MODE_0] = glamo_spigpio_txrx_mode0;
+       sp->bitbang.txrx_word[SPI_MODE_1] = glamo_spigpio_txrx_mode1;
+       sp->bitbang.txrx_word[SPI_MODE_2] = glamo_spigpio_txrx_mode2;
+       sp->bitbang.txrx_word[SPI_MODE_3] = glamo_spigpio_txrx_mode3;
+
+       /* set state of spi pins */
+       glamo_gpio_setpin(sp->glamo, sp->info->pin_clk, 0);
+       glamo_gpio_setpin(sp->glamo, sp->info->pin_mosi, 0);
+       glamo_gpio_setpin(sp->glamo, sp->info->pin_cs, 1);
+
+       glamo_gpio_cfgpin(sp->glamo, sp->info->pin_clk);
+       glamo_gpio_cfgpin(sp->glamo, sp->info->pin_mosi);
+       glamo_gpio_cfgpin(sp->glamo, sp->info->pin_cs);
+       if (sp->info->pin_miso)
+               glamo_gpio_cfgpin(sp->glamo, sp->info->pin_miso);
+
+       /* bring the LCM panel out of reset if it isn't already */
+
+       glamo_gpio_setpin(sp->glamo, GLAMO_GPIO4, 1);
+       glamo_gpio_cfgpin(sp->glamo, GLAMO_GPIO4_OUTPUT);
+       msleep(90);
+
+#if 0
+       sp->dev = &pdev->dev;
+
+       sp->bitbang.setup_transfer = glamo_spi_setupxfer;
+       sp->bitbang.txrx_bufs = glamo_spi_txrx;
+       sp->bitbang.master->setup = glamo_spi_setup;
+#endif
+
+       ret = spi_bitbang_start(&sp->bitbang);
+       if (ret)
+               goto err_no_bitbang;
+
+       /* register the chips to go with the board */
+
+       for (i = 0; i < sp->info->board_size; i++) {
+               dev_info(&pdev->dev, "registering %p: %s\n",
+                        &sp->info->board_info[i],
+                        sp->info->board_info[i].modalias);
+
+               sp->info->board_info[i].controller_data = sp;
+               spi_new_device(master, sp->info->board_info + i);
+       }
+
+       return 0;
+
+err_no_bitbang:
+       platform_set_drvdata(pdev, NULL);
+err_no_pdev:
+       spi_master_put(sp->bitbang.master);
+err:
+       return ret;
+
+}
+
+static int glamo_spigpio_remove(struct platform_device *pdev)
+{
+       struct glamo_spigpio *sp = platform_get_drvdata(pdev);
+
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+
+       return 0;
+}
+
+#define glamo_spigpio_suspend NULL
+#define glamo_spigpio_resume NULL
+
+static struct platform_driver glamo_spi_drv = {
+       .probe          = glamo_spigpio_probe,
+       .remove         = glamo_spigpio_remove,
+       .suspend        = glamo_spigpio_suspend,
+       .resume         = glamo_spigpio_resume,
+       .driver         = {
+               .name   = "glamo-spi-gpio",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init glamo_spi_init(void)
+{
+       return platform_driver_register(&glamo_spi_drv);
+}
+
+static void __exit glamo_spi_exit(void)
+{
+       platform_driver_unregister(&glamo_spi_drv);
+}
+
+module_init(glamo_spi_init);
+module_exit(glamo_spi_exit);
+
+MODULE_DESCRIPTION("Smedia Glamo 336x/337x LCM serial command SPI Driver");
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>")
+MODULE_LICENSE("GPL");
diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
new file mode 100644 (file)
index 0000000..ea945ea
--- /dev/null
@@ -0,0 +1,194 @@
+/* linux/include/asm-arm/arch-s3c2410/irqs.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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.
+*/
+
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H __FILE__
+
+#ifndef __ASM_ARM_IRQ_H
+#error "Do not include this directly, instead #include <asm/irq.h>"
+#endif
+
+/* we keep the first set of CPU IRQs out of the range of
+ * the ISA space, so that the PC104 has them to itself
+ * and we don't end up having to do horrible things to the
+ * standard ISA drivers....
+ */
+
+#define S3C2410_CPUIRQ_OFFSET   (16)
+
+#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
+
+/* main cpu interrupts */
+#define IRQ_EINT0      S3C2410_IRQ(0)      /* 16 */
+#define IRQ_EINT1      S3C2410_IRQ(1)
+#define IRQ_EINT2      S3C2410_IRQ(2)
+#define IRQ_EINT3      S3C2410_IRQ(3)
+#define IRQ_EINT4t7    S3C2410_IRQ(4)      /* 20 */
+#define IRQ_EINT8t23   S3C2410_IRQ(5)
+#define IRQ_RESERVED6  S3C2410_IRQ(6)      /* for s3c2410 */
+#define IRQ_CAM        S3C2410_IRQ(6)      /* for s3c2440,s3c2443 */
+#define IRQ_BATT_FLT   S3C2410_IRQ(7)
+#define IRQ_TICK       S3C2410_IRQ(8)      /* 24 */
+#define IRQ_WDT               S3C2410_IRQ(9)       /* WDT/AC97 for s3c2443 */
+#define IRQ_TIMER0     S3C2410_IRQ(10)
+#define IRQ_TIMER1     S3C2410_IRQ(11)
+#define IRQ_TIMER2     S3C2410_IRQ(12)
+#define IRQ_TIMER3     S3C2410_IRQ(13)
+#define IRQ_TIMER4     S3C2410_IRQ(14)
+#define IRQ_UART2      S3C2410_IRQ(15)
+#define IRQ_LCD               S3C2410_IRQ(16)      /* 32 */
+#define IRQ_DMA0       S3C2410_IRQ(17)     /* IRQ_DMA for s3c2443 */
+#define IRQ_DMA1       S3C2410_IRQ(18)
+#define IRQ_DMA2       S3C2410_IRQ(19)
+#define IRQ_DMA3       S3C2410_IRQ(20)
+#define IRQ_SDI               S3C2410_IRQ(21)
+#define IRQ_SPI0       S3C2410_IRQ(22)
+#define IRQ_UART1      S3C2410_IRQ(23)
+#define IRQ_RESERVED24 S3C2410_IRQ(24)     /* 40 */
+#define IRQ_NFCON      S3C2410_IRQ(24)     /* for s3c2440 */
+#define IRQ_USBD       S3C2410_IRQ(25)
+#define IRQ_USBH       S3C2410_IRQ(26)
+#define IRQ_IIC               S3C2410_IRQ(27)
+#define IRQ_UART0      S3C2410_IRQ(28)     /* 44 */
+#define IRQ_SPI1       S3C2410_IRQ(29)
+#define IRQ_RTC               S3C2410_IRQ(30)
+#define IRQ_ADCPARENT  S3C2410_IRQ(31)
+
+/* interrupts generated from the external interrupts sources */
+#define IRQ_EINT4      S3C2410_IRQ(32)    /* 48 */
+#define IRQ_EINT5      S3C2410_IRQ(33)
+#define IRQ_EINT6      S3C2410_IRQ(34)
+#define IRQ_EINT7      S3C2410_IRQ(35)
+#define IRQ_EINT8      S3C2410_IRQ(36)
+#define IRQ_EINT9      S3C2410_IRQ(37)
+#define IRQ_EINT10     S3C2410_IRQ(38)
+#define IRQ_EINT11     S3C2410_IRQ(39)
+#define IRQ_EINT12     S3C2410_IRQ(40)
+#define IRQ_EINT13     S3C2410_IRQ(41)
+#define IRQ_EINT14     S3C2410_IRQ(42)
+#define IRQ_EINT15     S3C2410_IRQ(43)
+#define IRQ_EINT16     S3C2410_IRQ(44)
+#define IRQ_EINT17     S3C2410_IRQ(45)
+#define IRQ_EINT18     S3C2410_IRQ(46)
+#define IRQ_EINT19     S3C2410_IRQ(47)
+#define IRQ_EINT20     S3C2410_IRQ(48)    /* 64 */
+#define IRQ_EINT21     S3C2410_IRQ(49)
+#define IRQ_EINT22     S3C2410_IRQ(50)
+#define IRQ_EINT23     S3C2410_IRQ(51)
+
+
+#define IRQ_EINT(x)    (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x)))
+
+#define IRQ_LCD_FIFO   S3C2410_IRQ(52)
+#define IRQ_LCD_FRAME  S3C2410_IRQ(53)
+
+/* IRQs for the interal UARTs, and ADC
+ * these need to be ordered in number of appearance in the
+ * SUBSRC mask register
+*/
+
+#define S3C2410_IRQSUB(x)      S3C2410_IRQ((x)+54)
+
+#define IRQ_S3CUART_RX0                S3C2410_IRQSUB(0)       /* 70 */
+#define IRQ_S3CUART_TX0                S3C2410_IRQSUB(1)
+#define IRQ_S3CUART_ERR0       S3C2410_IRQSUB(2)
+
+#define IRQ_S3CUART_RX1                S3C2410_IRQSUB(3)       /* 73 */
+#define IRQ_S3CUART_TX1                S3C2410_IRQSUB(4)
+#define IRQ_S3CUART_ERR1       S3C2410_IRQSUB(5)
+
+#define IRQ_S3CUART_RX2                S3C2410_IRQSUB(6)       /* 76 */
+#define IRQ_S3CUART_TX2                S3C2410_IRQSUB(7)
+#define IRQ_S3CUART_ERR2       S3C2410_IRQSUB(8)
+
+#define IRQ_TC                 S3C2410_IRQSUB(9)
+#define IRQ_ADC                        S3C2410_IRQSUB(10)
+
+/* extra irqs for s3c2412 */
+
+#define IRQ_S3C2412_CFSDI      S3C2410_IRQ(21)
+
+#define IRQ_S3C2412_SDI                S3C2410_IRQSUB(13)
+#define IRQ_S3C2412_CF         S3C2410_IRQSUB(14)
+
+/* extra irqs for s3c2440 */
+
+#define IRQ_S3C2440_CAM_C      S3C2410_IRQSUB(11)      /* S3C2443 too */
+#define IRQ_S3C2440_CAM_P      S3C2410_IRQSUB(12)      /* S3C2443 too */
+#define IRQ_S3C2440_WDT                S3C2410_IRQSUB(13)
+#define IRQ_S3C2440_AC97       S3C2410_IRQSUB(14)
+
+/* irqs for s3c2443 */
+
+#define IRQ_S3C2443_DMA                S3C2410_IRQ(17)         /* IRQ_DMA1 */
+#define IRQ_S3C2443_UART3      S3C2410_IRQ(18)         /* IRQ_DMA2 */
+#define IRQ_S3C2443_CFCON      S3C2410_IRQ(19)         /* IRQ_DMA3 */
+#define IRQ_S3C2443_HSMMC      S3C2410_IRQ(20)         /* IRQ_SDI */
+#define IRQ_S3C2443_NAND       S3C2410_IRQ(24)         /* reserved */
+
+#define IRQ_S3C2443_LCD1       S3C2410_IRQSUB(14)
+#define IRQ_S3C2443_LCD2       S3C2410_IRQSUB(15)
+#define IRQ_S3C2443_LCD3       S3C2410_IRQSUB(16)
+#define IRQ_S3C2443_LCD4       S3C2410_IRQSUB(17)
+
+#define IRQ_S3C2443_DMA0       S3C2410_IRQSUB(18)
+#define IRQ_S3C2443_DMA1       S3C2410_IRQSUB(19)
+#define IRQ_S3C2443_DMA2       S3C2410_IRQSUB(20)
+#define IRQ_S3C2443_DMA3       S3C2410_IRQSUB(21)
+#define IRQ_S3C2443_DMA4       S3C2410_IRQSUB(22)
+#define IRQ_S3C2443_DMA5       S3C2410_IRQSUB(23)
+
+/* UART3 */
+#define IRQ_S3C2443_RX3                S3C2410_IRQSUB(24)
+#define IRQ_S3C2443_TX3                S3C2410_IRQSUB(25)
+#define IRQ_S3C2443_ERR3       S3C2410_IRQSUB(26)
+
+#define IRQ_S3C2443_WDT                S3C2410_IRQSUB(27)
+#define IRQ_S3C2443_AC97       S3C2410_IRQSUB(28)
+
+#ifdef CONFIG_CPU_S3C2443
+#define _NR_IRQS (IRQ_S3C2443_AC97+1)
+#else
+#define _NR_IRQS (IRQ_S3C2440_AC97+1)
+#endif
+
+/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
+#define FIQ_START              IRQ_EINT0
+
+/*
+ * The next 16 interrupts are for board specific purposes.  Since
+ * the kernel can only run on one machine at a time, we can re-use
+ * these.  If you need more, increase IRQ_BOARD_END, but keep it
+ * within sensible limits.
+ */
+#define IRQ_BOARD_START                _NR_IRQS
+#define IRQ_BOARD_END          (_NR_IRQS + 10)
+
+#if defined(CONFIG_MACH_NEO1973_GTA02)
+#define NR_IRQS                        (IRQ_BOARD_END)
+#else
+#define NR_IRQS                        (IRQ_BOARD_START)
+#endif
+
+/* Neo1973 GTA02 interrupts */
+#define NEO1973_GTA02_IRQ(x)   (IRQ_BOARD_START + (x))
+#define IRQ_GLAMO(x)           NEO1973_GTA02_IRQ(x)
+#define IRQ_GLAMO_HOSTBUS      IRQ_GLAMO(0)
+#define IRQ_GLAMO_JPEG         IRQ_GLAMO(1)
+#define IRQ_GLAMO_MPEG         IRQ_GLAMO(2)
+#define IRQ_GLAMO_MPROC1       IRQ_GLAMO(3)
+#define IRQ_GLAMO_MPROC0       IRQ_GLAMO(4)
+#define IRQ_GLAMO_CMDQUEUE     IRQ_GLAMO(5)
+#define IRQ_GLAMO_2D           IRQ_GLAMO(6)
+#define IRQ_GLAMO_MMC          IRQ_GLAMO(7)
+#define IRQ_GLAMO_RISC         IRQ_GLAMO(8)
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/include/linux/glamo-gpio.h b/include/linux/glamo-gpio.h
new file mode 100644 (file)
index 0000000..d00f7e9
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef __GLAMO_GPIO_H
+#define __GLAMO_GPIO_H
+
+struct glamo_core;
+
+#define GLAMO_GPIO_BANKA       0x0000
+#define GLAMO_GPIO_BANKB       0x1000
+#define GLAMO_GPIO_BANKC       0x2000
+#define GLAMO_GPIO_BANKD       0x3000
+
+#define GLAMO_GPIONO(bank, pin)        ((bank & 0xf000) | ((pin & 0xf) << 8))
+
+#define GLAMO_GPIO_F_IN                0x0010
+#define GLAMO_GPIO_F_OUT       0x0020
+#define GLAMO_GPIO_F_FUNC      0x0030
+
+#define GLAMO_GPIO0            GLAMO_GPIONO(GLAMO_GPIO_BANKA, 0)
+#define GLAMO_GPIO0_INPUT      (GLAMO_GPIO0 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO0_OUTPUT     (GLAMO_GPIO0 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO0_HA20       (GLAMO_GPIO0 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO1            GLAMO_GPIONO(GLAMO_GPIO_BANKA, 1)
+#define GLAMO_GPIO1_INPUT      (GLAMO_GPIO1 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO1_OUTPUT     (GLAMO_GPIO1 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO1_HA21       (GLAMO_GPIO1 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO2            GLAMO_GPIONO(GLAMO_GPIO_BANKA, 2)
+#define GLAMO_GPIO2_INPUT      (GLAMO_GPIO2 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO2_OUTPUT     (GLAMO_GPIO2 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO2_HA22       (GLAMO_GPIO2 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO3            GLAMO_GPIONO(GLAMO_GPIO_BANKA, 3)
+#define GLAMO_GPIO3_INPUT      (GLAMO_GPIO3 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO3_OUTPUT     (GLAMO_GPIO3 | GLAMO_GPIO_F_OUT)
+#define        GLAMO_GPIO3_HA23        (GLAMO_GPIO3 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO4            GLAMO_GPIONO(GLAMO_GPIO_BANKB, 0)
+#define GLAMO_GPIO4_INPUT      (GLAMO_GPIO4 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO4_OUTPUT     (GLAMO_GPIO4 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO4_nLCS0      (GLAMO_GPIO4 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO5            GLAMO_GPIONO(GLAMO_GPIO_BANKB, 1)
+#define GLAMO_GPIO5_INPUT      (GLAMO_GPIO5 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO5_OUTPUT     (GLAMO_GPIO5 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO5_nLCS1      (GLAMO_GPIO5 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO6            GLAMO_GPIONO(GLAMO_GPIO_BANKB, 2)
+#define GLAMO_GPIO6_INPUT      (GLAMO_GPIO6 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO6_OUTPUT     (GLAMO_GPIO6 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO6_LDCLK      (GLAMO_GPIO6 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO7            GLAMO_GPIONO(GLAMO_GPIO_BANKB, 3)
+#define GLAMO_GPIO7_INPUT      (GLAMO_GPIO7 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO7_OUTPUT     (GLAMO_GPIO7 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO7_nLDE       (GLAMO_GPIO7 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO8            GLAMO_GPIONO(GLAMO_GPIO_BANKC, 0)
+#define GLAMO_GPIO8_INPUT      (GLAMO_GPIO8 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO8_OUTPUT     (GLAMO_GPIO8 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO8_LD16       (GLAMO_GPIO8 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO9            GLAMO_GPIONO(GLAMO_GPIO_BANKC, 1)
+#define GLAMO_GPIO9_INPUT      (GLAMO_GPIO9 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO9_OUTPUT     (GLAMO_GPIO9 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO9_LD17       (GLAMO_GPIO9 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO10           GLAMO_GPIONO(GLAMO_GPIO_BANKC, 2)
+#define GLAMO_GPIO10_INPUT     (GLAMO_GPIO10 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO10_OUTPUT    (GLAMO_GPIO10 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO10_LSCK      (GLAMO_GPIO10 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO11           GLAMO_GPIONO(GLAMO_GPIO_BANKC, 3)
+#define GLAMO_GPIO11_INPUT     (GLAMO_GPIO11 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO11_OUTPUT    (GLAMO_GPIO11 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO11_LSDA      (GLAMO_GPIO11 | GLAMO_GPIO_F_FUNC)
+
+#define GLAMO_GPIO12           GLAMO_GPIONO(GLAMO_GPIO_BANKD, 0)
+#define GLAMO_GPIO12_INPUT     (GLAMO_GPIO12 | GLAMO_GPIO_F_IN)
+#define GLAMO_GPIO12_OUTPUT    (GLAMO_GPIO12 | GLAMO_GPIO_F_OUT)
+#define GLAMO_GPIO12_LSA0      (GLAMO_GPIO12 | GLAMO_GPIO_F_FUNC)
+
+
+#define REG_OF_GPIO(gpio)      (((gpio & 0xf000) >> 12)*2 \
+                                               + GLAMO_REG_GPIO_GEN1)
+#define NUM_OF_GPIO(gpio)      ((gpio & 0x0f00) >> 8)
+#define GPIO_OUT_BIT(gpio)     (1 << (NUM_OF_GPIO(gpio) + 0))
+#define OUTPUT_BIT(gpio)       (1 << (NUM_OF_GPIO(gpio) + 4))
+#define INPUT_BIT(gpio)                (1 << (NUM_OF_GPIO(gpio) + 8))
+#define FUNC_BIT(gpio)         (1 << (NUM_OF_GPIO(gpio) + 12))
+
+void glamo_gpio_setpin(struct glamo_core *glamo, unsigned int pin,
+                      unsigned int value);
+
+int glamo_gpio_getpin(struct glamo_core *glamo, unsigned int pin);
+
+void glamo_gpio_cfgpin(struct glamo_core *glamo, unsigned int pinfunc);
+
+
+#endif /* _GLAMO_GPIO */
diff --git a/include/linux/glamofb.h b/include/linux/glamofb.h
new file mode 100644 (file)
index 0000000..24742a2
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _LINUX_GLAMOFB_H
+#define _LINUX_GLAMOFB_H
+
+#include <linux/spi/glamo.h>
+
+struct glamofb_val {
+       unsigned int defval;
+       unsigned int min;
+       unsigned int max;
+};
+
+struct glamo_core;
+
+struct glamofb_platform_data {
+       int width, height;
+       int pixclock;
+       int left_margin, right_margin;
+       int upper_margin, lower_margin;
+       int hsync_len, vsync_len;
+       int fb_mem_size;
+
+       struct glamofb_val xres;
+       struct glamofb_val yres;
+       struct glamofb_val bpp;
+
+       struct glamo_spi_info *spi_info;
+       struct glamo_spigpio_info *spigpio_info;
+       struct glamo_core *glamo;
+
+       /* glamo mmc platform specific info */
+       void            (*glamo_set_mci_power)(unsigned char power_mode,
+                                    unsigned short vdd);
+       int             (*glamo_irq_is_wired)(void);
+};
+
+void glamofb_cmd_mode(struct glamofb_handle *gfb, int on);
+int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val);
+
+#endif
diff --git a/include/linux/spi/glamo.h b/include/linux/spi/glamo.h
new file mode 100644 (file)
index 0000000..86419ea
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __GLAMO_SPI_H
+#define __GLAMO_SPI_H
+
+#include <linux/glamo-gpio.h>
+
+struct spi_board_info;
+struct glamofb_handle;
+struct glamo_core;
+
+struct glamo_spi_info {
+       unsigned long           board_size;
+       struct spi_board_info   *board_info;
+       struct glamofb_handle   *glamofb_handle;
+};
+
+struct glamo_spigpio_info {
+       unsigned int            pin_clk;
+       unsigned int            pin_mosi;
+       unsigned int            pin_miso;
+       unsigned int            pin_cs;
+
+       unsigned int            board_size;
+       struct spi_board_info   *board_info;
+       struct glamo_core       *glamo;
+};
+
+
+#endif