[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

s3c24xx kernel flavour



Hi,
I am working on a s3c24xx kernel flavour[1], mainly for the Neo
FreeRunner (FR).

It is work in progress, but I can already install Debian on the FR's µSD
using a network-console Debian Installer image.

However, beside the flavour-specific config file, it needs a few patches
to be useful: 

* s3c2410_udc-2440_dual_packet-workaround.patch:
    Fix the lag in USB gadgets
* glamo.patch:
    Add the glamo driver, required to have µSD (and graphics, but another driver is missing, too) support
* glamo-device.patch:
    The platform-specific code for the glamo device on the Freerunner
* register-glamo.patch:
    A small patch to add "platform:glamo-..." alias to the glamo drivers, in for udev to auto-load them
* pcf50633-bitfields.patch:
    A fix for the pcf50633 regulator driver, not sure it is needed, but it should not hurt

All those patches (except register-glamo.patch) comes from OpenMoko (OM)
kernel.git, slightly modified to apply to the Debian kernel without
needing all the changes made by OM. Each patch should refer to the
correspondign commit(s) from OM git repository.
They are for the unstable kernel.

AFAIK, the affected code isn't used for any device currently supported
by Debian, so, if something goes wrong, it's easy to drop them.

So, two questions: First, is it possible to have this flavour in Debian
after some more work? If yes, can I target the 2.6.32 kernel so it have
a chance to be in squeeze?

By the way, any comment on the patches/config itself is of course
welcome!

Best regards,
Thibaut Girka.

[1] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=503292
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 24 Oct 2009 16:48:17 +0000 (+0200)
Subject: MFD: pcf50633: Fix bitfield logic in interrupt handler
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=470379585be3e2e116e9412e114698debb02eb9e

MFD: pcf50633: Fix bitfield logic in interrupt handler

Those constants are alreay bitfields.
---

diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 63a614d..64d490c 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -354,18 +354,18 @@ static void pcf50633_irq_worker(struct work_struct *work)
 	if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
 		chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
 		if (chgstat & (0x3 << 4))
-			pcf_int[0] &= ~(1 << PCF50633_INT1_USBREM);
+			pcf_int[0] &= ~PCF50633_INT1_USBREM;
 		else
-			pcf_int[0] &= ~(1 << PCF50633_INT1_USBINS);
+			pcf_int[0] &= ~PCF50633_INT1_USBINS;
 	}
 
 	/* Make sure only one of ADPINS or ADPREM is set */
 	if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
 		chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
 		if (chgstat & (0x3 << 4))
-			pcf_int[0] &= ~(1 << PCF50633_INT1_ADPREM);
+			pcf_int[0] &= ~PCF50633_INT1_ADPREM;
 		else
-			pcf_int[0] &= ~(1 << PCF50633_INT1_ADPINS);
+			pcf_int[0] &= ~PCF50633_INT1_ADPINS;
 	}
 
 	dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
From: mokopatches <mokopatches@openmoko.org>
Date: Wed, 19 Nov 2008 17:03:14 +0000 (+0000)
Subject: s3c2410_udc-2440_dual_packet-workaround.patch
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=200ef71c3f94b4c152bdb02954297cd0672bc07e

s3c2410_udc-2440_dual_packet-workaround.patch
This is a patch that seems to make the USB hangs on the S3C2440 go away. At
least a good amount of ping torture didn't make them come back so far.

The issue is that, if there are several back-to-back packets,
sometimes no interrupt is generated for one of them. This
seems to be caused by the mysterious dual packet mode, which
the USB hardware enters automatically if the endpoint size is
half that of the FIFO. (On the 2440, this is the normal
situation for bulk data endpoints.)

There is also a timing factor in this. I think what happens is
that the USB hardware automatically sends an acknowledgement
if there is only one packet in the FIFO (the FIFO has space
for two). If another packet arrives before the host has
retrieved and acknowledged the previous one, no interrupt is
generated for that second one.

However, there may be an indication. There is one undocumented
bit (none of the 244x manuals document it), OUT_CRS1_REG[1],
that seems to be set suspiciously often when this condition
occurs. There is also CLR_DATA_TOGGLE, OUT_CRS1_REG[7], which
may have a function related to this. (The Samsung manual is
rather terse on that, as usual.)

This needs to be examined further. For now, the patch seems to do the
trick.

Note that this is not a clean solution by any means, because we
might potentially get stuck in that interrupt for quite a while.
---

diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index d5f4c1d..e6b76d8 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -842,6 +842,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
 	u32			ep_csr1;
 	u32			idx;
 
+handle_ep_again:
 	if (likely (!list_empty(&ep->queue)))
 		req = list_entry(ep->queue.next,
 				struct s3c2410_request, queue);
@@ -881,6 +882,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
 
 		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
 			s3c2410_udc_read_fifo(ep,req);
+			if (s3c2410_udc_fifo_count_out())
+				goto handle_ep_again;
 		}
 	}
 }
Description: Add glamo driver, required for µSD access on FreeRunner
Origin: http://git.openmoko.org/?p=kernel.git;a=commit;h=09cb945ad762e9a7f258287942918dd4a3badae4

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2a5a0b7..d72b985 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -304,6 +304,7 @@ config EZX_PCAP
 	help
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
+source "drivers/mfd/glamo/Kconfig"
 
 endmenu
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 22715ad..b0c5971 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_MFD_88PM860X)	+= 88pm860x.o
 
 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
index 0000000..3aa4831
--- /dev/null
+++ b/drivers/mfd/glamo/Kconfig
@@ -0,0 +1,42 @@
+config MFD_GLAMO
+	bool "Smedia Glamo 336x/337x support"
+	select MFD_CORE
+	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
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	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_GPIO
+	tristate "Glamo GPIO support"
+	depends on MFD_GLAMO
+
+	help
+		Enable a bitbanging SPI adapter driver for the Smedia Glamo.
+
+config MFD_GLAMO_MCI
+	tristate "Glamo S3C SD/MMC Card Interface support"
+	depends on MFD_GLAMO && MMC && REGULATOR
+   select CRC7
+	help
+	  This selects a driver for the MCI interface found in
+	  the S-Media GLAMO chip, as used in Openmoko
+	  neo1973 GTA-02.
+
+	  If unsure, say N.
diff --git a/drivers/mfd/glamo/Makefile b/drivers/mfd/glamo/Makefile
new file mode 100644
index 0000000..ebf26f7
--- /dev/null
+++ b/drivers/mfd/glamo/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Smedia Glamo framebuffer driver
+#
+
+obj-$(CONFIG_MFD_GLAMO)			+= glamo-core.o
+obj-$(CONFIG_MFD_GLAMO_GPIO)		+= glamo-gpio.o
+obj-$(CONFIG_MFD_GLAMO_SPI)		+= glamo-spi.o
+
+obj-$(CONFIG_MFD_GLAMO_FB)		+= glamo-fb.o
+obj-$(CONFIG_MFD_GLAMO_MCI)		+= glamo-mci.o
+
diff --git a/drivers/mfd/glamo/glamo-core.c b/drivers/mfd/glamo/glamo-core.c
new file mode 100644
index 0000000..23073fe
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-core.c
@@ -0,0 +1,1289 @@
+/* Smedia Glamo 3362 driver
+ *
+ * (C) 2007 by Openmoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ * 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/delay.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/glamo.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <linux/pm.h>
+
+#include "glamo-regs.h"
+#include "glamo-core.h"
+
+#define GLAMO_MEM_REFRESH_COUNT 0x100
+
+#define GLAMO_NR_IRQS 9
+
+#define GLAMO_IRQ_HOSTBUS	0
+#define GLAMO_IRQ_JPEG		1
+#define GLAMO_IRQ_MPEG		2
+#define GLAMO_IRQ_MPROC1	3
+#define GLAMO_IRQ_MPROC0	4
+#define GLAMO_IRQ_CMDQUEUE	5
+#define GLAMO_IRQ_2D		6
+#define GLAMO_IRQ_MMC		7
+#define GLAMO_IRQ_RISC		8
+
+/*
+ * Glamo internal settings
+ *
+ * We run the memory interface from the faster PLLB on 2.6.28 kernels and
+ * above.  Couple of GTA02 users report trouble with memory bus when they
+ * upgraded from 2.6.24.  So this parameter allows reversion to 2.6.24
+ * scheme if their Glamo chip needs it.
+ *
+ * you can override the faster default on kernel commandline using
+ *
+ *   glamo3362.slow_memory=1
+ *
+ * for example
+ */
+
+static int slow_memory;
+module_param(slow_memory, int, 0644);
+
+struct reg_range {
+	int start;
+	int count;
+	char *name;
+	unsigned dump:1;
+};
+
+static const struct reg_range reg_range[] = {
+	{ 0x0000, 0x76,		"General",	1 },
+	{ 0x0200, 0x18,		"Host Bus",	1 },
+	{ 0x0300, 0x38,		"Memory",	1 },
+/*	{ 0x0400, 0x100,	"Sensor",	0 }, */
+/*	{ 0x0500, 0x300,	"ISP",		0 }, */
+/*	{ 0x0800, 0x400,	"JPEG",		0 }, */
+/*	{ 0x0c00, 0xcc,		"MPEG",		0 }, */
+	{ 0x1100, 0xb2,		"LCD 1",	1 },
+	{ 0x1200, 0x64,		"LCD 2",	1 },
+	{ 0x1400, 0x42,		"MMC",		1 },
+/*	{ 0x1500, 0x080,	"MPU 0",	0 },
+	{ 0x1580, 0x080,	"MPU 1",	0 },
+	{ 0x1600, 0x080,	"Cmd Queue",	0 },
+	{ 0x1680, 0x080,	"RISC CPU",	0 },*/
+	{ 0x1700, 0x400,	"2D Unit",	1 },
+/*	{ 0x1b00, 0x900,	"3D Unit",	0 }, */
+};
+
+static inline void __reg_write(struct glamo_core *glamo,
+				uint16_t reg, uint16_t val)
+{
+	writew(val, glamo->base + reg);
+}
+
+void glamo_reg_write(struct glamo_core *glamo,
+				uint16_t reg, uint16_t val)
+{
+	spin_lock(&glamo->lock);
+	__reg_write(glamo, reg, val);
+	spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL_GPL(glamo_reg_write);
+
+
+static inline uint16_t __reg_read(struct glamo_core *glamo,
+					uint16_t reg)
+{
+	return readw(glamo->base + reg);
+}
+
+uint16_t glamo_reg_read(struct glamo_core *glamo, uint16_t reg)
+{
+	uint16_t val;
+	spin_lock(&glamo->lock);
+	val = __reg_read(glamo, reg);
+	spin_unlock(&glamo->lock);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(glamo_reg_read);
+
+static void __reg_set_bit_mask(struct glamo_core *glamo,
+				uint16_t reg, uint16_t mask,
+				uint16_t val)
+{
+	uint16_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,
+				uint16_t reg, uint16_t mask,
+				uint16_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,
+				 uint16_t reg, uint16_t bit)
+{
+	uint16_t tmp;
+	tmp = __reg_read(glamo, reg);
+	tmp |= bit;
+	__reg_write(glamo, reg, tmp);
+}
+
+static inline void __reg_clear_bit(struct glamo_core *glamo,
+					uint16_t reg, uint16_t bit)
+{
+	uint16_t tmp;
+	tmp = __reg_read(glamo, reg);
+	tmp &= ~bit;
+	__reg_write(glamo, reg, tmp);
+}
+
+static void __reg_write_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values)
+{
+	uint16_t end;
+	for (end = reg + count * 2; reg < end; reg += 2, ++values)
+		__reg_write(glamo, reg, *values);
+}
+
+static void __reg_read_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values)
+{
+	uint16_t end;
+	for (end = reg + count * 2; reg < end; reg += 2, ++values)
+		*values = __reg_read(glamo, reg);
+}
+
+void glamo_reg_write_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values)
+{
+	spin_lock(&glamo->lock);
+	__reg_write_batch(glamo, reg, count, values);
+	spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL(glamo_reg_write_batch);
+
+void glamo_reg_read_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values)
+{
+	spin_lock(&glamo->lock);
+	__reg_read_batch(glamo, reg, count, values);
+	spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL(glamo_reg_read_batch);
+
+/***********************************************************************
+ * resources of sibling devices
+ ***********************************************************************/
+
+static struct resource glamo_fb_resources[] = {
+	{
+		.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 resource glamo_mmc_resources[] = {
+	{
+		.name	= "glamo-mmc-regs",
+		.start	= GLAMO_REGOFS_MMC,
+		.end	= GLAMO_REGOFS_MPROC0 - 1,
+		.flags	= IORESOURCE_MEM
+	}, {
+		.name	= "glamo-mmc-mem",
+		.start	= GLAMO_OFFSET_FB + GLAMO_FB_SIZE,
+		.end	= GLAMO_OFFSET_FB + GLAMO_FB_SIZE +
+				  GLAMO_MMC_BUFFER_SIZE - 1,
+		.flags	= IORESOURCE_MEM
+	}, {
+		.start	= GLAMO_IRQ_MMC,
+		.end	= GLAMO_IRQ_MMC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+enum glamo_cells {
+	GLAMO_CELL_FB,
+	GLAMO_CELL_MMC,
+	GLAMO_CELL_GPIO,
+};
+
+static const struct mfd_cell glamo_cells[] = {
+	[GLAMO_CELL_FB] = {
+		.name = "glamo-fb",
+		.num_resources = ARRAY_SIZE(glamo_fb_resources),
+		.resources = glamo_fb_resources,
+	},
+	[GLAMO_CELL_MMC] = {
+		.name = "glamo-mci",
+		.num_resources = ARRAY_SIZE(glamo_mmc_resources),
+		.resources = glamo_mmc_resources,
+	},
+	[GLAMO_CELL_GPIO] = {
+		.name = "glamo-gpio",
+	},
+};
+
+/***********************************************************************
+ * IRQ demultiplexer
+ ***********************************************************************/
+#define glamo_irq_bit(glamo, x)	BIT(x - glamo->irq_base)
+
+static inline struct glamo_core *irq_to_glamo(unsigned int irq)
+{
+	return (struct glamo_core *)get_irq_chip_data(irq);
+}
+
+static void glamo_ack_irq(unsigned int irq)
+{
+	struct glamo_core *glamo = irq_to_glamo(irq);
+	/* clear interrupt source */
+	__reg_write(glamo, GLAMO_REG_IRQ_CLEAR, glamo_irq_bit(glamo, irq));
+}
+
+static void glamo_mask_irq(unsigned int irq)
+{
+	struct glamo_core *glamo = irq_to_glamo(irq);
+
+	/* clear bit in enable register */
+	__reg_clear_bit(glamo, GLAMO_REG_IRQ_ENABLE, glamo_irq_bit(glamo, irq));
+}
+
+static void glamo_unmask_irq(unsigned int irq)
+{
+	struct glamo_core *glamo = irq_to_glamo(irq);
+
+	/* set bit in enable register */
+	__reg_set_bit(glamo, GLAMO_REG_IRQ_ENABLE, glamo_irq_bit(glamo, irq));
+}
+
+static struct irq_chip glamo_irq_chip = {
+	.name	= "glamo",
+	.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)
+{
+	struct glamo_core *glamo = get_irq_desc_data(desc);
+	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);
+		return;
+	}
+	kstat_incr_irqs_this_cpu(irq, desc);
+
+	desc->chip->ack(irq);
+	desc->status |= IRQ_INPROGRESS;
+
+	do {
+		uint16_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, GLAMO_REG_IRQ_STATUS);
+		for (i = 0; i < 9; ++i) {
+			if (irqstatus & BIT(i))
+				generic_handle_irq(glamo->irq_base + i);
+		}
+
+	} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+
+	desc->status &= ~IRQ_INPROGRESS;
+}
+
+/*
+sysfs
+*/
+
+static ssize_t regs_write(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct glamo_core *glamo = dev_get_drvdata(dev);
+	unsigned int reg;
+	unsigned int val;
+
+	sscanf(buf, "%u %u", &reg, &val);
+	printk(KERN_INFO"reg 0x%02x <-- 0x%04x\n",
+		reg, val);
+
+	glamo_reg_write(glamo, reg, val);
+
+	return count;
+}
+
+static ssize_t regs_read(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct glamo_core *glamo = dev_get_drvdata(dev);
+	int i, n;
+	char *end = buf;
+	const struct reg_range *rr = reg_range;
+
+	spin_lock(&glamo->lock);
+
+	for (i = 0; i < ARRAY_SIZE(reg_range); ++i, ++rr) {
+		if (!rr->dump)
+			continue;
+		end += sprintf(end, "\n%s\n", rr->name);
+		for (n = rr->start; n < rr->start + rr->count; n += 2) {
+			if ((n & 15) == 0)
+				end += sprintf(end, "\n%04X:  ", n);
+			end += sprintf(end, "%04x ", __reg_read(glamo, n));
+		}
+		end += sprintf(end, "\n");
+	}
+	spin_unlock(&glamo->lock);
+
+	return end - buf;
+}
+
+static DEVICE_ATTR(regs, 0644, regs_read, regs_write);
+
+struct glamo_engine_reg_set {
+	uint16_t reg;
+	uint16_t mask_suspended;
+	uint16_t mask_enabled;
+};
+
+struct glamo_engine_desc {
+	const char *name;
+	uint16_t hostbus;
+	const struct glamo_engine_reg_set *regs;
+	int num_regs;
+};
+
+static const struct glamo_engine_reg_set glamo_lcd_regs[] = {
+	{ GLAMO_REG_CLOCK_LCD,
+	GLAMO_CLOCK_LCD_EN_M5CLK |
+	GLAMO_CLOCK_LCD_DG_M5CLK |
+	GLAMO_CLOCK_LCD_EN_DMCLK,
+
+	GLAMO_CLOCK_LCD_EN_DHCLK |
+	GLAMO_CLOCK_LCD_EN_DCLK
+	},
+	{ GLAMO_REG_CLOCK_GEN5_1,
+	GLAMO_CLOCK_GEN51_EN_DIV_DMCLK,
+
+	GLAMO_CLOCK_GEN51_EN_DIV_DHCLK |
+	GLAMO_CLOCK_GEN51_EN_DIV_DCLK
+	}
+};
+
+static const struct glamo_engine_reg_set glamo_mmc_regs[] = {
+	{ GLAMO_REG_CLOCK_MMC,
+	GLAMO_CLOCK_MMC_EN_M9CLK |
+	GLAMO_CLOCK_MMC_DG_M9CLK,
+
+	GLAMO_CLOCK_MMC_EN_TCLK |
+	GLAMO_CLOCK_MMC_DG_TCLK
+	},
+	{ GLAMO_REG_CLOCK_GEN5_1,
+	0,
+	GLAMO_CLOCK_GEN51_EN_DIV_TCLK
+	}
+};
+
+static const struct glamo_engine_reg_set glamo_2d_regs[] = {
+	{ GLAMO_REG_CLOCK_2D,
+	GLAMO_CLOCK_2D_EN_M7CLK |
+	GLAMO_CLOCK_2D_DG_M7CLK,
+
+	GLAMO_CLOCK_2D_EN_GCLK |
+	GLAMO_CLOCK_2D_DG_GCLK
+	},
+	{ GLAMO_REG_CLOCK_GEN5_1,
+	0,
+	GLAMO_CLOCK_GEN51_EN_DIV_GCLK,
+	}
+};
+
+static const struct glamo_engine_reg_set glamo_cmdq_regs[] = {
+	{ GLAMO_REG_CLOCK_2D,
+	GLAMO_CLOCK_2D_EN_M6CLK,
+	0
+	},
+};
+
+#define GLAMO_ENGINE(xname, xhostbus, xregs) { \
+	.name = xname, \
+	.hostbus = xhostbus, \
+	.num_regs = ARRAY_SIZE(xregs), \
+	.regs = xregs, \
+}
+
+static const struct glamo_engine_desc glamo_engines[] = {
+	[GLAMO_ENGINE_LCD] = GLAMO_ENGINE("LCD", GLAMO_HOSTBUS2_MMIO_EN_LCD,
+					glamo_lcd_regs),
+	[GLAMO_ENGINE_MMC] = GLAMO_ENGINE("MMC", GLAMO_HOSTBUS2_MMIO_EN_MMC,
+					glamo_mmc_regs),
+	[GLAMO_ENGINE_2D] = GLAMO_ENGINE("2D", GLAMO_HOSTBUS2_MMIO_EN_2D,
+					glamo_2d_regs),
+	[GLAMO_ENGINE_CMDQ] = GLAMO_ENGINE("CMDQ", GLAMO_HOSTBUS2_MMIO_EN_CQ,
+					glamo_cmdq_regs),
+};
+
+static inline const char *glamo_engine_name(enum glamo_engine engine)
+{
+	return glamo_engines[engine].name;
+}
+
+/***********************************************************************
+ * 'engine' support
+ ***********************************************************************/
+
+int __glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int i;
+	const struct glamo_engine_desc *engine_desc = &glamo_engines[engine];
+	const struct glamo_engine_reg_set *reg;
+
+	switch (engine) {
+	case GLAMO_ENGINE_LCD:
+	case GLAMO_ENGINE_MMC:
+	case GLAMO_ENGINE_2D:
+	case GLAMO_ENGINE_CMDQ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = engine_desc->regs;
+
+	__reg_set_bit(glamo, GLAMO_REG_HOSTBUS(2),
+			engine_desc->hostbus);
+	for (i = engine_desc->num_regs; i; --i, ++reg)
+		__reg_set_bit(glamo, reg->reg,
+				reg->mask_suspended | reg->mask_enabled);
+
+	return 0;
+}
+
+int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int ret = 0;
+
+	spin_lock(&glamo->lock);
+
+	if (glamo->engine_state[engine] != GLAMO_ENGINE_ENABLED) {
+		ret = __glamo_engine_enable(glamo, engine);
+		if (!ret)
+			glamo->engine_state[engine] = GLAMO_ENGINE_ENABLED;
+	}
+
+	spin_unlock(&glamo->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(glamo_engine_enable);
+
+int __glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int i;
+	const struct glamo_engine_desc *engine_desc = &glamo_engines[engine];
+	const struct glamo_engine_reg_set *reg;
+
+	switch (engine) {
+	case GLAMO_ENGINE_LCD:
+	case GLAMO_ENGINE_MMC:
+	case GLAMO_ENGINE_2D:
+	case GLAMO_ENGINE_CMDQ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = engine_desc->regs;
+
+	__reg_clear_bit(glamo, GLAMO_REG_HOSTBUS(2),
+			engine_desc->hostbus);
+	for (i = engine_desc->num_regs; i; --i, ++reg)
+		__reg_clear_bit(glamo, reg->reg,
+				reg->mask_suspended | reg->mask_enabled);
+
+	return 0;
+}
+int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int ret = 0;
+
+	spin_lock(&glamo->lock);
+
+	if (glamo->engine_state[engine] != GLAMO_ENGINE_DISABLED) {
+		ret = __glamo_engine_disable(glamo, engine);
+		if (!ret)
+			glamo->engine_state[engine] = GLAMO_ENGINE_DISABLED;
+	}
+
+	spin_unlock(&glamo->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(glamo_engine_disable);
+
+int __glamo_engine_suspend(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int i;
+	const struct glamo_engine_desc *engine_desc = &glamo_engines[engine];
+	const struct glamo_engine_reg_set *reg;
+
+	switch (engine) {
+	case GLAMO_ENGINE_LCD:
+	case GLAMO_ENGINE_MMC:
+	case GLAMO_ENGINE_2D:
+	case GLAMO_ENGINE_CMDQ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = engine_desc->regs;
+
+	__reg_set_bit(glamo, GLAMO_REG_HOSTBUS(2),
+			engine_desc->hostbus);
+	for (i = engine_desc->num_regs; i; --i, ++reg) {
+		__reg_set_bit(glamo, reg->reg, reg->mask_suspended);
+		__reg_clear_bit(glamo, reg->reg, reg->mask_enabled);
+	}
+
+	return 0;
+}
+
+int glamo_engine_suspend(struct glamo_core *glamo, enum glamo_engine engine)
+{
+	int ret = 0;
+
+	spin_lock(&glamo->lock);
+
+	if (glamo->engine_state[engine] != GLAMO_ENGINE_SUSPENDED) {
+		ret = __glamo_engine_suspend(glamo, engine);
+		if (!ret)
+			glamo->engine_state[engine] = GLAMO_ENGINE_SUSPENDED;
+	}
+
+	spin_unlock(&glamo->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(glamo_engine_suspend);
+
+static const struct glamo_script reset_regs[] = {
+	[GLAMO_ENGINE_LCD] = {
+		GLAMO_REG_CLOCK_LCD, GLAMO_CLOCK_LCD_RESET
+	},
+	[GLAMO_ENGINE_MMC] = {
+		GLAMO_REG_CLOCK_MMC, GLAMO_CLOCK_MMC_RESET
+	},
+	[GLAMO_ENGINE_CMDQ] = {
+		GLAMO_REG_CLOCK_2D, GLAMO_CLOCK_2D_CQ_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)
+{
+	uint16_t reg = reset_regs[engine].reg;
+	uint16_t val = reset_regs[engine].val;
+
+	if (engine >= ARRAY_SIZE(reset_regs)) {
+		dev_warn(&glamo->pdev->dev, "unknown engine %u ", engine);
+		return;
+	}
+
+	spin_lock(&glamo->lock);
+	__reg_set_bit(glamo, reg, val);
+	__reg_clear_bit(glamo, reg, val);
+	spin_unlock(&glamo->lock);
+}
+EXPORT_SYMBOL_GPL(glamo_engine_reset);
+
+int glamo_pll_rate(struct glamo_core *glamo,
+			  enum glamo_pll pll)
+{
+	uint16_t reg;
+	unsigned int osci = glamo->pdata->osci_clock_rate;
+
+	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 (int)osci * (int)reg;
+}
+EXPORT_SYMBOL_GPL(glamo_pll_rate);
+
+int glamo_engine_reclock(struct glamo_core *glamo,
+			 enum glamo_engine engine,
+			 int hz)
+{
+	int pll;
+	uint16_t reg, mask, div;
+
+	if (!hz)
+		return -EINVAL;
+
+	switch (engine) {
+	case GLAMO_ENGINE_LCD:
+		pll = GLAMO_PLL1;
+		reg = GLAMO_REG_CLOCK_GEN7;
+		mask = 0xff;
+		break;
+	case GLAMO_ENGINE_MMC:
+		pll = GLAMO_PLL1;
+		reg = GLAMO_REG_CLOCK_GEN8;
+		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);
+
+	div = pll / hz;
+
+	if (div != 0 && pll / div <= hz)
+		--div;
+
+	if (div > mask)
+		div = mask;
+
+	dev_dbg(&glamo->pdev->dev,
+			"PLL %d, kHZ %d, div %d\n", pll, hz / 1000, div);
+
+	reg_set_bit_mask(glamo, reg, mask, div);
+	mdelay(5); /* wait some time to stabilize */
+
+	return pll / (div + 1);
+}
+EXPORT_SYMBOL_GPL(glamo_engine_reclock);
+
+/***********************************************************************
+ * script support
+ ***********************************************************************/
+
+#define GLAMO_SCRIPT_END	0xffff
+#define GLAMO_SCRIPT_WAIT	0xfffe
+#define GLAMO_SCRIPT_LOCK_PLL	0xfffd
+
+/*
+ * couple of people reported artefacts with 2.6.28 changes, this
+ * allows reversion to 2.6.24 settings
+*/
+static const uint16_t reg_0x200[] = {
+0xe03, /* 0 waits on Async BB R & W, Use PLL 2 for mem bus */
+0xef0, /* 3 waits on Async BB R & W, Use PLL 1 for mem bus */
+0xea0, /* 2 waits on Async BB R & W, Use PLL 1 for mem bus */
+0xe50, /* 1 waits on Async BB R & W, Use PLL 1 for mem bus */
+0xe00, /* 0 waits on Async BB R & W, Use PLL 1 for mem bus */
+0xef3, /* 3 waits on Async BB R & W, Use PLL 2 for mem bus */
+0xea3, /* 2 waits on Async BB R & W, Use PLL 2 for mem bus */
+0xe53, /* 1 waits on Async BB R & W, Use PLL 2 for mem bus */
+};
+
+static int glamo_run_script(struct glamo_core *glamo,
+				const struct glamo_script *script, int len,
+				int may_sleep)
+{
+	int i;
+	uint16_t status;
+	const struct glamo_script *line = script;
+
+	for (i = 0; i < len; ++i, ++line) {
+		switch (line->reg) {
+		case GLAMO_SCRIPT_END:
+			return 0;
+		case GLAMO_SCRIPT_WAIT:
+			if (may_sleep)
+				msleep(line->val);
+			else
+				mdelay(line->val * 4);
+			break;
+		case GLAMO_SCRIPT_LOCK_PLL:
+			/* spin until PLLs lock */
+			do {
+				status = __reg_read(glamo, GLAMO_REG_PLL_GEN5);
+			} while ((status & 3) != 3);
+			break;
+		case 0x200:
+			__reg_write(glamo, line->reg,
+					reg_0x200[slow_memory & 0x8]);
+			break;
+		default:
+			__reg_write(glamo, line->reg, line->val);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct glamo_script glamo_init_script[] = {
+	{ GLAMO_REG_CLOCK_HOST,		0x1000 },
+	{ GLAMO_SCRIPT_WAIT,		     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,		0x1000 },
+	{ GLAMO_REG_CLOCK_MPEG,		0x3000 },
+	{ GLAMO_REG_CLOCK_MPROC,	0x1000 /*0x100f*/ },
+	{ GLAMO_SCRIPT_WAIT,		     2 },
+	{ GLAMO_REG_CLOCK_HOST,		0x0000 },
+	{ GLAMO_REG_CLOCK_MEMORY,	0x0000 },
+	{ GLAMO_REG_CLOCK_LCD,		0x0000 },
+	{ GLAMO_REG_CLOCK_MMC,		0x0000 },
+	{ GLAMO_REG_PLL_GEN1,		0x05db },	/* 48MHz */
+	{ GLAMO_REG_PLL_GEN3,		0x0aba },	/* 90MHz */
+	{ GLAMO_SCRIPT_LOCK_PLL, 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,		0x0100 },
+	{ GLAMO_REG_CLOCK_GEN6,		0x2000 },
+	{ GLAMO_REG_CLOCK_GEN7,		0x0101 },
+	{ GLAMO_REG_CLOCK_GEN8,		0x0100 },
+	{ GLAMO_REG_CLOCK_HOST,		0x000d },
+	/*
+	 * b7..b4 = 0 = no wait states on read or write
+	 * b0 = 1 select PLL2 for Host interface, b1 = enable it
+	 */
+	{ GLAMO_REG_HOSTBUS(0),		0x0e03 /* this is replaced by script parser */ },
+	{ GLAMO_REG_HOSTBUS(1),		0x07ff }, /* TODO: Disable all */
+	{ GLAMO_REG_HOSTBUS(10),	0x0000 },
+	{ GLAMO_REG_HOSTBUS(11),	0x4000 },
+	{ GLAMO_REG_HOSTBUS(12),	0xf00e },
+
+	/* S-Media recommended "set tiling mode to 512 mode for memory access
+	 * more efficiency when 640x480" */
+	{ GLAMO_REG_MEM_TYPE,		0x0c74 }, /* 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 },
+	{ GLAMO_SCRIPT_WAIT,		     1 },
+	{ GLAMO_REG_MEM_DRAM1,		0xc100 },
+	{ GLAMO_SCRIPT_WAIT,		     1 },
+	{ GLAMO_REG_MEM_DRAM1,		0xe100 },
+	{ GLAMO_REG_MEM_DRAM2,		0x01d6 },
+	{ GLAMO_REG_CLOCK_MEMORY,	0x000b },
+};
+
+/* Find out if we can support this version of the Glamo chip */
+static int __devinit glamo_supported(struct glamo_core *glamo)
+{
+	uint16_t dev_id, rev_id;
+
+	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);
+		}
+		break;
+	default:
+		dev_err(&glamo->pdev->dev, "unsupported Glamo device %04x\n",
+			dev_id);
+		return 0;
+	}
+
+	dev_dbg(&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 __devinit glamo_probe(struct platform_device *pdev)
+{
+	int ret = 0, irq, irq_base;
+	struct glamo_core *glamo;
+	struct resource *mem;
+
+	glamo = kmalloc(GFP_KERNEL, sizeof(*glamo));
+	if (!glamo)
+		return -ENOMEM;
+
+	spin_lock_init(&glamo->lock);
+
+	glamo->pdev = pdev;
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	glamo->irq = platform_get_irq(pdev, 0);
+	glamo->irq_base = irq_base = platform_get_irq(pdev, 1);
+	glamo->pdata = pdev->dev.platform_data;
+
+	if (glamo->irq < 0) {
+		ret = glamo->irq;
+		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+		goto err_free;
+	}
+
+	if (irq_base < 0) {
+		ret = glamo->irq;
+		dev_err(&pdev->dev, "Failed to get glamo irq base: %d\n", ret);
+		goto err_free;
+	}
+
+	if (!mem) {
+		dev_err(&pdev->dev, "Failed to get platform memory\n");
+		ret = -ENOENT;
+		goto err_free;
+	}
+
+	if (!glamo->pdata) {
+		dev_err(&pdev->dev, "Missing platform data\n");
+		ret = -ENOENT;
+		goto err_free;
+	}
+
+	/* only request the generic, hostbus and memory controller registers */
+	glamo->mem = request_mem_region(mem->start, GLAMO_REGOFS_VIDCAP,
+					pdev->name);
+
+	if (!glamo->mem) {
+		dev_err(&pdev->dev, "Failed to request io memory region\n");
+		ret = -ENOENT;
+		goto err_free;
+	}
+
+	glamo->base = ioremap(glamo->mem->start, resource_size(glamo->mem));
+	if (!glamo->base) {
+		dev_err(&pdev->dev, "Failed to ioremap() memory region\n");
+		goto err_release_mem_region;
+	}
+
+	/* confirm it isn't insane version */
+	if (!glamo_supported(glamo)) {
+		dev_err(&pdev->dev,
+			"This version of the Glamo is not supported\n");
+		goto err_iounmap;
+	}
+
+	platform_set_drvdata(pdev, glamo);
+
+	/* sysfs */
+	ret = device_create_file(&pdev->dev, &dev_attr_regs);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to create sysfs file\n");
+		goto err_iounmap;
+	}
+
+	/* init the chip with canned register set */
+	glamo_run_script(glamo, glamo_init_script,
+			 ARRAY_SIZE(glamo_init_script), 1);
+
+	/*
+	 * finally set the mfd interrupts up
+	 */
+	for (irq = irq_base; irq < irq_base + GLAMO_NR_IRQS; ++irq) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		set_irq_noprobe(irq);
+#endif
+		set_irq_chip_data(irq, glamo);
+		set_irq_chip_and_handler(irq, &glamo_irq_chip,
+					handle_level_irq);
+	}
+
+	set_irq_type(glamo->irq, IRQ_TYPE_EDGE_FALLING);
+	set_irq_data(glamo->irq, glamo);
+	set_irq_chained_handler(glamo->irq, glamo_irq_demux_handler);
+	glamo->irq_works = 1;
+
+	ret = mfd_add_devices(&pdev->dev, pdev->id, glamo_cells,
+				ARRAY_SIZE(glamo_cells), mem, glamo->irq_base);
+
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
+		goto err_free_irqs;
+	}
+
+	dev_info(&glamo->pdev->dev, "Glamo core PLL1: %uHz, PLL2: %uHz\n",
+		 glamo_pll_rate(glamo, GLAMO_PLL1),
+		 glamo_pll_rate(glamo, GLAMO_PLL2));
+
+	return 0;
+
+err_free_irqs:
+	disable_irq(glamo->irq);
+	set_irq_chained_handler(glamo->irq, NULL);
+	set_irq_chip_data(glamo->irq, NULL);
+
+	for (irq = irq_base; irq < irq_base + GLAMO_NR_IRQS; ++irq) {
+		set_irq_chip(irq, NULL);
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#else
+		set_irq_probe(irq);
+#endif
+		set_irq_chip_data(irq, NULL);
+	}
+err_iounmap:
+	iounmap(glamo->base);
+err_release_mem_region:
+	release_mem_region(glamo->mem->start, resource_size(glamo->mem));
+err_free:
+	platform_set_drvdata(pdev, NULL);
+	kfree(glamo);
+
+	return ret;
+}
+
+static int __devexit glamo_remove(struct platform_device *pdev)
+{
+	struct glamo_core *glamo = platform_get_drvdata(pdev);
+	int irq;
+	int irq_base = glamo->irq_base;
+
+	mfd_remove_devices(&pdev->dev);
+
+	disable_irq(glamo->irq);
+	set_irq_chained_handler(glamo->irq, NULL);
+	set_irq_chip_data(glamo->irq, NULL);
+
+	for (irq = irq_base; irq < irq_base + GLAMO_NR_IRQS; ++irq) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#else
+		set_irq_noprobe();
+#endif
+		set_irq_chip(irq, NULL);
+		set_irq_chip_data(irq, NULL);
+	}
+
+	platform_set_drvdata(pdev, NULL);
+	iounmap(glamo->base);
+	release_mem_region(glamo->mem->start, resource_size(glamo->mem));
+	kfree(glamo);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+#if 0
+static struct glamo_script glamo_resume_script[] = {
+
+	{ GLAMO_REG_PLL_GEN1,		0x05db },	/* 48MHz */
+	{ GLAMO_REG_PLL_GEN3,		0x0aba },	/* 90MHz */
+	{ GLAMO_REG_DFT_GEN6, 1 },
+		{ 0xfffe, 100 },
+		{ 0xfffd, 0 },
+	{ 0x200,	0x0e03 },
+
+	/*
+	 * 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_HOST,		0x0018 },
+	{ GLAMO_REG_CLOCK_GEN5_1, 0x18b1 },
+
+	{ 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 },
+};
+#endif
+
+#if 0
+static void glamo_power(struct glamo_core *glamo)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&glamo->lock, flags);
+
+	/*
+Power management
+static const REG_VALUE_MASK_TYPE reg_powerOn[] =
+{
+	{ REG_GEN_DFT6,	    REG_BIT_ALL,    REG_DATA(1u << 0)		},
+	{ REG_GEN_PLL3,	    0u,		    REG_DATA(1u << 13)		},
+	{ REG_GEN_MEM_CLK,  REG_BIT_ALL,    REG_BIT_EN_MOCACLK		},
+	{ REG_MEM_DRAM2,    0u,		    REG_BIT_EN_DEEP_POWER_DOWN	},
+	{ REG_MEM_DRAM1,    0u,		    REG_BIT_SELF_REFRESH	}
+};
+
+static const REG_VALUE_MASK_TYPE reg_powerStandby[] =
+{
+	{ REG_MEM_DRAM1,    REG_BIT_ALL,    REG_BIT_SELF_REFRESH    },
+	{ REG_GEN_MEM_CLK,  0u,		    REG_BIT_EN_MOCACLK	    },
+	{ REG_GEN_PLL3,	    REG_BIT_ALL,    REG_DATA(1u << 13)	    },
+	{ REG_GEN_DFT5,	    REG_BIT_ALL,    REG_DATA(1u << 0)	    }
+};
+
+static const REG_VALUE_MASK_TYPE reg_powerSuspend[] =
+{
+	{ REG_MEM_DRAM2,    REG_BIT_ALL,    REG_BIT_EN_DEEP_POWER_DOWN  },
+	{ REG_GEN_MEM_CLK,  0u,		    REG_BIT_EN_MOCACLK		},
+	{ REG_GEN_PLL3,	    REG_BIT_ALL,    REG_DATA(1u << 13)		},
+	{ REG_GEN_DFT5,	    REG_BIT_ALL,    REG_DATA(1u << 0)		}
+};
+*/
+	switch (new_state) {
+	case GLAMO_POWER_ON:
+
+		/*
+		 * glamo state on resume is nondeterministic in some
+		 * fundamental way, it has also been observed that the
+		 * Glamo reset pin can get asserted by, eg, touching it with
+		 * a scope probe.  So the only answer is to roll with it and
+		 * force an external reset on the Glamo during resume.
+		 */
+
+
+		break;
+
+	case GLAMO_POWER_SUSPEND:
+
+		break;
+	}
+	spin_unlock_irqrestore(&glamo->lock, flags);
+}
+#endif
+
+static int glamo_suspend(struct device *dev)
+{
+	struct glamo_core *glamo = dev_get_drvdata(dev);
+	int n;
+
+	spin_lock(&glamo->lock);
+
+	glamo->saved_irq_mask = __reg_read(glamo, GLAMO_REG_IRQ_ENABLE);
+
+	/* nuke interrupts */
+	__reg_write(glamo, GLAMO_REG_IRQ_ENABLE, 0x200);
+
+	/* take down each engine before we kill mem and pll */
+	for (n = 0; n < __NUM_GLAMO_ENGINES; n++) {
+		if (glamo->engine_state != GLAMO_ENGINE_DISABLED)
+			__glamo_engine_disable(glamo, n);
+	}
+
+	/* enable self-refresh */
+
+	__reg_write(glamo, GLAMO_REG_MEM_DRAM1,
+				GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
+				GLAMO_MEM_DRAM1_EN_GATE_CKE |
+				GLAMO_MEM_DRAM1_SELF_REFRESH |
+				GLAMO_MEM_REFRESH_COUNT);
+	__reg_write(glamo, GLAMO_REG_MEM_DRAM1,
+				GLAMO_MEM_DRAM1_EN_MODEREG_SET |
+				GLAMO_MEM_DRAM1_EN_DRAM_REFRESH |
+				GLAMO_MEM_DRAM1_EN_GATE_CKE |
+				GLAMO_MEM_DRAM1_SELF_REFRESH |
+				GLAMO_MEM_REFRESH_COUNT);
+
+	/* force RAM into deep powerdown */
+	__reg_write(glamo, GLAMO_REG_MEM_DRAM2,
+				GLAMO_MEM_DRAM2_DEEP_PWRDOWN |
+				(7 << 6) | /* tRC */
+				(1 << 4) | /* tRP */
+				(1 << 2) | /* tRCD */
+				2); /* CAS latency */
+
+	/* disable clocks to memory */
+	__reg_write(glamo, GLAMO_REG_CLOCK_MEMORY, 0);
+
+	/* all dividers from OSCI */
+	__reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_GEN5_1, 0x400, 0x400);
+
+	/* PLL2 into bypass */
+	__reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 12, 1 << 12);
+
+	__reg_write(glamo, GLAMO_BASIC_MMC_EN_TCLK_DLYA1, 0x0e00);
+
+	/* kill PLLS 1 then 2 */
+	__reg_write(glamo, GLAMO_REG_DFT_GEN5, 0x0001);
+	__reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 1 << 13, 1 << 13);
+
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static int glamo_resume(struct device *dev)
+{
+	struct glamo_core *glamo = dev_get_drvdata(dev);
+	int n;
+
+	(glamo->pdata->glamo_external_reset)(0);
+	udelay(10);
+	(glamo->pdata->glamo_external_reset)(1);
+	mdelay(5);
+
+	spin_lock(&glamo->lock);
+
+	glamo_run_script(glamo, glamo_init_script,
+			 ARRAY_SIZE(glamo_init_script), 0);
+
+
+	for (n = 0; n < __NUM_GLAMO_ENGINES; n++) {
+		switch (glamo->engine_state[n]) {
+		case GLAMO_ENGINE_SUSPENDED:
+			__glamo_engine_suspend(glamo, n);
+			break;
+		case GLAMO_ENGINE_ENABLED:
+			__glamo_engine_enable(glamo, n);
+			break;
+		default:
+			break;
+		}
+	}
+
+	__reg_write(glamo, GLAMO_REG_IRQ_ENABLE, glamo->saved_irq_mask);
+
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static struct dev_pm_ops glamo_pm_ops = {
+	.suspend    = glamo_suspend,
+	.resume     = glamo_resume,
+	.poweroff   = glamo_suspend,
+	.restore    = glamo_resume,
+};
+
+#define GLAMO_PM_OPS (&glamo_pm_ops)
+
+#else
+#define GLAMO_PM_OPS NULL
+#endif
+
+static struct platform_driver glamo_driver = {
+	.probe		= glamo_probe,
+	.remove		= __devexit_p(glamo_remove),
+	.driver		= {
+		.name	= "glamo3362",
+		.owner	= THIS_MODULE,
+		.pm	= GLAMO_PM_OPS,
+	},
+};
+
+static int __devinit glamo_init(void)
+{
+	return platform_driver_register(&glamo_driver);
+}
+module_init(glamo_init);
+
+static void __exit glamo_exit(void)
+{
+	platform_driver_unregister(&glamo_driver);
+}
+module_exit(glamo_exit);
+
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Smedia Glamo 3362 core/resource driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:glamo3362");
diff --git a/drivers/mfd/glamo/glamo-core.h b/drivers/mfd/glamo/glamo-core.h
new file mode 100644
index 0000000..17017b0
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-core.h
@@ -0,0 +1,61 @@
+#ifndef __GLAMO_CORE_H
+#define __GLAMO_CORE_H
+
+#include <linux/mfd/glamo.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)
+
+enum glamo_pll {
+    GLAMO_PLL1,
+    GLAMO_PLL2,
+};
+
+enum glamo_engine_state {
+    GLAMO_ENGINE_DISABLED,
+    GLAMO_ENGINE_SUSPENDED,
+    GLAMO_ENGINE_ENABLED,
+};
+
+struct glamo_core {
+	int irq;
+	int irq_base;
+	int irq_works; /* 0 means PCB does not support Glamo IRQ */
+	struct resource *mem;
+	void __iomem *base;
+	struct platform_device *pdev;
+	struct glamo_platform_data *pdata;
+	enum glamo_engine_state engine_state[__NUM_GLAMO_ENGINES];
+	spinlock_t lock;
+	uint16_t saved_irq_mask;
+};
+
+struct glamo_script {
+	uint16_t reg;
+	uint16_t val;
+};
+
+int glamo_pll_rate(struct glamo_core *glamo, enum glamo_pll pll);
+
+int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine);
+int glamo_engine_suspend(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);
+
+void glamo_reg_read_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values);
+void glamo_reg_write_batch(struct glamo_core *glamo, uint16_t reg,
+				uint16_t count, uint16_t *values);
+#endif /* __GLAMO_CORE_H */
diff --git a/drivers/mfd/glamo/glamo-fb.c b/drivers/mfd/glamo/glamo-fb.c
new file mode 100644
index 0000000..0eac3ac
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-fb.c
@@ -0,0 +1,982 @@
+/* Smedia Glamo 336x/337x driver
+ *
+ * (C) 2007-2008 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/string.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/mfd/glamo.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"
+
+static void glamofb_program_mode(struct glamofb_handle *glamo);
+
+struct glamofb_handle {
+	struct glamo_core *core;
+	struct fb_info *fb;
+	struct device *dev;
+	struct resource *reg;
+	struct resource *fb_res;
+	char __iomem *base;
+	struct glamo_fb_platform_data *mach_info;
+	char __iomem *cursor_addr;
+	int cursor_on;
+	u_int32_t pseudo_pal[16];
+	spinlock_t lock_cmd;
+	int blank_mode;
+	int mode_set; /* 0 if the current display mode hasn't been set on the glamo */
+	int output_enabled; /* 0 if the video output is disabled */
+};
+
+static void glamo_output_enable(struct glamofb_handle *gfb)
+{
+	struct glamo_core *gcore = gfb->core;
+
+	if (gfb->output_enabled)
+		return;
+
+	/* enable the pixel clock if off */
+	glamo_engine_enable(gcore, GLAMO_ENGINE_LCD);
+
+	gfb->output_enabled = 1;
+	if (!gfb->mode_set)
+		glamofb_program_mode(gfb);
+}
+
+static void glamo_output_disable(struct glamofb_handle *gfb)
+{
+	struct glamo_core *gcore = gfb->core;
+
+	if (!gfb->output_enabled)
+		return;
+
+	/* enable the pixel clock if off */
+	glamo_engine_suspend(gcore, GLAMO_ENGINE_LCD);
+
+	gfb->output_enabled = 0;
+}
+
+
+static int reg_read(struct glamofb_handle *glamo,
+			   u_int16_t reg)
+{
+	int i = 0;
+
+	for (i = 0; i != 2; i++)
+		nop();
+
+	return readw(glamo->base + reg);
+}
+
+static void reg_write(struct glamofb_handle *glamo,
+			 uint16_t reg, uint16_t val)
+{
+	int i = 0;
+
+	for (i = 0; i != 2; i++)
+		nop();
+
+	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, 0x9020 },
+	  /* video flip, no ptr, no ptr, dhclk off,
+	   * 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 */
+	/* The following values assume 640*480@16bpp */
+	{ GLAMO_REG_LCD_A_BASE1, 0x0000 }, /* display A base address 15:0 */
+	{ GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */
+	{ GLAMO_REG_LCD_CURSOR_BASE1, 0xC000 }, /* cursor base address 15:0 */
+	{ GLAMO_REG_LCD_CURSOR_BASE2, 0x0012 }, /* cursor base address 22:16 */
+	{ GLAMO_REG_LCD_COMMAND2, 0x0000 }, /* display page A */
+};
+
+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->bits_per_pixel != 16)
+		var->bits_per_pixel = 16;
+
+	var->height = glamo->mach_info->height;
+	var->width = glamo->mach_info->width;
+
+	/* 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;
+	}
+
+	return 0;
+}
+
+static void reg_set_bit_mask(struct glamofb_handle *glamo,
+				uint16_t reg, uint16_t mask,
+				uint16_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
+
+/* the caller has to enxure lock_cmd is held and we are in cmd mode */
+static void __rotate_lcd(struct glamofb_handle *glamo, __u32 rotation)
+{
+	int glamo_rot;
+
+	switch (rotation) {
+	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;
+	}
+
+	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);
+}
+
+static void glamofb_program_mode(struct glamofb_handle *gfb)
+{
+	int sync, bp, disp, fp, total;
+	unsigned long flags;
+	struct glamo_core *gcore = gfb->core;
+	struct fb_var_screeninfo *var = &gfb->fb->var;
+
+	dev_dbg(&gcore->pdev->dev,
+			  "glamofb_program_mode spin_lock_irqsave\n");
+	spin_lock_irqsave(&gfb->lock_cmd, flags);
+
+	if (glamofb_cmd_mode(gfb, 1))
+		goto out_unlock;
+
+	if (var->pixclock)
+		glamo_engine_reclock(gcore, GLAMO_ENGINE_LCD,
+				 (1000000000UL / gfb->fb->var.pixclock) * 1000);
+
+	reg_set_bit_mask(gfb,
+			 GLAMO_REG_LCD_WIDTH,
+			 GLAMO_LCD_WIDTH_MASK,
+			 var->xres);
+	reg_set_bit_mask(gfb,
+			 GLAMO_REG_LCD_HEIGHT,
+			 GLAMO_LCD_HEIGHT_MASK,
+			 var->yres);
+	reg_set_bit_mask(gfb,
+			 GLAMO_REG_LCD_PITCH,
+			 GLAMO_LCD_PITCH_MASK,
+			 gfb->fb->fix.line_length);
+
+	/* honour the rotation request */
+	__rotate_lcd(gfb, var->rotate);
+
+	/* update scannout timings */
+	sync = 0;
+	bp = sync + var->hsync_len;
+	disp = bp + var->left_margin;
+	fp = disp + var->xres;
+	total = fp + var->right_margin;
+
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_TOTAL,
+			 GLAMO_LCD_HV_TOTAL_MASK, total);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_RETR_START,
+			 GLAMO_LCD_HV_RETR_START_MASK, sync);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_RETR_END,
+			 GLAMO_LCD_HV_RETR_END_MASK, bp);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_DISP_START,
+			  GLAMO_LCD_HV_RETR_DISP_START_MASK, disp);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_HORIZ_DISP_END,
+			 GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
+
+	sync = 0;
+	bp = sync + var->vsync_len;
+	disp = bp + var->upper_margin;
+	fp = disp + var->yres;
+	total = fp + var->lower_margin;
+
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_TOTAL,
+			 GLAMO_LCD_HV_TOTAL_MASK, total);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_RETR_START,
+			  GLAMO_LCD_HV_RETR_START_MASK, sync);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_RETR_END,
+			 GLAMO_LCD_HV_RETR_END_MASK, bp);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_DISP_START,
+			 GLAMO_LCD_HV_RETR_DISP_START_MASK, disp);
+	reg_set_bit_mask(gfb, GLAMO_REG_LCD_VERT_DISP_END,
+			 GLAMO_LCD_HV_RETR_DISP_END_MASK, fp);
+
+	glamofb_cmd_mode(gfb, 0);
+
+	gfb->mode_set = 1;
+
+out_unlock:
+	dev_dbg(&gcore->pdev->dev,
+		  "glamofb_program_mode spin_unlock_irqrestore\n");
+	spin_unlock_irqrestore(&gfb->lock_cmd, flags);
+}
+
+
+static int glamofb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	return 0;
+}
+
+static struct fb_videomode *glamofb_find_mode(struct fb_info *info,
+						struct fb_var_screeninfo *var)
+{
+	struct glamofb_handle *glamo = info->par;
+	struct glamo_fb_platform_data *pdata = glamo->mach_info;
+	struct fb_videomode *mode;
+	int i;
+
+	for (i = pdata->num_modes, mode = pdata->modes; i; --i, ++mode) {
+		if (mode->xres == var->xres &&
+			mode->yres == var->yres)
+			return mode;
+	}
+
+	return NULL;
+}
+
+static int glamofb_set_par(struct fb_info *info)
+{
+	struct glamofb_handle *glamo = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_videomode *mode;
+
+	mode = glamofb_find_mode(info, var);
+	if (!mode)
+		return -EINVAL;
+
+	fb_videomode_to_var(var, mode);
+
+	info->mode = mode;
+
+	glamo->mode_set = 0;
+
+	switch (var->rotate) {
+	case FB_ROTATE_CW:
+	case FB_ROTATE_CCW:
+		info->fix.line_length = (var->yres * var->bits_per_pixel) / 8;
+		/* FIXME: Limit pixelclock */
+		var->pixclock *= 2;
+		break;
+	default:
+		info->fix.line_length = (var->xres * var->bits_per_pixel) / 8;
+		break;
+	}
+
+	if (glamo->output_enabled)
+		glamofb_program_mode(glamo);
+
+	return 0;
+}
+
+static int glamofb_blank(int blank_mode, struct fb_info *info)
+{
+	struct glamofb_handle *gfb = info->par;
+
+	dev_dbg(gfb->dev, "glamofb_blank(%u)\n", blank_mode);
+
+	switch (blank_mode) {
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+		/* FIXME: add pdata hook/flag to indicate whether
+		 * we should already switch off pixel clock here */
+		break;
+	case FB_BLANK_POWERDOWN:
+		/* disable the pixel clock */
+		glamo_output_disable(gfb);
+		gfb->blank_mode = blank_mode;
+		break;
+	case FB_BLANK_UNBLANK:
+	case FB_BLANK_NORMAL:
+		glamo_output_enable(gfb);
+		gfb->blank_mode = blank_mode;
+		break;
+	}
+
+	/* FIXME: once we have proper clock management in glamo-core,
+	 * we can determine if other units need MCLK1 or the PLL, and
+	 * disable it if not used. */
+	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_ioctl(struct fb_info *info, unsigned int cmd,
+				unsigned long arg)
+{
+	struct glamofb_handle *gfb = (struct glamofb_handle *)info->par;
+	struct glamo_core *gcore = gfb->core;
+	int retval = -ENOTTY;
+
+	switch (cmd) {
+	case GLAMOFB_ENGINE_ENABLE:
+		retval = glamo_engine_enable(gcore, arg);
+		break;
+	case GLAMOFB_ENGINE_DISABLE:
+		retval = glamo_engine_disable(gcore, arg);
+		break;
+	case GLAMOFB_ENGINE_RESET:
+		glamo_engine_reset(gcore, arg);
+		retval = 0;
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
+static inline void glamofb_vsync_wait(struct glamofb_handle *glamo,
+		int line, int size, int range)
+{
+	int count[2];
+
+	do {
+		count[0] = reg_read(glamo, GLAMO_REG_LCD_STATUS2) & 0x3ff;
+		count[1] = reg_read(glamo, GLAMO_REG_LCD_STATUS2) & 0x3ff;
+	} while (count[0] != count[1] ||
+			(line < count[0] + range &&
+			 size > count[0] - range) ||
+			count[0] < range * 2);
+}
+
+/*
+ * Enable/disable the hardware cursor mode altogether
+ * (for blinking and such, use glamofb_cursor()).
+ */
+static void glamofb_cursor_onoff(struct glamofb_handle *glamo, int on)
+{
+	int y, size;
+
+	if (glamo->cursor_on) {
+		y = reg_read(glamo, GLAMO_REG_LCD_CURSOR_Y_POS);
+		size = reg_read(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE);
+
+		glamofb_vsync_wait(glamo, y, size, 30);
+	}
+
+	reg_set_bit_mask(glamo, GLAMO_REG_LCD_MODE1,
+			GLAMO_LCD_MODE1_CURSOR_EN,
+			on ? GLAMO_LCD_MODE1_CURSOR_EN : 0);
+	glamo->cursor_on = on;
+
+	/* Hide the cursor by default */
+	reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE, 0);
+}
+
+static int glamofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	struct glamofb_handle *glamo = info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glamo->lock_cmd, flags);
+
+	reg_write(glamo, GLAMO_REG_LCD_CURSOR_X_SIZE,
+			cursor->enable ? cursor->image.width : 0);
+
+	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) {
+		uint16_t fg = glamo->pseudo_pal[cursor->image.fg_color];
+		uint16_t bg = glamo->pseudo_pal[cursor->image.bg_color];
+
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_FG_COLOR, fg);
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_BG_COLOR, bg);
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_DST_COLOR, fg);
+	}
+
+	if (cursor->set & FB_CUR_SETHOT)
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_PRESET,
+				(cursor->hot.x << 8) | cursor->hot.y);
+
+	if ((cursor->set & FB_CUR_SETSIZE) ||
+	    (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE))) {
+		int x, y, pitch, op;
+		const uint8_t *pcol = cursor->image.data;
+		const uint8_t *pmsk = cursor->mask;
+		uint8_t __iomem *dst = glamo->cursor_addr;
+		uint8_t dcol = 0;
+		uint8_t dmsk = 0;
+		uint8_t byte = 0;
+
+		if (cursor->image.depth > 1) {
+			spin_unlock_irqrestore(&glamo->lock_cmd, flags);
+			return -EINVAL;
+		}
+
+		pitch = ((cursor->image.width + 7) >> 2) & ~1;
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_PITCH,
+			pitch);
+		reg_write(glamo, GLAMO_REG_LCD_CURSOR_Y_SIZE,
+			cursor->image.height);
+
+		for (y = 0; y < cursor->image.height; y++) {
+			byte = 0;
+			for (x = 0; x < cursor->image.width; x++) {
+				if ((x % 8) == 0) {
+					dcol = *pcol++;
+					dmsk = *pmsk++;
+				} else {
+					dcol >>= 1;
+					dmsk >>= 1;
+				}
+
+				if (cursor->rop == ROP_COPY)
+					op = (dmsk & 1) ?
+						(dcol & 1) ? 1 : 3 : 0;
+				else
+					op = ((dmsk & 1) << 1) |
+						((dcol & 1) << 0);
+				byte |= op << ((x & 3) << 1);
+
+				if (x % 4 == 3) {
+					writeb(byte, dst + x / 4);
+					byte = 0;
+				}
+			}
+			if (x % 4) {
+				writeb(byte, dst + x / 4);
+				byte = 0;
+			}
+
+			dst += pitch;
+		}
+	}
+
+	spin_unlock_irqrestore(&glamo->lock_cmd, flags);
+
+	return 0;
+}
+#endif
+
+static inline int glamofb_cmdq_empty(struct glamofb_handle *gfb)
+{
+	/* DGCMdQempty -- 1 == command queue is empty */
+	return reg_read(gfb, GLAMO_REG_LCD_STATUS1) & (1 << 15);
+}
+
+/* call holding gfb->lock_cmd  when locking, until you unlock */
+int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
+{
+	int timeout = 2000000;
+
+	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: ",
+			__func__);
+		while (!glamofb_cmdq_empty(gfb) && (timeout--))
+			cpu_relax();
+		if (timeout < 0) {
+			printk(KERN_ERR "glamofb cmd_queue never got empty\n");
+			return -EIO;
+		}
+		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 idle */
+		dev_dbg(gfb->dev, "waiting for lcd idle: ");
+		timeout = 2000000;
+		while (!(reg_read(gfb, GLAMO_REG_LCD_STATUS2) & (1 << 12)) &&
+		      (timeout--))
+			cpu_relax();
+		if (timeout < 0) {
+			printk(KERN_ERR"*************"
+				       "glamofb lcd never idle"
+				       "*************\n");
+			return -EIO;
+		}
+
+		mdelay(100);
+
+		dev_dbg(gfb->dev, "cmd mode entered\n");
+
+	} 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);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(glamofb_cmd_mode);
+
+
+int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val)
+{
+	int timeout = 200000;
+
+	dev_dbg(gfb->dev, "%s: waiting for cmdq empty\n", __func__);
+	while ((!glamofb_cmdq_empty(gfb)) && (timeout--))
+		yield();
+	if (timeout < 0) {
+		printk(KERN_ERR"*************"
+				"glamofb cmd_queue never got empty"
+				"*************\n");
+		return 1;
+	}
+	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_pan_display	= glamofb_pan_display,
+	.fb_set_par	= glamofb_set_par,
+	.fb_blank	= glamofb_blank,
+	.fb_setcolreg	= glamofb_setcolreg,
+	.fb_ioctl = glamofb_ioctl,
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
+	.fb_cursor	= glamofb_cursor,
+#endif
+	.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 glamo_core *core = dev_get_drvdata(pdev->dev.parent);
+	struct glamo_fb_platform_data *mach_info;
+
+	printk(KERN_INFO "SMEDIA Glamo frame buffer driver (C) 2007 "
+		"Openmoko, Inc.\n");
+
+	if (!core->pdata || !core->pdata->fb_data)
+		return -ENOENT;
+
+
+	fbinfo = framebuffer_alloc(sizeof(struct glamofb_handle), &pdev->dev);
+	if (!fbinfo)
+		return -ENOMEM;
+
+
+	glamofb = fbinfo->par;
+	glamofb->fb = fbinfo;
+	glamofb->dev = &pdev->dev;
+
+	glamofb->blank_mode = FB_BLANK_POWERDOWN;
+
+	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,
+					      resource_size(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,
+						 resource_size(glamofb->fb_res),
+						 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_nocache(glamofb->reg->start,
+					resource_size(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 = (__u32) resource_size(glamofb->fb_res);
+
+	fbinfo->screen_base = ioremap(glamofb->fb_res->start,
+					   resource_size(glamofb->fb_res));
+	if (!fbinfo->screen_base) {
+		dev_err(&pdev->dev, "failed to ioremap() vram memory\n");
+		goto out_release_fb;
+	}
+	glamofb->cursor_addr = fbinfo->screen_base + 0x12C000;
+
+	platform_set_drvdata(pdev, glamofb);
+
+	mach_info = core->pdata->fb_data;
+	glamofb->core = core;
+	glamofb->mach_info = mach_info;
+
+	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_GLAMO;
+
+
+	fbinfo->fbops = &glamofb_ops;
+	fbinfo->flags = FBINFO_FLAG_DEFAULT;
+	fbinfo->pseudo_palette = &glamofb->pseudo_pal;
+
+	fbinfo->mode = mach_info->modes;
+	fb_videomode_to_var(&fbinfo->var, fbinfo->mode);
+	fbinfo->var.bits_per_pixel = 16;
+	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;
+
+	glamo_engine_enable(core, GLAMO_ENGINE_LCD);
+	glamo_engine_reset(core, GLAMO_ENGINE_LCD);
+	glamofb->output_enabled = 1;
+	glamofb->mode_set = 1;
+
+	dev_info(&pdev->dev, "spin_lock_init\n");
+	spin_lock_init(&glamofb->lock_cmd);
+	glamofb_init_regs(glamofb);
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
+	glamofb_cursor_onoff(glamofb, 1);
+#endif
+
+	fb_videomode_to_modelist(mach_info->modes, mach_info->num_modes,
+				 &fbinfo->modelist);
+
+	rc = register_framebuffer(fbinfo);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "failed to register framebuffer\n");
+		goto out_unmap_fb;
+	}
+
+	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,
+				resource_size(glamofb->fb_res));
+out_release_reg:
+	release_mem_region(glamofb->reg->start,
+				resource_size(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, resource_size(glamofb->reg));
+
+	framebuffer_release(glamofb->fb);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int glamofb_suspend(struct device *dev)
+{
+	struct glamofb_handle *gfb = dev_get_drvdata(dev);
+
+	acquire_console_sem();
+	fb_set_suspend(gfb->fb, 1);
+	release_console_sem();
+
+	/* seriously -- nobody is allowed to touch glamo memory when we
+	 * are suspended or we lock on nWAIT
+	 */
+	/* iounmap(gfb->fb->screen_base); */
+
+	return 0;
+}
+
+static int glamofb_resume(struct device *dev)
+{
+	struct glamofb_handle *gfb = dev_get_drvdata(dev);
+
+	/* OK let's allow framebuffer ops again */
+	/* gfb->fb->screen_base = ioremap(gfb->fb_res->start,
+					   resource_size(gfb->fb_res)); */
+	glamo_engine_enable(gfb->core, GLAMO_ENGINE_LCD);
+	glamo_engine_reset(gfb->core, GLAMO_ENGINE_LCD);
+
+	glamofb_init_regs(gfb);
+#ifdef CONFIG_MFD_GLAMO_HWACCEL
+	glamofb_cursor_onoff(gfb, 1);
+#endif
+
+	acquire_console_sem();
+	fb_set_suspend(gfb->fb, 0);
+	release_console_sem();
+
+	return 0;
+}
+
+static struct dev_pm_ops glamofb_pm_ops = {
+	.suspend = glamofb_suspend,
+	.resume = glamofb_resume,
+};
+
+#define GLAMOFB_PM_OPS (&glamofb_pm_ops)
+
+#else
+#define GLAMOFB_PM_OPS NULL
+#endif
+
+static struct platform_driver glamofb_driver = {
+	.probe		= glamofb_probe,
+	.remove		= glamofb_remove,
+	.driver		= {
+		.name	= "glamo-fb",
+		.owner	= THIS_MODULE,
+		.pm	= GLAMOFB_PM_OPS
+	},
+};
+
+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
index 0000000..30ee6ed
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-gpio.c
@@ -0,0 +1,285 @@
+/* Smedia Glamo 336x/337x gpio driver
+ *
+ * (C) 2009 Lars-Peter Clausen
+ *
+ * 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/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/gpio.h>
+#include <linux/mfd/glamo.h>
+
+#include "glamo-core.h"
+#include "glamo-regs.h"
+
+#define GLAMO_NR_GPIO 21
+#define GLAMO_NR_GPIO_REGS DIV_ROUND_UP(GLAMO_NR_GPIO, 4)
+
+#define GLAMO_REG_GPIO(x) (((x) * 2) + GLAMO_REG_GPIO_GEN1)
+
+struct glamo_gpio {
+	struct glamo_core *glamo;
+	struct gpio_chip chip;
+	uint16_t saved_regs[GLAMO_NR_GPIO_REGS];
+};
+
+#define REG_OF_GPIO(gpio)   (GLAMO_REG_GPIO(gpio >> 2))
+#define NUM_OF_GPIO(gpio)	(gpio & 0x3)
+#define DIRECTION_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))
+
+
+static inline struct glamo_core *chip_to_glamo(struct gpio_chip *chip)
+{
+	return container_of(chip, struct glamo_gpio, chip)->glamo;
+}
+
+static void glamo_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	unsigned int reg = REG_OF_GPIO(offset);
+	u_int16_t tmp;
+
+	spin_lock(&glamo->lock);
+	tmp = readw(glamo->base + reg);
+	if (value)
+		tmp |= OUTPUT_BIT(offset);
+	else
+		tmp &= ~OUTPUT_BIT(offset);
+	writew(tmp, glamo->base + reg);
+	spin_unlock(&glamo->lock);
+}
+
+static int glamo_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	return !!(readw(glamo->base + REG_OF_GPIO(offset)) & INPUT_BIT(offset));
+}
+
+static int glamo_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	unsigned int reg = REG_OF_GPIO(offset);
+	u_int16_t tmp;
+
+	spin_lock(&glamo->lock);
+	tmp = readw(glamo->base + reg);
+	if ((tmp & FUNC_BIT(offset)) == 0) {
+		tmp |= FUNC_BIT(offset);
+		writew(tmp, glamo->base + reg);
+	}
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static void glamo_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	unsigned int reg = REG_OF_GPIO(offset);
+	u_int16_t tmp;
+
+	spin_lock(&glamo->lock);
+	tmp = readw(glamo->base + reg);
+	if ((tmp & FUNC_BIT(offset)) == 1) {
+		tmp &= ~FUNC_BIT(offset);
+		writew(tmp, glamo->base + reg);
+	}
+	spin_unlock(&glamo->lock);
+}
+
+static int glamo_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+						int value)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	unsigned int reg = REG_OF_GPIO(offset);
+	u_int16_t tmp;
+
+	spin_lock(&glamo->lock);
+	tmp = readw(glamo->base + reg);
+    tmp &= ~DIRECTION_BIT(offset);
+
+	if (value)
+		tmp |= OUTPUT_BIT(offset);
+	else
+		tmp &= ~OUTPUT_BIT(offset);
+
+	writew(tmp, glamo->base + reg);
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static int glamo_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct glamo_core *glamo = chip_to_glamo(chip);
+	unsigned int reg = REG_OF_GPIO(offset);
+	u_int16_t tmp;
+
+	spin_lock(&glamo->lock);
+	tmp = readw(glamo->base + reg);
+	if ((tmp & DIRECTION_BIT(offset)) == 0) {
+		tmp |= DIRECTION_BIT(offset);
+		writew(tmp, glamo->base + reg);
+	}
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static const struct __devinit gpio_chip glamo_gpio_chip = {
+	.label				= "glamo",
+	.request			= glamo_gpio_request,
+	.free				= glamo_gpio_free,
+	.direction_input	= glamo_gpio_direction_input,
+	.get				= glamo_gpio_get,
+	.direction_output	= glamo_gpio_direction_output,
+	.set				= glamo_gpio_set,
+	.base				= -1,
+	.ngpio				= GLAMO_NR_GPIO,
+	.can_sleep			= 0,
+	.owner             = THIS_MODULE,
+};
+
+static int __devinit glamo_gpio_probe(struct platform_device *pdev)
+{
+	struct glamo_platform_data *pdata = pdev->dev.parent->platform_data;
+	struct glamo_gpio *glamo_gpio;
+	int ret;
+
+	glamo_gpio = kzalloc(sizeof(struct glamo_gpio), GFP_KERNEL);
+	if (!glamo_gpio)
+		return -ENOMEM;
+
+	glamo_gpio->glamo = dev_get_drvdata(pdev->dev.parent);
+	glamo_gpio->chip = glamo_gpio_chip;
+	glamo_gpio->chip.dev = &pdev->dev;
+	if (pdata && pdata->gpio_data)
+		glamo_gpio->chip.base = pdata->gpio_data->base;
+
+	ret = gpiochip_add(&glamo_gpio->chip);
+
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register gpio chip: %d\n", ret);
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, glamo_gpio);
+
+	if (pdata && pdata->gpio_data && pdata->gpio_data->registered)
+		pdata->gpio_data->registered(&pdev->dev);
+
+	return 0;
+err:
+	kfree(glamo_gpio);
+	return ret;
+}
+
+static int __devexit glamo_gpio_remove(struct platform_device *pdev)
+{
+	struct glamo_gpio *glamo_gpio = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&glamo_gpio->chip);
+	if (!ret)
+		goto done;
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(glamo_gpio);
+
+done:
+	return ret;
+}
+
+#ifdef CONFIG_PM
+
+static int glamo_gpio_suspend(struct device *dev)
+{
+	struct glamo_gpio *glamo_gpio = dev_get_drvdata(dev);
+	struct glamo_core *glamo = glamo_gpio->glamo;
+	uint16_t *saved_regs = glamo_gpio->saved_regs;
+	int i;
+
+	spin_lock(&glamo->lock);
+	for (i = 0; i < GLAMO_NR_GPIO / 4; ++i)
+		saved_regs[i] = readw(glamo->base + GLAMO_REG_GPIO(i));
+	spin_unlock(&glamo->lock);
+
+	return 0;
+}
+
+static int glamo_gpio_resume(struct device *dev)
+{
+	struct glamo_gpio *glamo_gpio = dev_get_drvdata(dev);
+	struct glamo_core *glamo = glamo_gpio->glamo;
+	uint16_t *saved_regs = glamo_gpio->saved_regs;
+	int i;
+
+	spin_lock(&glamo->lock);
+	for (i = 0; i < GLAMO_NR_GPIO_REGS; ++i)
+		writew(saved_regs[i], glamo->base + GLAMO_REG_GPIO(i));
+	spin_unlock(&glamo->lock);
+	return 0;
+}
+
+static const struct dev_pm_ops glamo_pm_ops = {
+	.suspend = glamo_gpio_suspend,
+	.resume  = glamo_gpio_resume,
+	.freeze  = glamo_gpio_suspend,
+	.thaw    = glamo_gpio_resume,
+};
+
+#define GLAMO_GPIO_PM_OPS (&glamo_pm_ops)
+
+#else
+#define GLAMO_GPIO_PM_OPS NULL
+#endif
+
+static struct platform_driver glamo_gpio_driver = {
+	.driver = {
+		.name  = "glamo-gpio",
+		.owner = THIS_MODULE,
+		.pm    = GLAMO_GPIO_PM_OPS,
+	},
+	.probe = glamo_gpio_probe,
+	.remove = __devexit_p(glamo_gpio_remove),
+};
+
+static int __devinit glamo_gpio_init(void)
+{
+	return platform_driver_register(&glamo_gpio_driver);
+}
+module_init(glamo_gpio_init);
+
+static void __exit glamo_gpio_exit(void)
+{
+	platform_driver_unregister(&glamo_gpio_driver);
+}
+module_exit(glamo_gpio_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("GPIO interface for the Glamo multimedia device");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:glamo-gpio");
diff --git a/drivers/mfd/glamo/glamo-mci.c b/drivers/mfd/glamo/glamo-mci.c
new file mode 100644
index 0000000..f49fa71
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-mci.c
@@ -0,0 +1,1023 @@
+/*
+ *  linux/drivers/mmc/host/glamo-mmc.c - Glamo MMC driver
+ *
+ *  Copyright (C) 2007 Openmoko, Inc,  Andy Green <andy@openmoko.com>
+ *  Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
+ *  Based on S3C MMC driver that was:
+ *  Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/crc7.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/mfd/glamo.h>
+
+#include "glamo-core.h"
+#include "glamo-regs.h"
+
+struct glamo_mci_host {
+	struct glamo_mmc_platform_data *pdata;
+	struct platform_device	*pdev;
+	struct glamo_core	*core;
+	struct mmc_host		*mmc;
+	struct resource		*mmio_mem;
+	struct resource		*data_mem;
+	void __iomem		*mmio_base;
+	uint16_t __iomem	*data_base;
+
+	unsigned int irq;
+
+	struct regulator *regulator;
+	struct mmc_request *mrq;
+
+	unsigned int clk_rate;
+
+	unsigned short vdd;
+	char power_mode;
+
+	unsigned char request_counter;
+
+	struct timer_list disable_timer;
+
+	struct work_struct irq_work;
+	struct work_struct read_work;
+
+	unsigned clk_enabled:1;
+};
+
+static void glamo_mci_send_request(struct mmc_host *mmc,
+				    struct mmc_request *mrq);
+static void glamo_mci_send_command(struct glamo_mci_host *host,
+				    struct mmc_command *cmd);
+
+/*
+ * Max SD clock rate
+ *
+ * held at /(3 + 1) due to concerns of 100R recommended series resistor
+ * allows 16MHz @ 4-bit --> 8MBytes/sec raw
+ *
+ * you can override this on kernel commandline using
+ *
+ *   glamo_mci.sd_max_clk=10000000
+ *
+ * for example
+ */
+
+static int sd_max_clk = 21000000;
+module_param(sd_max_clk, int, 0644);
+
+/*
+ * Slow SD clock rate
+ *
+ * you can override this on kernel commandline using
+ *
+ *   glamo_mci.sd_slow_ratio=8
+ *
+ * for example
+ *
+ * platform callback is used to decide effective clock rate, if not
+ * defined then max is used, if defined and returns nonzero, rate is
+ * divided by this factor
+ */
+
+static int sd_slow_ratio = 8;
+module_param(sd_slow_ratio, int, 0644);
+
+/*
+ * Post-power SD clock rate
+ *
+ * you can override this on kernel commandline using
+ *
+ *   glamo_mci.sd_post_power_clock=1000000
+ *
+ * for example
+ *
+ * After changing power to card, clock is held at this rate until first bulk
+ * transfer completes
+ */
+
+static int sd_post_power_clock = 1000000;
+module_param(sd_post_power_clock, int, 0644);
+
+
+static inline void glamo_reg_write(struct glamo_mci_host *glamo,
+				uint16_t reg, uint16_t val)
+{
+	writew(val, glamo->mmio_base + reg);
+}
+
+static inline uint16_t glamo_reg_read(struct glamo_mci_host *glamo,
+				   uint16_t reg)
+{
+	return readw(glamo->mmio_base + reg);
+}
+
+static void glamo_reg_set_bit_mask(struct glamo_mci_host *glamo,
+				uint16_t reg, uint16_t mask,
+				uint16_t val)
+{
+	uint16_t tmp;
+
+	val &= mask;
+
+	tmp = glamo_reg_read(glamo, reg);
+	tmp &= ~mask;
+	tmp |= val;
+	glamo_reg_write(glamo, reg, tmp);
+}
+
+static void glamo_mci_reset(struct glamo_mci_host *host)
+{
+	glamo_engine_reset(host->core, GLAMO_ENGINE_MMC);
+
+	glamo_reg_write(host, GLAMO_REG_MMC_WDATADS1,
+			(uint16_t)(host->data_mem->start));
+	glamo_reg_write(host, GLAMO_REG_MMC_WDATADS2,
+			(uint16_t)(host->data_mem->start >> 16));
+
+	glamo_reg_write(host, GLAMO_REG_MMC_RDATADS1,
+			(uint16_t)(host->data_mem->start));
+	glamo_reg_write(host, GLAMO_REG_MMC_RDATADS2,
+			(uint16_t)(host->data_mem->start >> 16));
+
+}
+
+static void glamo_mci_clock_disable(struct glamo_mci_host *host)
+{
+    glamo_engine_suspend(host->core, GLAMO_ENGINE_MMC);
+}
+
+static void glamo_mci_clock_enable(struct glamo_mci_host *host)
+{
+	del_timer_sync(&host->disable_timer);
+
+    glamo_engine_enable(host->core, GLAMO_ENGINE_MMC);
+}
+
+static void glamo_mci_disable_timer(unsigned long data)
+{
+	struct glamo_mci_host *host = (struct glamo_mci_host *)data;
+	glamo_mci_clock_disable(host);
+}
+
+
+static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data)
+{
+	struct sg_mapping_iter miter;
+	uint16_t __iomem *from_ptr = host->data_base;
+
+	dev_dbg(&host->pdev->dev, "pio_read():\n");
+
+	sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
+
+	while (sg_miter_next(&miter)) {
+		memcpy(miter.addr, from_ptr, miter.length);
+		from_ptr += miter.length >> 1;
+
+		data->bytes_xfered += miter.length;
+	}
+
+	sg_miter_stop(&miter);
+
+	dev_dbg(&host->pdev->dev, "pio_read(): "
+			"complete (no more data).\n");
+}
+
+static void do_pio_write(struct glamo_mci_host *host, struct mmc_data *data)
+{
+	struct sg_mapping_iter miter;
+	uint16_t __iomem *to_ptr = host->data_base;
+
+	dev_dbg(&host->pdev->dev, "pio_write():\n");
+	sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
+
+	while (sg_miter_next(&miter)) {
+		memcpy(to_ptr, miter.addr, miter.length);
+		to_ptr += miter.length >> 1;
+
+		data->bytes_xfered += miter.length;
+	}
+
+	sg_miter_stop(&miter);
+	dev_dbg(&host->pdev->dev, "pio_write(): complete\n");
+}
+
+static int glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq)
+{
+	int real_rate = 0;
+
+	if (freq) {
+		glamo_mci_clock_enable(host);
+		real_rate = glamo_engine_reclock(host->core, GLAMO_ENGINE_MMC,
+						freq);
+	} else {
+		glamo_mci_clock_disable(host);
+	}
+
+	return real_rate;
+}
+
+static int glamo_mci_wait_idle(struct glamo_mci_host *host,
+				unsigned long timeout)
+{
+	uint16_t status;
+	do {
+		status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+	} while (!(status & GLAMO_STAT1_MMC_IDLE) &&
+		  time_is_after_jiffies(timeout));
+
+	if (time_is_before_eq_jiffies(timeout)) {
+		glamo_mci_reset(host);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void glamo_mci_request_done(struct glamo_mci_host *host, struct
+mmc_request *mrq)
+{
+	mod_timer(&host->disable_timer, jiffies + HZ / 16);
+	mmc_request_done(host->mmc, mrq);
+}
+
+
+static void glamo_mci_irq_worker(struct work_struct *work)
+{
+	struct glamo_mci_host *host = container_of(work, struct glamo_mci_host,
+						    irq_work);
+	struct mmc_request *mrq;
+	struct mmc_command *cmd;
+	uint16_t status;
+
+	if (!host->mrq || !host->mrq->cmd)
+		return;
+
+	mrq = host->mrq;
+	cmd = mrq->cmd;
+
+#if 0
+	if (cmd->data->flags & MMC_DATA_READ)
+		return;
+#endif
+
+	status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+	dev_dbg(&host->pdev->dev, "status = 0x%04x\n", status);
+
+	/* we ignore a data timeout report if we are also told the data came */
+	if (status & GLAMO_STAT1_MMC_RB_DRDY)
+		status &= ~GLAMO_STAT1_MMC_DTOUT;
+
+	if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT))
+		cmd->error = -ETIMEDOUT;
+	else if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR))
+		cmd->error = -EILSEQ;
+
+	if (cmd->error) {
+		dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status);
+		goto done;
+	}
+
+	/* issue STOP if we have been given one to use */
+	if (mrq->stop)
+		glamo_mci_send_command(host, mrq->stop);
+
+	if (cmd->data->flags & MMC_DATA_READ)
+		do_pio_read(host, cmd->data);
+
+	if (mrq->stop)
+		mrq->stop->error = glamo_mci_wait_idle(host, jiffies + HZ);
+
+done:
+	host->mrq = NULL;
+	glamo_mci_request_done(host, cmd->mrq);
+}
+
+static void glamo_mci_read_worker(struct work_struct *work)
+{
+	struct glamo_mci_host *host = container_of(work, struct glamo_mci_host,
+							read_work);
+	struct mmc_command *cmd;
+	uint16_t status;
+	uint16_t blocks_ready;
+	size_t data_read = 0;
+	size_t data_ready;
+	struct scatterlist *sg;
+	uint16_t __iomem *from_ptr = host->data_base;
+	void *sg_pointer;
+
+
+	cmd = host->mrq->cmd;
+	sg = cmd->data->sg;
+	do {
+		status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+
+		if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT))
+			cmd->error = -ETIMEDOUT;
+		if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR))
+			cmd->error = -EILSEQ;
+		if (cmd->error) {
+			dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n",
+				status);
+			goto done;
+		}
+
+		blocks_ready = glamo_reg_read(host, GLAMO_REG_MMC_RB_BLKCNT);
+		data_ready = blocks_ready * cmd->data->blksz;
+
+		if (data_ready == data_read)
+			yield();
+
+		while (sg && data_read + sg->length <= data_ready) {
+			sg_pointer = page_address(sg_page(sg)) + sg->offset;
+			memcpy(sg_pointer, from_ptr, sg->length);
+			from_ptr += sg->length >> 1;
+
+			data_read += sg->length;
+			sg = sg_next(sg);
+		}
+
+	} while (sg);
+	cmd->data->bytes_xfered = data_read;
+
+	do {
+		status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+	} while (!(status & GLAMO_STAT1_MMC_IDLE));
+
+	if (host->mrq->stop)
+		glamo_mci_send_command(host, host->mrq->stop);
+
+	do {
+		status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+	} while (!(status & GLAMO_STAT1_MMC_IDLE));
+done:
+	host->mrq = NULL;
+	glamo_mci_request_done(host, cmd->mrq);
+}
+
+static irqreturn_t glamo_mci_irq(int irq, void *devid)
+{
+	struct glamo_mci_host *host = (struct glamo_mci_host *)devid;
+	schedule_work(&host->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static void glamo_mci_send_command(struct glamo_mci_host *host,
+				  struct mmc_command *cmd)
+{
+	uint8_t u8a[6];
+	uint16_t fire = 0;
+	unsigned int timeout = 1000000;
+	uint16_t *reg_resp = (uint16_t *)(host->mmio_base + GLAMO_REG_MMC_CMD_RSP1);
+	uint16_t status;
+	int triggers_int = 1;
+
+	/* if we can't do it, reject as busy */
+	if (!(glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1) &
+		 GLAMO_STAT1_MMC_IDLE)) {
+		cmd->error = -EBUSY;
+		return;
+	}
+
+	/* create an array in wire order for CRC computation */
+	u8a[0] = 0x40 | (cmd->opcode & 0x3f);
+	u8a[1] = (uint8_t)(cmd->arg >> 24);
+	u8a[2] = (uint8_t)(cmd->arg >> 16);
+	u8a[3] = (uint8_t)(cmd->arg >> 8);
+	u8a[4] = (uint8_t)cmd->arg;
+	u8a[5] = (crc7(0, u8a, 5) << 1) | 0x01;
+
+	/* issue the wire-order array including CRC in register order */
+	glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG1, ((u8a[4] << 8) | u8a[5]));
+	glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG2, ((u8a[2] << 8) | u8a[3]));
+	glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG3, ((u8a[0] << 8) | u8a[1]));
+
+	/* command index toggle */
+	fire |= (host->request_counter & 1) << 12;
+
+	/* set type of command */
+	switch (mmc_cmd_type(cmd)) {
+	case MMC_CMD_BC:
+		fire |= GLAMO_FIRE_MMC_CMDT_BNR;
+		break;
+	case MMC_CMD_BCR:
+		fire |= GLAMO_FIRE_MMC_CMDT_BR;
+		break;
+	case MMC_CMD_AC:
+		fire |= GLAMO_FIRE_MMC_CMDT_AND;
+		break;
+	case MMC_CMD_ADTC:
+		fire |= GLAMO_FIRE_MMC_CMDT_AD;
+		break;
+	}
+	/*
+	 * if it expects a response, set the type expected
+	 *
+	 * R1, Length  : 48bit, Normal response
+	 * R1b, Length : 48bit, same R1, but added card busy status
+	 * R2, Length  : 136bit (really 128 bits with CRC snipped)
+	 * R3, Length  : 48bit (OCR register value)
+	 * R4, Length  : 48bit, SDIO_OP_CONDITION, Reverse SDIO Card
+	 * R5, Length  : 48bit, IO_RW_DIRECTION, Reverse SDIO Card
+	 * R6, Length  : 48bit (RCA register)
+	 * R7, Length  : 48bit (interface condition, VHS(voltage supplied),
+	 *                     check pattern, CRC7)
+	 */
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_R1: /* same index as R6 and R7 */
+		fire |= GLAMO_FIRE_MMC_RSPT_R1;
+		break;
+	case MMC_RSP_R1B:
+		fire |= GLAMO_FIRE_MMC_RSPT_R1b;
+		break;
+	case MMC_RSP_R2:
+		fire |= GLAMO_FIRE_MMC_RSPT_R2;
+		break;
+	case MMC_RSP_R3:
+		fire |= GLAMO_FIRE_MMC_RSPT_R3;
+		break;
+	/* R4 and R5 supported by chip not defined in linux/mmc/core.h (sdio) */
+	}
+	/*
+	 * From the command index, set up the command class in the host ctrllr
+	 *
+	 * missing guys present on chip but couldn't figure out how to use yet:
+	 *     0x0 "stream read"
+	 *     0x9 "cancel running command"
+	 */
+	switch (cmd->opcode) {
+	case MMC_READ_SINGLE_BLOCK:
+		fire |= GLAMO_FIRE_MMC_CC_SBR; /* single block read */
+		break;
+	case MMC_SWITCH: /* 64 byte payload */
+	case SD_APP_SEND_SCR:
+	case MMC_READ_MULTIPLE_BLOCK:
+		/* we will get an interrupt off this */
+		if (!cmd->mrq->stop) {
+			/* multiblock no stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBRNS;
+		} else {
+			/* multiblock with stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBRS;
+		}
+		break;
+	case MMC_WRITE_BLOCK:
+		fire |= GLAMO_FIRE_MMC_CC_SBW; /* single block write */
+		break;
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		if (cmd->mrq->stop) {
+			/* multiblock with stop */
+			fire |= GLAMO_FIRE_MMC_CC_MBWS;
+		} else {
+			/* multiblock NO stop-- 'RESERVED'? */
+			fire |= GLAMO_FIRE_MMC_CC_MBWNS;
+		}
+		break;
+	case MMC_STOP_TRANSMISSION:
+		fire |= GLAMO_FIRE_MMC_CC_STOP; /* STOP */
+		triggers_int = 0;
+		break;
+	default:
+		fire |= GLAMO_FIRE_MMC_CC_BASIC; /* "basic command" */
+		triggers_int = 0;
+		break;
+	}
+
+	if (cmd->data)
+		host->mrq = cmd->mrq;
+
+	/* always largest timeout */
+	glamo_reg_write(host, GLAMO_REG_MMC_TIMEOUT, 0xfff);
+
+	/* Generate interrupt on txfer */
+	glamo_reg_set_bit_mask(host, GLAMO_REG_MMC_BASIC, 0xff36,
+			0x0800 |
+			GLAMO_BASIC_MMC_NO_CLK_RD_WAIT |
+			GLAMO_BASIC_MMC_EN_COMPL_INT |
+			GLAMO_BASIC_MMC_EN_DATA_PUPS |
+			GLAMO_BASIC_MMC_EN_CMD_PUP);
+
+	/* send the command out on the wire */
+	/* dev_info(&host->pdev->dev, "Using FIRE %04X\n", fire); */
+	glamo_reg_write(host, GLAMO_REG_MMC_CMD_FIRE, fire);
+
+	/* we are deselecting card?  because it isn't going to ack then... */
+	if ((cmd->opcode == 7) && (cmd->arg == 0))
+		return;
+
+	/*
+	 * we must spin until response is ready or timed out
+	 * -- we don't get interrupts unless there is a bulk rx
+	 */
+	do
+		status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
+	while (((((status >> 15) & 1) != (host->request_counter & 1)) ||
+		(!(status & (GLAMO_STAT1_MMC_RB_RRDY |
+				 GLAMO_STAT1_MMC_RTOUT |
+				 GLAMO_STAT1_MMC_DTOUT |
+				 GLAMO_STAT1_MMC_BWERR |
+				 GLAMO_STAT1_MMC_BRERR)))) && (timeout--));
+
+	if ((status & (GLAMO_STAT1_MMC_RTOUT |
+				   GLAMO_STAT1_MMC_DTOUT)) ||
+		(timeout == 0)) {
+		cmd->error = -ETIMEDOUT;
+	} else if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) {
+		cmd->error = -EILSEQ;
+	}
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136) {
+			cmd->resp[3] = readw(&reg_resp[0]) |
+						   (readw(&reg_resp[1]) << 16);
+			cmd->resp[2] = readw(&reg_resp[2]) |
+						   (readw(&reg_resp[3]) << 16);
+			cmd->resp[1] = readw(&reg_resp[4]) |
+						   (readw(&reg_resp[5]) << 16);
+			cmd->resp[0] = readw(&reg_resp[6]) |
+						   (readw(&reg_resp[7]) << 16);
+		} else {
+			cmd->resp[0] = (readw(&reg_resp[0]) >> 8) |
+					   (readw(&reg_resp[1]) << 8) |
+					   (readw(&reg_resp[2]) << 24);
+		}
+	}
+
+#if 0
+	/* We'll only get an interrupt when all data has been transfered.
+	   By starting to copy data when it's avaiable we can increase
+	   throughput by up to 30%. */
+	if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+		schedule_work(&host->read_work);
+#endif
+
+}
+
+static int glamo_mci_prepare_pio(struct glamo_mci_host *host,
+				 struct mmc_data *data)
+{
+	/* set up the block info */
+	glamo_reg_write(host, GLAMO_REG_MMC_DATBLKLEN, data->blksz);
+	glamo_reg_write(host, GLAMO_REG_MMC_DATBLKCNT, data->blocks);
+
+	data->bytes_xfered = 0;
+
+	/* if write, prep the write into the shared RAM before the command */
+	if (data->flags & MMC_DATA_WRITE)
+		do_pio_write(host, data);
+
+	dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n",
+				   data->blksz, data->blocks);
+	return 0;
+}
+
+static int glamo_mci_irq_poll(struct glamo_mci_host *host,
+				struct mmc_command *cmd)
+{
+	int timeout = 1000000;
+	uint16_t status;
+	/*
+	 * if the glamo INT# line isn't wired (*cough* it can happen)
+	 * I'm afraid we have to spin on the IRQ status bit and "be
+	 * our own INT# line"
+	 */
+	/*
+	 * we have faith we will get an "interrupt"...
+	 * but something insane like suspend problems can mean
+	 * we spin here forever, so we timeout after a LONG time
+	 */
+	do {
+		status = glamo_reg_read(host, GLAMO_REG_IRQ_STATUS);
+	} while ((--timeout) && !(status & GLAMO_IRQ_MMC));
+
+	if (timeout <= 0) {
+		if (cmd->data->error)
+			cmd->data->error = -ETIMEDOUT;
+		dev_err(&host->pdev->dev, "Payload timeout\n");
+		return -ETIMEDOUT;
+	}
+	/* ack this interrupt source */
+	writew(GLAMO_IRQ_MMC, host->core->base +
+		   GLAMO_REG_IRQ_CLEAR);
+
+	/* yay we are an interrupt controller! -- call the ISR
+	 * it will stop clock to card
+	 */
+	glamo_mci_irq(host->irq, host);
+
+	return 0;
+}
+
+static void glamo_mci_send_request(struct mmc_host *mmc,
+					struct mmc_request *mrq)
+{
+	struct glamo_mci_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd = mrq->cmd;
+
+	glamo_mci_clock_enable(host);
+	host->request_counter++;
+	if (cmd->data) {
+		if (glamo_mci_prepare_pio(host, cmd->data)) {
+			cmd->error = -EIO;
+			cmd->data->error = -EIO;
+			goto done;
+		}
+	}
+
+	dev_dbg(&host->pdev->dev, "cmd 0x%x, "
+		 "arg 0x%x data=%p mrq->stop=%p flags 0x%x\n",
+		 cmd->opcode, cmd->arg, cmd->data, cmd->mrq->stop,
+		 cmd->flags);
+
+	glamo_mci_send_command(host, cmd);
+
+	/*
+	 * if we don't have bulk data to take care of, we're done
+	 */
+	if (!cmd->data || cmd->error)
+		goto done;
+
+
+	if (!host->core->irq_works) {
+		if (glamo_mci_irq_poll(host, mrq->cmd))
+			goto done;
+	}
+
+	/*
+	 * Otherwise can can use the interrupt as async completion --
+	 * if there is read data coming, or we wait for write data to complete,
+	 * exit without mmc_request_done() as the payload interrupt
+	 * will service it
+	 */
+	dev_dbg(&host->pdev->dev, "Waiting for payload data\n");
+	return;
+done:
+	if (!cmd->error)
+		cmd->error = glamo_mci_wait_idle(host, jiffies + 2 * HZ);
+	glamo_mci_request_done(host, mrq);
+}
+
+static void glamo_mci_set_power_mode(struct glamo_mci_host *host,
+				unsigned char power_mode)
+{
+	int ret;
+
+	if (power_mode == host->power_mode)
+		return;
+
+	switch (power_mode) {
+	case MMC_POWER_UP:
+		if (host->power_mode == MMC_POWER_OFF) {
+			ret = regulator_enable(host->regulator);
+			if (ret)
+				dev_err(&host->pdev->dev,
+					"Failed to enable regulator: %d\n",
+					ret);
+		}
+		break;
+	case MMC_POWER_ON:
+		break;
+	case MMC_POWER_OFF:
+	default:
+		glamo_engine_disable(host->core, GLAMO_ENGINE_MMC);
+
+		ret = regulator_disable(host->regulator);
+		if (ret)
+			dev_warn(&host->pdev->dev,
+				"Failed to disable regulator: %d\n",
+				ret);
+		break;
+	}
+	host->power_mode = power_mode;
+}
+
+static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct glamo_mci_host *host = mmc_priv(mmc);
+	int bus_width = 0;
+	int rate;
+	int sd_drive;
+	int ret;
+
+	/* Set power */
+	glamo_mci_set_power_mode(host, ios->power_mode);
+
+	if (host->vdd != ios->vdd) {
+		ret = mmc_regulator_set_ocr(host->regulator, ios->vdd);
+		if (ret)
+			dev_err(&host->pdev->dev,
+				"Failed to set regulator voltage: %d\n", ret);
+		else
+			host->vdd = ios->vdd;
+	}
+	rate = glamo_mci_set_card_clock(host, ios->clock);
+
+	if ((ios->power_mode == MMC_POWER_ON) ||
+		(ios->power_mode == MMC_POWER_UP)) {
+		dev_info(&host->pdev->dev,
+			"powered (vdd = %hu) clk: %dkHz div=%hu (req: %ukHz). "
+			"Bus width=%d\n", ios->vdd,
+			rate / 1000, 0,
+			ios->clock / 1000, (int)ios->bus_width);
+	} else {
+		dev_info(&host->pdev->dev, "glamo_mci_set_ios: power down.\n");
+	}
+
+	/* set bus width */
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		bus_width = GLAMO_BASIC_MMC_EN_4BIT_DATA;
+
+	sd_drive = (rate * 4) / host->clk_rate;
+	if (sd_drive > 3)
+		sd_drive = 3;
+
+	glamo_reg_set_bit_mask(host, GLAMO_REG_MMC_BASIC,
+				GLAMO_BASIC_MMC_EN_4BIT_DATA | 0xb0,
+						   bus_width | sd_drive << 6);
+}
+
+
+/*
+ * no physical write protect supported by us
+ */
+static int glamo_mci_get_ro(struct mmc_host *mmc)
+{
+	return 0;
+}
+
+static struct mmc_host_ops glamo_mci_ops = {
+	.request	= glamo_mci_send_request,
+	.set_ios	= glamo_mci_set_ios,
+	.get_ro		= glamo_mci_get_ro,
+};
+
+static int glamo_mci_probe(struct platform_device *pdev)
+{
+	struct mmc_host *mmc;
+	struct glamo_mci_host *host;
+	struct glamo_core *core = dev_get_drvdata(pdev->dev.parent);
+	int ret;
+
+	dev_info(&pdev->dev, "glamo_mci driver (C)2007 Openmoko, Inc\n");
+
+	mmc = mmc_alloc_host(sizeof(struct glamo_mci_host), &pdev->dev);
+	if (!mmc) {
+		ret = -ENOMEM;
+		goto probe_out;
+	}
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->pdev = pdev;
+	if (core->pdata)
+		host->pdata = core->pdata->mmc_data;
+	host->power_mode = MMC_POWER_OFF;
+	host->clk_enabled = 0;
+	host->core = core;
+	host->irq = platform_get_irq(pdev, 0);
+
+	INIT_WORK(&host->irq_work, glamo_mci_irq_worker);
+	INIT_WORK(&host->read_work, glamo_mci_read_worker);
+
+	host->regulator = regulator_get(pdev->dev.parent, "SD_3V3");
+	if (IS_ERR(host->regulator)) {
+		dev_err(&pdev->dev, "Cannot proceed without regulator.\n");
+		ret = PTR_ERR(host->regulator);
+		goto probe_free_host;
+	}
+
+	host->mmio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!host->mmio_mem) {
+		dev_err(&pdev->dev,
+			"failed to get io memory region resouce.\n");
+		ret = -ENOENT;
+		goto probe_regulator_put;
+	}
+
+	host->mmio_mem = request_mem_region(host->mmio_mem->start,
+						resource_size(host->mmio_mem),
+						pdev->name);
+
+	if (!host->mmio_mem) {
+		dev_err(&pdev->dev, "failed to request io memory region.\n");
+		ret = -ENOENT;
+		goto probe_regulator_put;
+	}
+
+	host->mmio_base = ioremap(host->mmio_mem->start,
+				      resource_size(host->mmio_mem));
+	if (!host->mmio_base) {
+		dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
+		ret = -EINVAL;
+		goto probe_free_mem_region_mmio;
+	}
+
+
+	/* Get ahold of our data buffer we use for data in and out on MMC */
+	host->data_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!host->data_mem) {
+		dev_err(&pdev->dev,
+			"failed to get io memory region resource.\n");
+		ret = -ENOENT;
+		goto probe_iounmap_mmio;
+	}
+
+	host->data_mem = request_mem_region(host->data_mem->start,
+						resource_size(host->data_mem),
+						pdev->name);
+
+	if (!host->data_mem) {
+		dev_err(&pdev->dev, "failed to request io memory region.\n");
+		ret = -ENOENT;
+		goto probe_iounmap_mmio;
+	}
+	host->data_base = ioremap(host->data_mem->start,
+				      resource_size(host->data_mem));
+
+	if (host->data_base == 0) {
+		dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
+		ret = -EINVAL;
+		goto probe_free_mem_region_data;
+	}
+
+	ret = request_irq(host->irq, glamo_mci_irq, IRQF_SHARED,
+			   pdev->name, host);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register irq.\n");
+		goto probe_iounmap_data;
+	}
+
+
+	host->vdd = 0;
+	host->clk_rate = glamo_pll_rate(host->core, GLAMO_PLL1);
+
+	/* explain our host controller capabilities */
+	mmc->ops	= &glamo_mci_ops;
+	mmc->ocr_avail	= mmc_regulator_get_ocrmask(host->regulator);
+	mmc->caps	= MMC_CAP_4_BIT_DATA |
+			    MMC_CAP_MMC_HIGHSPEED |
+			    MMC_CAP_SD_HIGHSPEED;
+	mmc->f_min	= host->clk_rate / 256;
+	mmc->f_max	= sd_max_clk;
+
+	mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */
+	mmc->max_blk_size  = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */
+	mmc->max_req_size  = resource_size(host->data_mem);
+	mmc->max_seg_size  = mmc->max_req_size;
+	mmc->max_phys_segs = 128;
+	mmc->max_hw_segs   = 128;
+
+	if (mmc->ocr_avail < 0) {
+		dev_warn(&pdev->dev,
+			"Failed to get ocr list for regulator: %d.\n",
+			mmc->ocr_avail);
+		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	}
+
+	platform_set_drvdata(pdev, mmc);
+
+	glamo_engine_enable(host->core, GLAMO_ENGINE_MMC);
+	glamo_mci_reset(host);
+	glamo_engine_disable(host->core, GLAMO_ENGINE_MMC);
+
+	setup_timer(&host->disable_timer, glamo_mci_disable_timer,
+				(unsigned long)host);
+
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add mmc host.\n");
+		goto probe_freeirq;
+	}
+
+	return 0;
+
+probe_freeirq:
+	free_irq(host->irq, host);
+probe_iounmap_data:
+	iounmap(host->data_base);
+probe_free_mem_region_data:
+	release_mem_region(host->data_mem->start,
+				resource_size(host->data_mem));
+probe_iounmap_mmio:
+	iounmap(host->mmio_base);
+probe_free_mem_region_mmio:
+	release_mem_region(host->mmio_mem->start,
+				resource_size(host->mmio_mem));
+probe_regulator_put:
+	regulator_put(host->regulator);
+probe_free_host:
+	mmc_free_host(mmc);
+probe_out:
+	return ret;
+}
+
+static int glamo_mci_remove(struct platform_device *pdev)
+{
+	struct mmc_host	*mmc = platform_get_drvdata(pdev);
+	struct glamo_mci_host *host = mmc_priv(mmc);
+
+	free_irq(host->irq, host);
+
+	mmc_remove_host(mmc);
+	iounmap(host->mmio_base);
+	iounmap(host->data_base);
+	release_mem_region(host->mmio_mem->start,
+				resource_size(host->mmio_mem));
+	release_mem_region(host->data_mem->start,
+				resource_size(host->data_mem));
+
+	regulator_put(host->regulator);
+
+	mmc_free_host(mmc);
+
+	glamo_engine_disable(host->core, GLAMO_ENGINE_MMC);
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int glamo_mci_suspend(struct device *dev)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct glamo_mci_host *host = mmc_priv(mmc);
+	int ret;
+
+	cancel_work_sync(&host->irq_work);
+
+	ret = mmc_suspend_host(mmc, PMSG_SUSPEND);
+
+	return ret;
+}
+
+static int glamo_mci_resume(struct device *dev)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct glamo_mci_host *host = mmc_priv(mmc);
+	int ret;
+
+
+	glamo_mci_reset(host);
+	glamo_engine_enable(host->core, GLAMO_ENGINE_MMC);
+    mdelay(10);
+
+	ret = mmc_resume_host(host->mmc);
+
+	return 0;
+}
+
+static struct dev_pm_ops glamo_mci_pm_ops = {
+	.suspend    = glamo_mci_suspend,
+	.resume     = glamo_mci_resume,
+    .freeze     = glamo_mci_suspend,
+    .thaw       = glamo_mci_resume,
+};
+#define GLAMO_MCI_PM_OPS (&glamo_mci_pm_ops)
+
+#else /* CONFIG_PM */
+#define GLAMO_MCI_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+
+static struct platform_driver glamo_mci_driver = {
+	.probe  = glamo_mci_probe,
+	.remove = glamo_mci_remove,
+	.driver = {
+		.name	= "glamo-mci",
+		.owner	= THIS_MODULE,
+		.pm	= GLAMO_MCI_PM_OPS,
+	},
+};
+
+static int __init glamo_mci_init(void)
+{
+	platform_driver_register(&glamo_mci_driver);
+	return 0;
+}
+module_init(glamo_mci_init);
+
+static void __exit glamo_mci_exit(void)
+{
+	platform_driver_unregister(&glamo_mci_driver);
+}
+module_exit(glamo_mci_exit);
+
+MODULE_DESCRIPTION("Glamo MMC/SD Card Interface driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andy Green <andy@openmoko.com>");
diff --git a/drivers/mfd/glamo/glamo-regs.h b/drivers/mfd/glamo/glamo-regs.h
new file mode 100644
index 0000000..59848e1
--- /dev/null
+++ b/drivers/mfd/glamo/glamo-regs.h
@@ -0,0 +1,630 @@
+#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 {
+	/* b0 - b10 == refresh period, 1 -> 2048 clocks */
+	GLAMO_MEM_DRAM1_EN_GATE_CLK	= (1 << 11),
+	GLAMO_MEM_DRAM1_SELF_REFRESH	= (1 << 12),
+	GLAMO_MEM_DRAM1_EN_GATE_CKE	= (1 << 13),
+	GLAMO_MEM_DRAM1_EN_DRAM_REFRESH	= (1 << 14),
+	GLAMO_MEM_DRAM1_EN_MODEREG_SET	= (1 << 15),
+};
+
+enum glamo_reg_mem_dram2 {
+	GLAMO_MEM_DRAM2_DEEP_PWRDOWN	= (1 << 12),
+};
+
+enum glamo_irq_index {
+	GLAMO_IRQIDX_HOSTBUS	= 0,
+	GLAMO_IRQIDX_JPEG	= 1,
+	GLAMO_IRQIDX_MPEG	= 2,
+	GLAMO_IRQIDX_MPROC1	= 3,
+	GLAMO_IRQIDX_MPROC0	= 4,
+	GLAMO_IRQIDX_CMDQUEUE	= 5,
+	GLAMO_IRQIDX_2D		= 6,
+	GLAMO_IRQIDX_MMC	= 7,
+	GLAMO_IRQIDX_RISC	= 8,
+};
+
+enum glamo_irq {
+	GLAMO_IRQ_HOSTBUS	= (1 << GLAMO_IRQIDX_HOSTBUS),
+	GLAMO_IRQ_JPEG		= (1 << GLAMO_IRQIDX_JPEG),
+	GLAMO_IRQ_MPEG		= (1 << GLAMO_IRQIDX_MPEG),
+	GLAMO_IRQ_MPROC1	= (1 << GLAMO_IRQIDX_MPROC1),
+	GLAMO_IRQ_MPROC0	= (1 << GLAMO_IRQIDX_MPROC0),
+	GLAMO_IRQ_CMDQUEUE	= (1 << GLAMO_IRQIDX_CMDQUEUE),
+	GLAMO_IRQ_2D		= (1 << GLAMO_IRQIDX_2D),
+	GLAMO_IRQ_MMC		= (1 << GLAMO_IRQIDX_MMC),
+	GLAMO_IRQ_RISC		= (1 << GLAMO_IRQIDX_RISC),
+};
+
+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_basic_mmc {
+	/* set to disable CRC error rejection */
+	GLAMO_BASIC_MMC_DISABLE_CRC	= 0x0001,
+	/* enable completion interrupt */
+	GLAMO_BASIC_MMC_EN_COMPL_INT	= 0x0002,
+	/* stop MMC clock while enforced idle waiting for data from card */
+	GLAMO_BASIC_MMC_NO_CLK_RD_WAIT	= 0x0004,
+	/* 0 = 1-bit bus to card, 1 = use 4-bit bus (has to be negotiated) */
+	GLAMO_BASIC_MMC_EN_4BIT_DATA	= 0x0008,
+	/* enable 75K pullups on D3..D0 */
+	GLAMO_BASIC_MMC_EN_DATA_PUPS	= 0x0010,
+	/* enable 75K pullup on CMD */
+	GLAMO_BASIC_MMC_EN_CMD_PUP	= 0x0020,
+	/* IO drive strength 00=weak -> 11=strongest */
+	GLAMO_BASIC_MMC_EN_DR_STR0	= 0x0040,
+	GLAMO_BASIC_MMC_EN_DR_STR1	= 0x0080,
+	/* TCLK delay stage A, 0000 = 500ps --> 1111 = 8ns */
+	GLAMO_BASIC_MMC_EN_TCLK_DLYA0	= 0x0100,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYA1	= 0x0200,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYA2	= 0x0400,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYA3	= 0x0800,
+	/* TCLK delay stage B (cumulative), 0000 = 500ps --> 1111 = 8ns */
+	GLAMO_BASIC_MMC_EN_TCLK_DLYB0	= 0x1000,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYB1	= 0x2000,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYB2	= 0x4000,
+	GLAMO_BASIC_MMC_EN_TCLK_DLYB3	= 0x8000,
+};
+
+enum glamo_reg_stat1_mmc {
+	/* command "counter" (really: toggle) */
+	GLAMO_STAT1_MMC_CMD_CTR	= 0x8000,
+	/* engine is idle */
+	GLAMO_STAT1_MMC_IDLE	= 0x4000,
+	/* readback response is ready */
+	GLAMO_STAT1_MMC_RB_RRDY	= 0x0200,
+	/* readback data is ready */
+	GLAMO_STAT1_MMC_RB_DRDY	= 0x0100,
+	/* no response timeout */
+	GLAMO_STAT1_MMC_RTOUT	= 0x0020,
+	/* no data timeout */
+	GLAMO_STAT1_MMC_DTOUT	= 0x0010,
+	/* CRC error on block write */
+	GLAMO_STAT1_MMC_BWERR	= 0x0004,
+	/* CRC error on block read */
+	GLAMO_STAT1_MMC_BRERR	= 0x0002
+};
+
+enum glamo_reg_fire_mmc {
+	/* command "counter" (really: toggle)
+	 * the STAT1 register reflects this so you can ensure you don't look
+	 * at status for previous command
+	 */
+	GLAMO_FIRE_MMC_CMD_CTR	= 0x8000,
+	/* sets kind of response expected */
+	GLAMO_FIRE_MMC_RES_MASK	= 0x0700,
+	/* sets command type */
+	GLAMO_FIRE_MMC_TYP_MASK	= 0x00C0,
+	/* sets command class */
+	GLAMO_FIRE_MMC_CLS_MASK	= 0x000F,
+};
+
+enum glamo_fire_mmc_response_types {
+	GLAMO_FIRE_MMC_RSPT_R1	= 0x0000,
+	GLAMO_FIRE_MMC_RSPT_R1b	= 0x0100,
+	GLAMO_FIRE_MMC_RSPT_R2	= 0x0200,
+	GLAMO_FIRE_MMC_RSPT_R3	= 0x0300,
+	GLAMO_FIRE_MMC_RSPT_R4	= 0x0400,
+	GLAMO_FIRE_MMC_RSPT_R5	= 0x0500,
+};
+
+enum glamo_fire_mmc_command_types {
+	/* broadcast, no response */
+	GLAMO_FIRE_MMC_CMDT_BNR	= 0x0000,
+	/* broadcast, with response */
+	GLAMO_FIRE_MMC_CMDT_BR	= 0x0040,
+	/* addressed, no data */
+	GLAMO_FIRE_MMC_CMDT_AND	= 0x0080,
+	/* addressed, with data */
+	GLAMO_FIRE_MMC_CMDT_AD	= 0x00C0,
+};
+
+enum glamo_fire_mmc_command_class {
+	/* "Stream Read" */
+	GLAMO_FIRE_MMC_CC_STRR	= 0x0000,
+	/* Single Block Read */
+	GLAMO_FIRE_MMC_CC_SBR	= 0x0001,
+	/* Multiple Block Read With Stop */
+	GLAMO_FIRE_MMC_CC_MBRS	= 0x0002,
+	/* Multiple Block Read No Stop */
+	GLAMO_FIRE_MMC_CC_MBRNS	= 0x0003,
+	/* RESERVED for "Stream Write" */
+	GLAMO_FIRE_MMC_CC_STRW	= 0x0004,
+	/* "Stream Write" */
+	GLAMO_FIRE_MMC_CC_SBW	= 0x0005,
+	/* RESERVED for Multiple Block Write With Stop */
+	GLAMO_FIRE_MMC_CC_MBWS	= 0x0006,
+	/* Multiple Block Write No Stop */
+	GLAMO_FIRE_MMC_CC_MBWNS	= 0x0007,
+	/* STOP command */
+	GLAMO_FIRE_MMC_CC_STOP	= 0x0008,
+	/* Cancel on Running Command */
+	GLAMO_FIRE_MMC_CC_CANCL	= 0x0009,
+	/* "Basic Command" */
+	GLAMO_FIRE_MMC_CC_BASIC	= 0x000a,
+};
+
+/* these are offsets from the start of the MMC register region */
+enum glamo_register_mmc {
+	/* MMC command, b15..8 = cmd arg b7..0; b7..1 = CRC; b0 = end bit */
+	GLAMO_REG_MMC_CMD_REG1	= 0x00,
+	/* MMC command, b15..0 = cmd arg b23 .. 8 */
+	GLAMO_REG_MMC_CMD_REG2	= 0x02,
+	/* MMC command, b15=start, b14=transmission,
+	 * b13..8=cmd idx, b7..0=cmd arg b31..24
+	 */
+	GLAMO_REG_MMC_CMD_REG3	= 0x04,
+	GLAMO_REG_MMC_CMD_FIRE	= 0x06,
+	GLAMO_REG_MMC_CMD_RSP1	= 0x10,
+	GLAMO_REG_MMC_CMD_RSP2	= 0x12,
+	GLAMO_REG_MMC_CMD_RSP3	= 0x14,
+	GLAMO_REG_MMC_CMD_RSP4	= 0x16,
+	GLAMO_REG_MMC_CMD_RSP5	= 0x18,
+	GLAMO_REG_MMC_CMD_RSP6	= 0x1a,
+	GLAMO_REG_MMC_CMD_RSP7	= 0x1c,
+	GLAMO_REG_MMC_CMD_RSP8	= 0x1e,
+	GLAMO_REG_MMC_RB_STAT1	= 0x20,
+	GLAMO_REG_MMC_RB_BLKCNT	= 0x22,
+	GLAMO_REG_MMC_RB_BLKLEN	= 0x24,
+	GLAMO_REG_MMC_BASIC	= 0x30,
+	GLAMO_REG_MMC_RDATADS1	= 0x34,
+	GLAMO_REG_MMC_RDATADS2	= 0x36,
+	GLAMO_REG_MMC_WDATADS1	= 0x38,
+	GLAMO_REG_MMC_WDATADS2	= 0x3a,
+	GLAMO_REG_MMC_DATBLKCNT	= 0x3c,
+	GLAMO_REG_MMC_DATBLKLEN	= 0x3e,
+	GLAMO_REG_MMC_TIMEOUT	= 0x40,
+
+};
+
+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/include/linux/fb.h b/include/linux/fb.h
index c10163b..71f714a 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -134,6 +134,7 @@ struct dentry;
 #define FB_ACCEL_NEOMAGIC_NM2360 97	/* NeoMagic NM2360              */
 #define FB_ACCEL_NEOMAGIC_NM2380 98	/* NeoMagic NM2380              */
 #define FB_ACCEL_PXA3XX		 99	/* PXA3xx			*/
+#define FB_ACCEL_GLAMO		100	/* Smedia Glamo 3362            */
 
 #define FB_ACCEL_SAVAGE4        0x80	/* S3 Savage4                   */
 #define FB_ACCEL_SAVAGE3D       0x81	/* S3 Savage3D                  */
diff --git a/include/linux/glamofb.h b/include/linux/glamofb.h
new file mode 100644
index 0000000..5f9fab5
--- /dev/null
+++ b/include/linux/glamofb.h
@@ -0,0 +1,35 @@
+#ifndef _LINUX_GLAMOFB_H
+#define _LINUX_GLAMOFB_H
+
+#include <linux/fb.h>
+
+#ifdef __KERNEL__
+
+struct glamo_core;
+struct glamofb_handle;
+
+struct glamo_fb_platform_data {
+    int width, height;
+
+    int num_modes;
+    struct fb_videomode *modes;
+
+    struct glamo_core *core;
+};
+
+int glamofb_cmd_mode(struct glamofb_handle *gfb, int on);
+int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val);
+
+#ifdef CONFIG_MFD_GLAMO
+void glamo_lcm_reset(struct platform_device *pdev, int level);
+#else
+#define glamo_lcm_reset(...) do {} while (0)
+#endif
+
+#endif
+
+#define GLAMOFB_ENGINE_ENABLE _IOW('F', 0x1, __u32)
+#define GLAMOFB_ENGINE_DISABLE _IOW('F', 0x2, __u32)
+#define GLAMOFB_ENGINE_RESET _IOW('F', 0x3, __u32)
+
+#endif
diff --git a/include/linux/mfd/glamo.h b/include/linux/mfd/glamo.h
new file mode 100644
index 0000000..529d4f0
--- /dev/null
+++ b/include/linux/mfd/glamo.h
@@ -0,0 +1,52 @@
+#ifndef __GLAMO_MFD_H
+#define __GLAMO_MFD_H
+
+struct glamo_core;
+struct glamo_spigpio_platform_data;
+struct glamo_fb_platform_data;
+
+struct glamo_mmc_platform_data {
+	int	(*glamo_mmc_use_slow)(void);
+
+	struct glamo_core *core;
+};
+
+struct glamo_gpio_platform_data {
+	int base;
+	void (*registered)(struct device *dev);
+};
+
+struct glamo_platform_data {
+	struct glamo_fb_platform_data	*fb_data;
+	struct glamo_mmc_platform_data	*mmc_data;
+	struct glamo_gpio_platform_data	*gpio_data;
+
+	unsigned int osci_clock_rate;
+
+	void (*glamo_external_reset)(int);
+};
+
+enum glamo_engine {
+	GLAMO_ENGINE_CAPTURE = 0,
+	GLAMO_ENGINE_ISP = 1,
+	GLAMO_ENGINE_JPEG = 2,
+	GLAMO_ENGINE_MPEG_ENC = 3,
+	GLAMO_ENGINE_MPEG_DEC = 4,
+	GLAMO_ENGINE_LCD = 5,
+	GLAMO_ENGINE_CMDQ = 6,
+	GLAMO_ENGINE_2D = 7,
+	GLAMO_ENGINE_3D = 8,
+	GLAMO_ENGINE_MMC = 9,
+	GLAMO_ENGINE_MICROP0 = 10,
+	GLAMO_ENGINE_RISC = 11,
+	GLAMO_ENGINE_MICROP1_MPEG_ENC = 12,
+	GLAMO_ENGINE_MICROP1_MPEG_DEC = 13,
+#if 0
+	GLAMO_ENGINE_H264_DEC = 14,
+	GLAMO_ENGINE_RISC1 = 15,
+	GLAMO_ENGINE_SPI = 16,
+#endif
+	__NUM_GLAMO_ENGINES
+};
+
+#endif
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 10 Oct 2009 22:33:51 +0000 (+0200)
Subject: s3c24xx: Add support for board IRQs
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=2536d500962c564120a1e617d536da7af970f1d6

s3c24xx: Add support for board IRQs

Some boards have a need for a set of extra IRQ numbers, for example some
multifunction devices which do irq demultiplexing require them.
This patch adds S3C2410_BOARD_NR_IRQS which specifies the number of extra board
IRQs. Board specific code would use S3C2410_BOARD_IRQ_START to get the number of
it's first irq.

Since it is possible to support a multiple boards with a single kernel and
there is no easy way to set a CONFIG option to multiple values and only use the
maximum each board which needs board IRQs has do be explicitly added to irqs.h

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---

From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sat, 10 Oct 2009 23:23:35 +0000 (+0200)
Subject: s3c24xx: Add number of board irqs for the gta02
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=8dd3b11c092dff5aa3892c1e12cbda799fd37891

s3c24xx: Add number of board irqs for the gta02

The gta02 uses the glamo mfd driver which requires 9 board irqs and the pcf50633
mfd driver which requires 40 irqs.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---

From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sun, 4 Apr 2010 18:49:19 +0000 (+0200)
Subject: gta02: Configure pcf50633 gpios.
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=e46f39af3ced84382ec61fd0ca2d23d444331292

gta02: Configure pcf50633 gpios.
---

From: Lars-Peter Clausen <lars@metafoo.de>
Date: Sun, 4 Apr 2010 18:59:26 +0000 (+0200)
Subject: gta02: Add glamo device
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=323d14d9c5f8a33585d535815533738ae3e6e12c

gta02: Add glamo device
---

diff -r 6ca4f802a041 arch/arm/mach-s3c2410/include/mach/irqs.h
--- a/arch/arm/mach-s3c2410/include/mach/irqs.h	Mon May 31 23:14:47 2010 +0200
+++ b/arch/arm/mach-s3c2410/include/mach/irqs.h	Tue Jun 01 00:10:42 2010 +0200
@@ -153,9 +153,9 @@
 #define IRQ_S3C2443_AC97	S3C2410_IRQSUB(28)
 
 #ifdef CONFIG_CPU_S3C2443
-#define NR_IRQS (IRQ_S3C2443_AC97+1)
+#define S3C2410_NR_INTERNAL_IRQS (IRQ_S3C2443_AC97+1)
 #else
-#define NR_IRQS (IRQ_S3C2440_AC97+1)
+#define S3C2410_NR_INTERNAL_IRQS (IRQ_S3C2440_AC97+1)
 #endif
 
 /* compatibility define. */
@@ -173,4 +173,22 @@
 /* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
 #define FIQ_START		IRQ_EINT0
 
+/* Board specific IRQs
+ * If your board needs a extra set of IRQ numbers add it to the list here.
+ * Make sure that the numbers are kept in descending order, so if support for
+ * multiple boards is compiled in the maximum will be used and there are enough
+ * IRQ numbers available for each board.
+ */
+
+#if defined(CONFIG_MACH_NEO1973_GTA02)
+#define IRQ_BOARD_NR (9 + 40)
+#else
+#define IRQ_BOARD_NR 0
+#endif
+
+#define IRQ_BOARD_START S3C2410_NR_INTERNAL_IRQS
+#define IRQ_BOARD_END	(IRQ_BOARD_START + IRQ_BOARD_NR)
+
+#define NR_IRQS			IRQ_BOARD_END
+
 #endif /* __ASM_ARCH_IRQ_H */
diff -r 6ca4f802a041 arch/arm/mach-s3c2440/include/mach/gta02.h
--- a/arch/arm/mach-s3c2442/include/mach/gta02.h	Mon May 31 23:14:47 2010 +0200
+++ b/arch/arm/mach-s3c2442/include/mach/gta02.h	Tue Jun 01 00:10:42 2010 +0200
@@ -79,6 +79,11 @@
 #define GTA02_PCB_ID2_0		S3C2410_GPD(3)
 #define GTA02_PCB_ID2_1		S3C2410_GPD(4)
 
+#define GTA02_GPIO_GLAMO_BASE S3C_GPIO_END
+#define GTA02_GPIO_GLAMO(x) (GTA02_GPIO_GLAMO_BASE + (x))
+#define GTA02_GPIO_PCF_BASE (GTA02_GPIO_GLAMO_BASE + 32)
+#define GTA02_GPIO_PCF(x) (GTA02_GPIO_PCF_BASE + (x))
+
 int gta02_get_pcb_revision(void);
 
 #endif /* _GTA02_H */
diff -r 6ca4f802a041 arch/arm/mach-s3c2440/mach-gta02.c
--- a/arch/arm/mach-s3c2442/mach-gta02.c	Mon May 31 23:14:47 2010 +0200
+++ b/arch/arm/mach-s3c2442/mach-gta02.c	Tue Jun 01 00:10:42 2010 +0200
@@ -38,6 +38,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
 
 #include <linux/mmc/host.h>
 
@@ -87,6 +88,9 @@
 #include <plat/gpio-cfg.h>
 #include <plat/iic.h>
 
+#include <linux/glamofb.h>
+#include <linux/mfd/glamo.h>
+
 static struct pcf50633 *gta02_pcf;
 
 /*
@@ -149,6 +153,125 @@
 	},
 };
 
+/*
+ * we crank down SD Card clock dynamically when GPS is powered
+ */
+
+static int gta02_glamo_mci_use_slow(void)
+{
+	//We don't have GPS driver, so, it should always be off
+	return 0; //gta02_pm_gps_is_on();
+}
+
+static void gta02_glamo_external_reset(int level)
+{
+	s3c2410_gpio_setpin(GTA02_GPIO_3D_RESET, level);
+	s3c2410_gpio_cfgpin(GTA02_GPIO_3D_RESET, S3C2410_GPIO_OUTPUT);
+}
+
+struct spi_gpio_platform_data spigpio_platform_data = {
+	.sck = GTA02_GPIO_GLAMO(10),
+	.mosi = GTA02_GPIO_GLAMO(11),
+	.miso = GTA02_GPIO_GLAMO(5),
+	.num_chipselect = 1,
+};
+
+static struct platform_device spigpio_device = {
+	.name = "spi_gpio",
+	.id   = 2,
+	.dev = {
+		.platform_data = &spigpio_platform_data,
+	},
+};
+
+static void gta02_glamo_registered(struct device *dev)
+{
+	spigpio_device.dev.parent = dev;
+	platform_device_register(&spigpio_device);
+}
+
+static struct fb_videomode gta02_glamo_modes[] = {
+	{
+		.name = "480x640",
+		.xres = 480,
+		.yres = 640,
+		.pixclock	= 40816,
+		.left_margin	= 8,
+		.right_margin	= 16,
+		.upper_margin	= 2,
+		.lower_margin	= 16,
+		.hsync_len	= 8,
+		.vsync_len	= 2,
+		.vmode = FB_VMODE_NONINTERLACED,
+	}, {
+		.name = "240x320",
+		.xres = 240,
+		.yres = 320,
+		.pixclock	= 40816,
+		.left_margin	= 8,
+		.right_margin	= 16,
+		.upper_margin	= 2,
+		.lower_margin	= 16,
+		.hsync_len	= 8,
+		.vsync_len	= 2,
+		.vmode = FB_VMODE_NONINTERLACED,
+	}
+};
+
+static struct glamo_fb_platform_data gta02_glamo_fb_pdata = {
+	.width  = 43,
+	.height = 58,
+
+	.num_modes = ARRAY_SIZE(gta02_glamo_modes),
+	.modes = gta02_glamo_modes,
+};
+
+static struct glamo_mmc_platform_data gta02_glamo_mmc_pdata = {
+	.glamo_mmc_use_slow = gta02_glamo_mci_use_slow,
+};
+
+static struct glamo_gpio_platform_data gta02_glamo_gpio_pdata = {
+	.base = GTA02_GPIO_GLAMO_BASE,
+	.registered = gta02_glamo_registered,
+};
+
+static struct glamo_platform_data gta02_glamo_pdata = {
+	.fb_data    = &gta02_glamo_fb_pdata,
+	.mmc_data   = &gta02_glamo_mmc_pdata,
+	.gpio_data  = &gta02_glamo_gpio_pdata,
+
+	.osci_clock_rate = 32768,
+
+	.glamo_external_reset = gta02_glamo_external_reset,
+};
+
+static struct resource gta02_glamo_resources[] = {
+	[0] = {
+		.start	= S3C2410_CS1,
+		.end	= S3C2410_CS1 + 0x1000000 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= GTA02_IRQ_3D,
+		.end	= GTA02_IRQ_3D,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= IRQ_BOARD_START,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device gta02_glamo_dev = {
+	.name		= "glamo3362",
+	.num_resources	= ARRAY_SIZE(gta02_glamo_resources),
+	.resource	= gta02_glamo_resources,
+	.dev		= {
+		.platform_data	= &gta02_glamo_pdata,
+	},
+};
+
+
 #ifdef CONFIG_CHARGER_PCF50633
 /*
  * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
@@ -254,6 +377,13 @@
 	"battery",
 };
 
+static struct regulator_consumer_supply hcldo_consumers[] = {
+	{
+		.dev = &gta02_glamo_dev.dev,
+		.supply = "SD_3V3",
+	},
+};
+
 struct pcf50633_platform_data gta02_pcf_pdata = {
 	.resumers = {
 		[0] =	PCF50633_INT1_USBINS |
@@ -313,6 +445,8 @@
 				.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
 				.always_on = 1,
 			},
+			.num_consumer_supplies = ARRAY_SIZE(hcldo_consumers),
+			.consumer_supplies = hcldo_consumers,
 		},
 		[PCF50633_REGULATOR_LDO1] = {
 			.constraints = {
@@ -574,6 +708,7 @@
 	&s3c24xx_pwm_device,
 	&s3c_device_iis,
 	&s3c_device_i2c0,
+	&gta02_glamo_dev,
 };
 
 /* These guys DO need to be children of PMU. */
@@ -630,6 +765,11 @@
 
 	i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
 
+/*TODO: http://git.openmoko.org/?p=kernel.git;a=commitdiff;h=47827311
+	spi_register_board_info(gta02_spi_board_info,
+				ARRAY_SIZE(gta02_spi_board_info));
+*/
+
 	platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
 	pm_power_off = gta02_poweroff;
 }
Description: register glamo-mci and glamo-fb so it can be auto-loaded by udev
Author: Thibaut Girka <thib@sitedethib.com>
Forwarded: https://docs.openmoko.org/trac/ticket/2340

diff -r 96a74d55c156 drivers/mfd/glamo/glamo-fb.c
--- a/drivers/mfd/glamo/glamo-fb.c	Thu Jun 03 08:53:48 2010 +0200
+++ b/drivers/mfd/glamo/glamo-fb.c	Thu Jun 03 08:54:28 2010 +0200
@@ -980,3 +980,4 @@
 MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
 MODULE_DESCRIPTION("Smedia Glamo 336x/337x framebuffer driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:glamo-fb");
diff -r 96a74d55c156 drivers/mfd/glamo/glamo-mci.c
--- a/drivers/mfd/glamo/glamo-mci.c	Thu Jun 03 08:53:48 2010 +0200
+++ b/drivers/mfd/glamo/glamo-mci.c	Thu Jun 03 08:54:28 2010 +0200
@@ -1021,3 +1021,4 @@
 MODULE_DESCRIPTION("Glamo MMC/SD Card Interface driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Andy Green <andy@openmoko.com>");
+MODULE_ALIAS("platform:glamo-mci");
##
## file: arch/arm/Kconfig
##
## choice: ARM system type
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
# CONFIG_ARCH_IXP23XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
# CONFIG_ARCH_KIRKWOOD is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
# CONFIG_ARCH_ORION5X is not set
# CONFIG_ARCH_MMP is not set
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_W90X900 is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_MSM is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
CONFIG_ARCH_S3C2410=y
# CONFIG_ARCH_S3C64XX is not set
# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
# CONFIG_ARCH_BCMRING is not set
## end choice
CONFIG_UACCESS_WITH_MEMCPY=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE=""
# CONFIG_XIP_KERNEL is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y

##
## file: arch/arm/mach-s3c2410/Kconfig
##
# CONFIG_ARCH_SMDK2410 is not set
# CONFIG_ARCH_H1940 is not set
# CONFIG_MACH_N30 is not set
# CONFIG_ARCH_BAST is not set
# CONFIG_MACH_OTOM is not set
# CONFIG_MACH_AML_M5900 is not set
# CONFIG_MACH_TCT_HAMMER is not set
# CONFIG_MACH_VR1000 is not set
CONFIG_MACH_QT2410=y

##
## file: arch/arm/mach-s3c2412/Kconfig
##
# CONFIG_MACH_JIVE is not set
# CONFIG_MACH_SMDK2413 is not set
# CONFIG_MACH_SMDK2412 is not set
# CONFIG_MACH_VSTMS is not set

##
## file: arch/arm/mach-s3c2440/Kconfig
##
# CONFIG_MACH_ANUBIS is not set
# CONFIG_MACH_OSIRIS is not set
# CONFIG_MACH_RX3715 is not set
CONFIG_ARCH_S3C2440=y
# CONFIG_MACH_NEXCODER_2440 is not set
CONFIG_SMDK2440_CPU2440=y
# CONFIG_MACH_AT2440EVB is not set
# CONFIG_MACH_MINI2440 is not set

##
## file: arch/arm/mach-s3c2442/Kconfig
##
CONFIG_SMDK2440_CPU2442=y
CONFIG_MACH_NEO1973_GTA02=y

##
## file: arch/arm/mach-s3c2443/Kconfig
##
# CONFIG_MACH_SMDK2443 is not set

##
## file: arch/arm/mm/Kconfig
##
CONFIG_CPU_ARM920T=y
CONFIG_ARM_THUMB=y
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set

##
## file: arch/arm/plat-s3c/Kconfig
##
# CONFIG_S3C_BOOT_WATCHDOG is not set
# CONFIG_S3C_BOOT_ERROR_RESET is not set
CONFIG_S3C_BOOT_UART_FORCE_FIFO=y
# CONFIG_S3C2410_PM_DEBUG is not set
# CONFIG_S3C2410_PM_CHECK is not set
CONFIG_S3C_LOWLEVEL_UART_PORT=2
CONFIG_S3C_GPIO_SPACE=0

##
## file: arch/arm/plat-s3c24xx/Kconfig
##
CONFIG_S3C24XX_PWM=y
CONFIG_S3C2410_DMA=y
# CONFIG_S3C2410_DMA_DEBUG is not set
CONFIG_S3C24XX_ADC=y

##
## file: drivers/ata/Kconfig
##
# CONFIG_ATA is not set

##
## file: drivers/bluetooth/Kconfig
##
CONFIG_BT_HCIBTUSB=m
CONFIG_BT_HCIBTSDIO=m
# CONFIG_BT_HCIUART is not set
CONFIG_BT_HCIBCM203X=m
CONFIG_BT_HCIBPA10X=m
CONFIG_BT_HCIBFUSB=m
CONFIG_BT_HCIVHCI=m
CONFIG_BT_MRVL=m
CONFIG_BT_MRVL_SDIO=m

##
## file: drivers/char/Kconfig
##
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set

##
## file: drivers/char/ipmi/Kconfig
##
# CONFIG_IPMI_HANDLER is not set

##
## file: drivers/char/tpm/Kconfig
##
# CONFIG_TCG_TPM is not set

##
## file: drivers/cpuidle/Kconfig
##
CONFIG_CPU_IDLE=y

##
## file: drivers/dma/Kconfig
##
CONFIG_DMADEVICES=y

##
## file: drivers/gpio/Kconfig
##
CONFIG_GPIO_SYSFS=y

##
## file: drivers/i2c/Kconfig
##
CONFIG_I2C=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set

##
## file: drivers/i2c/busses/Kconfig
##
# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
CONFIG_I2C_S3C2410=y
# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_TINY_USB is not set
# CONFIG_I2C_PCA_PLATFORM is not set
# CONFIG_I2C_STUB is not set

##
## file: drivers/ide/Kconfig
##
# CONFIG_IDE is not set

##
## file: drivers/input/gameport/Kconfig
##
CONFIG_GAMEPORT=m

##
## file: drivers/input/joystick/Kconfig
##
CONFIG_INPUT_JOYSTICK=y

##
## file: drivers/input/keyboard/Kconfig
##
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_GPIO=m

##
## file: drivers/input/misc/Kconfig
##
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=m
CONFIG_INPUT_PCF50633_PMU=m

##
## file: drivers/input/mouse/Kconfig
##
CONFIG_INPUT_MOUSE=y

##
## file: drivers/input/serio/Kconfig
##
CONFIG_SERIO=m
CONFIG_SERIO_SERPORT=m
# CONFIG_SERIO_RAW is not set

##
## file: drivers/input/tablet/Kconfig
##
CONFIG_INPUT_TABLET=y
CONFIG_TABLET_USB_ACECAD=m
CONFIG_TABLET_USB_AIPTEK=m
CONFIG_TABLET_USB_GTCO=m
CONFIG_TABLET_USB_KBTAB=m
CONFIG_TABLET_USB_WACOM=m

##
## file: drivers/input/touchscreen/Kconfig
##
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_ADS7846 is not set
# CONFIG_TOUCHSCREEN_AD7877 is not set
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
# CONFIG_TOUCHSCREEN_W90X900 is not set

##
## file: drivers/isdn/Kconfig
##
# CONFIG_ISDN is not set

##
## file: drivers/leds/Kconfig
##
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_S3C24XX=y
# CONFIG_LEDS_PCA9532 is not set
# CONFIG_LEDS_GPIO is not set
# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_DAC124S085 is not set
# CONFIG_LEDS_PWM is not set
# CONFIG_LEDS_BD2802 is not set
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
CONFIG_LEDS_TRIGGER_BACKLIGHT=m
# CONFIG_LEDS_TRIGGER_GPIO is not set
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y

##
## file: drivers/mfd/Kconfig
##
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
# CONFIG_TWL4030_CORE is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
CONFIG_MFD_PCF50633=y
# CONFIG_MFD_MC13783 is not set
CONFIG_PCF50633_ADC=y
CONFIG_PCF50633_GPIO=y
# CONFIG_AB3100_CORE is not set
# CONFIG_EZX_PCAP is not set


##
## file: drivers/mmc/Kconfig
##
CONFIG_MMC=m

##
## file: drivers/mmc/card/Kconfig
##
CONFIG_MMC_BLOCK=m

##
## file: drivers/mmc/host/Kconfig
##
## choice: Atmel SD/MMC Driver
# CONFIG_MMC_AT91 is not set
# CONFIG_MMC_ATMELMCI is not set
## end choice
# CONFIG_MMC_SPI is not set
CONFIG_MMC_S3C=y
# CONFIG_MMC_S3C_HW_SDIO_IRQ is not set
## choice: Samsung S3C SD/MMC transfer code
CONFIG_MMC_S3C_PIO=y
# CONFIG_MMC_S3C_DMA is not set
# CONFIG_MMC_S3C_PIODMA is not set
## end choice

##
## file: drivers/mtd/Kconfig
##
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_TESTS is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
# CONFIG_MTD_AR7_PARTS is not set
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
# CONFIG_MTD_OOPS is not set

##
## file: drivers/mtd/chips/Kconfig
##
CONFIG_MTD_CFI=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
## choice: Flash cmd/query data swapping
CONFIG_MTD_CFI_NOSWAP=y
# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
## end choice
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
CONFIG_MTD_CFI_I4=y
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_OTP is not set
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=m
CONFIG_MTD_CFI_STAA=m
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set

##
## file: drivers/mtd/devices/Kconfig
##
# CONFIG_MTD_DATAFLASH is not set
# CONFIG_MTD_M25P80 is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLOCK2MTD is not set
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set

##
## file: drivers/mtd/maps/Kconfig
##
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_PHYSMAP_COMPAT is not set
# CONFIG_MTD_ARM_INTEGRATOR is not set
# CONFIG_MTD_IMPA7 is not set
# CONFIG_MTD_PLATRAM is not set

##
## file: drivers/mtd/nand/Kconfig
##
CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_S3C2410=y
# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
CONFIG_MTD_NAND_S3C2410_HWECC=y
# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
# CONFIG_MTD_ALAUDA is not set

##
## file: drivers/mtd/onenand/Kconfig
##
# CONFIG_MTD_ONENAND is not set

##
## file: drivers/mtd/ubi/Kconfig
##
CONFIG_MTD_UBI=y

##
## file: drivers/net/phy/Kconfig
##
# CONFIG_PHYLIB is not set

##
## file: drivers/pcmcia/Kconfig
##
# CONFIG_PCCARD is not set

##
## file: drivers/power/Kconfig
##
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
CONFIG_PDA_POWER=y
CONFIG_APM_POWER=y
# CONFIG_BATTERY_DS2760 is not set
# CONFIG_BATTERY_DS2782 is not set
CONFIG_BATTERY_BQ27x00=y
# CONFIG_BATTERY_MAX17040 is not set
CONFIG_CHARGER_PCF50633=y

##
## file: drivers/regulator/Kconfig
##
CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_REGULATOR_MAX1586 is not set
CONFIG_REGULATOR_PCF50633=y
# CONFIG_REGULATOR_LP3971 is not set
# CONFIG_REGULATOR_TPS65023 is not set
# CONFIG_REGULATOR_TPS6507X is not set

##
## file: drivers/rtc/Kconfig
##
CONFIG_RTC_DRV_PCF50633=y
CONFIG_RTC_DRV_S3C=m

##
## file: drivers/scsi/Kconfig
##
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set

##
## file: drivers/serial/Kconfig
##
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_SAMSUNG=y
# CONFIG_SERIAL_SAMSUNG_DEBUG is not set
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
CONFIG_SERIAL_S3C2410=y
CONFIG_SERIAL_S3C2440=y
# CONFIG_SERIAL_MAX3100 is not set

##
## file: drivers/spi/Kconfig
##
CONFIG_SPI_GPIO=y
# CONFIG_SPI_S3C24XX is not set
CONFIG_SPI_S3C24XX_GPIO=y

##
## file: drivers/ssb/Kconfig
##
# CONFIG_SSB is not set

##
## file: drivers/usb/Kconfig
##
CONFIG_USB_SUPPORT=y
CONFIG_USB=m

##
## file: drivers/usb/gadget/Kconfig
##
CONFIG_USB_GADGET=y
# CONFIG_USB_GADGET_DEBUG is not set
# CONFIG_USB_GADGET_DEBUG_FILES is not set
# CONFIG_USB_GADGET_DEBUG_FS is not set
CONFIG_USB_GADGET_VBUS_DRAW=500
## choice: USB Peripheral Controller
# CONFIG_USB_GADGET_AT91 is not set
# CONFIG_USB_GADGET_ATMEL_USBA is not set
# CONFIG_USB_GADGET_FSL_USB2 is not set
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_OTG is not set
# CONFIG_USB_GADGET_PXA25X is not set
# CONFIG_USB_GADGET_R8A66597 is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
CONFIG_USB_GADGET_S3C2410=y
# CONFIG_USB_S3C2410_DEBUG is not set
# CONFIG_USB_GADGET_MUSB_HDRC is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
# CONFIG_USB_GADGET_CI13XXX is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
## end choice
## choice: USB Gadget Drivers
# CONFIG_USB_ZERO is not set
# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
# CONFIG_USB_ETH_EEM is not set
CONFIG_USB_GADGETFS=m
CONFIG_USB_FILE_STORAGE=m
# CONFIG_USB_FILE_STORAGE_TEST is not set
CONFIG_USB_G_SERIAL=m
CONFIG_USB_MIDI_GADGET=m
# CONFIG_USB_G_PRINTER is not set
CONFIG_USB_CDC_COMPOSITE=m
## end choice

##
## file: drivers/usb/host/Kconfig
##
# CONFIG_USB_C67X00_HCD is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_U132_HCD is not set
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HWA_HCD is not set

##
## file: drivers/video/Kconfig
##
CONFIG_VIDEO_OUTPUT_CONTROL=m
CONFIG_FB=m
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_FOREIGN_ENDIAN is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_UVESA is not set
# CONFIG_FB_S1D13XXX is not set
CONFIG_FB_S3C2410=m
# CONFIG_FB_S3C2410_DEBUG is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_BROADSHEET is not set

##
## file: drivers/video/backlight/Kconfig
##
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
# CONFIG_LCD_LMS283GF05 is not set
CONFIG_LCD_LTV350QV=y
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
# CONFIG_LCD_PLATFORM is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
# CONFIG_BACKLIGHT_PWM is not set


##
## file: drivers/video/console/Kconfig
##
# CONFIG_VGA_CONSOLE is not set

##
## file: drivers/video/display/Kconfig
##
CONFIG_DISPLAY_SUPPORT=y

##
## file: drivers/watchdog/Kconfig
##
CONFIG_S3C2410_WATCHDOG=m

##
## file: fs/jffs2/Kconfig
##
CONFIG_JFFS2_FS=y

##
## file: fs/ubifs/Kconfig
##
CONFIG_UBIFS_FS=y

##
## file: kernel/power/Kconfig
##
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_APM_EMULATION=y
CONFIG_PM_RUNTIME=y

##
## file: kernel/Kconfig.preempt
##
## choice: Preemption Model
# CONFIG_PREEMPT is not set
## end choice

##
## file: mm/Kconfig
##
## choice: Memory model
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
## end choice

##
## file: sound/arm/Kconfig
##
CONFIG_SND_ARM=y

##
## file: sound/soc/Kconfig
##
CONFIG_SND_SOC=m

##
## file: sound/soc/s3c24xx/Kconfig
##
CONFIG_SND_S3C24XX_SOC=m
# CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753 is not set
# CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650 is not set
# CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X is not set
# CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 is not set
# CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES is not set

## Enable glamo driver
CONFIG_MFD_GLAMO=y
CONFIG_MFD_GLAMO_MCI=m

# Framebuffer (not that important for now)
CONFIG_MFD_GLAMO_FB=m

Attachment: signature.asc
Description: Ceci est une partie de message =?ISO-8859-1?Q?num=E9riquement?= =?ISO-8859-1?Q?_sign=E9e?=


Reply to: