r2349 - trunk/src/target/kernel/patches

laforge at sita.openmoko.org laforge at sita.openmoko.org
Wed Jun 27 18:11:48 CEST 2007


Author: laforge
Date: 2007-06-27 18:11:38 +0200 (Wed, 27 Jun 2007)
New Revision: 2349

Modified:
   trunk/src/target/kernel/patches/smedia-glamo.patch
Log:
continued smedia glamo framebuffer driver development to a point where it
actually has working VGA output on the GTA02


Modified: trunk/src/target/kernel/patches/smedia-glamo.patch
===================================================================
--- trunk/src/target/kernel/patches/smedia-glamo.patch	2007-06-27 11:54:41 UTC (rev 2348)
+++ trunk/src/target/kernel/patches/smedia-glamo.patch	2007-06-27 16:11:38 UTC (rev 2349)
@@ -2,7 +2,7 @@
 ===================================================================
 --- linux-2.6.21.3-moko.orig/drivers/video/Kconfig
 +++ linux-2.6.21.3-moko/drivers/video/Kconfig
-@@ -1633,6 +1633,32 @@
+@@ -1633,6 +1633,38 @@
  	  The default value can be overridden on the kernel command line
  	  using the "ps3fb" option (e.g. "ps3fb=9M");
  
@@ -24,14 +24,20 @@
 +
 +	  If unsure, say N.
 +
-+config GLAMO_SPI
-+       bool "Enable SPI Support"
++config GLAMO_SPI_GPIO
++       bool "Glamo GPIO SPI bitbang support"
 +       depends on GLAMO
 +       help
-+         Enable a bitbanging SPI adapter driver for the Smedia Glamo. This
-+	 SPI interface is frequently used to interconnect the LCM control
-+	 interface.
++         Enable a bitbanging SPI adapter driver for the Smedia Glamo.
 +
++config FB_GLAMO_SPI
++       bool "Glamo LCM control channel SPI support"
++       depends on FB_GLAMO
++       help
++         Enable a bitbanging SPI adapter driver for the Smedia Glamo LCM
++	 control channel.  This SPI interface is frequently used to
++	 interconnect the LCM control interface.
++
  config FB_VIRTUAL
  	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
  	depends on FB
@@ -51,22 +57,23 @@
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/drivers/video/glamo/Makefile
-@@ -0,0 +1,10 @@
+@@ -0,0 +1,11 @@
 +#
 +# Makefile for the Smedia Glamo framebuffer driver
 +#
 +
-+obj-$(CONFIG_GLAMO)	+= glamo-core.o
-+obj-$(CONFIG_FB_GLAMO)	+= glamofb.o
++obj-$(CONFIG_GLAMO)		+= glamo-core.o glamo-gpio.o
++obj-$(CONFIG_GLAMO_SPI)		+= glamo-spi.o
++obj-$(CONFIG_GLAMO_SPI_GPIO) 	+= glamo-spi-gpio.o
 +
-+glamofb-objs		:= glamo-fb.o
++obj-$(CONFIG_FB_GLAMO)		+= glamo-fb.o
++obj-$(CONFIG_FB_GLAMO_SPI)	+= glamo-lcm-spi.o
 +
-+obj-$(CONFIG_GLAMO_SPI)	+= glamo-spi.o
 Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-regs.h
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-regs.h
-@@ -0,0 +1,457 @@
+@@ -0,0 +1,466 @@
 +#ifndef _GLAMO_REGS_H
 +#define _GLAMO_REGS_H
 +
@@ -166,8 +173,8 @@
 +	GLAMO_REG_DFT_GEN3	= 0x0074,
 +	GLAMO_REG_DFT_GEN4	= 0x0076,
 +
-+	GLAMO_REG_PLL_GEN6	= 0x01e0,
-+	GLAMO_REG_PLL_GEN7	= 0x01f0,
++	GLAMO_REG_DFT_GEN5	= 0x01e0,
++	GLAMO_REG_DFT_GEN6	= 0x01f0,
 +};
 +
 +#define GLAMO_REG_HOSTBUS(x)	(GLAMO_REGOFS_HOSTBUS-2+(x*2))
@@ -209,6 +216,15 @@
 +
 +#define GLAMO_MEM_TYPE_MASK	0x03
 +
++enum glamo_reg_mem_dram1 {
++	GLAMO_MEM_DRAM1_EN_SDRAM_CLK	= (1 << 11),
++	GLAMO_MEM_DRAM1_SELF_REFRESH	= (1 << 12),
++};
++
++enum glamo_reg_mem_dram2 {
++	GLAMO_MEM_DRAM2_DEEP_PWRDOWN	= (1 << 12),
++};
++
 +enum glamo_irq {
 +	GLAMO_IRQ_HOSTBUS	= 0x0001,
 +	GLAMO_IRQ_JPEG		= 0x0002,
@@ -524,257 +540,11 @@
 +};
 +
 +#endif /* _GLAMO_REGS_H */
-Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-spi.c
-===================================================================
---- /dev/null
-+++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-spi.c
-@@ -0,0 +1,241 @@
-+/*
-+ * Copyright (C) 2007 OpenMoko, Inc.
-+ * Author: Harald Welte <laforge at openmoko.org>
-+ *
-+ * Smedia Glamo GPIO based SPI driver
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This driver currently only implements a minimum subset of the hardware
-+ * features, esp. those features that are required to drive the jbt6k74
-+ * LCM controller asic in the TD028TTEC1 LCM.
-+ *
-+*/
-+
-+#define DEBUG
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/spinlock.h>
-+#include <linux/workqueue.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spi_bitbang.h>
-+#include <linux/spi/glamo.h>
-+
-+#include <linux/glamofb.h>
-+
-+#include <asm/hardware.h>
-+
-+#include "glamo-core.h"
-+#include "glamo-regs.h"
-+
-+struct glamo_spi {
-+	struct spi_bitbang	bitbang;
-+	struct spi_master	*master;
-+	struct glamo_spi_info	*info;
-+	struct device		*dev;
-+};
-+
-+static inline struct glamo_spi *to_gs(struct spi_device *spi)
-+{
-+	return spi->controller_data;
-+}
-+
-+static int glamo_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
-+{
-+	struct glamo_spi *gs = to_gs(spi);
-+	unsigned int bpw;
-+
-+	bpw = t ? t->bits_per_word : spi->bits_per_word;
-+
-+	if (bpw != 9 && bpw != 8) {
-+		dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
-+		return -EINVAL;
-+	}
-+
-+	return 0;
-+}
-+
-+static void glamo_spi_chipsel(struct spi_device *spi, int value)
-+{
-+#if 0
-+	struct glamo_spi *gs = to_gs(spi);
-+
-+	dev_dbg(&spi->dev, "chipsel %d: spi=%p, gs=%p, info=%p, handle=%p\n",
-+		value, spi, gs, gs->info, gs->info->glamofb_handle);
-+
-+	glamofb_cmd_mode(gs->info->glamofb_handle, value);
-+#endif
-+}
-+
-+static int glamo_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
-+{
-+	struct glamo_spi *gs = to_gs(spi);
-+	const u_int16_t *ui16 = (const u_int16_t *) t->tx_buf;
-+	u_int16_t nine_bits;
-+	int i;
-+
-+	dev_dbg(&spi->dev, "txrx: tx %p, rx %p, bpw %d, len %d\n",
-+		t->tx_buf, t->rx_buf, t->bits_per_word, t->len);
-+
-+	if (spi->bits_per_word == 9)
-+		nine_bits = (1 << 9);
-+	else
-+		nine_bits = 0;
-+
-+	if (t->len > 3 * sizeof(u_int16_t)) {
-+		dev_err(&spi->dev, "this driver doesn't support "
-+			"%u sized xfers\n", t->len);
-+		return -EINVAL;
-+	}
-+
-+	for (i = 0; i < t->len/sizeof(u_int16_t); i++) {
-+		/* actually transfer the data */
-+#if 1
-+		glamofb_cmd_write(gs->info->glamofb_handle,
-+				  GLAMO_LCD_CMD_TYPE_SERIAL | nine_bits |
-+				  (1 << 10) | (1 << 11) | (ui16[i] & 0x1ff));
-+#endif
-+		/* FIXME: fire ?!? */
-+		if (i == 0 && (ui16[i] & 0x1ff) == 0x29) {
-+			dev_dbg(&spi->dev, "leaving command mode\n");
-+			glamofb_cmd_mode(gs->info->glamofb_handle, 0);
-+		}
-+	}
-+
-+	return t->len;
-+}
-+
-+static int glamo_spi_setup(struct spi_device *spi)
-+{
-+	int ret;
-+
-+	if (!spi->bits_per_word)
-+		spi->bits_per_word = 9;
-+
-+	/* FIXME: hardware can do this */
-+	if (spi->mode & SPI_LSB_FIRST)
-+		return -EINVAL;
-+
-+	ret = glamo_spi_setupxfer(spi, NULL);
-+	if (ret < 0) {
-+		dev_err(&spi->dev, "setupxfer returned %d\n", ret);
-+		return ret;
-+	}
-+
-+	dev_dbg(&spi->dev, "%s: mode %d, %u bpw\n",
-+		__FUNCTION__, spi->mode, spi->bits_per_word);
-+
-+	return 0;
-+}
-+
-+static int glamo_spi_probe(struct platform_device *pdev)
-+{
-+	struct spi_master *master;
-+	struct glamo_spi *sp;
-+	int ret;
-+	int i;
-+
-+	master = spi_alloc_master(&pdev->dev, sizeof(struct glamo_spi));
-+	if (master == NULL) {
-+		dev_err(&pdev->dev, "failed to allocate spi master\n");
-+		ret = -ENOMEM;
-+		goto err;
-+	}
-+
-+	sp = spi_master_get_devdata(master);
-+	memset(sp, 0, sizeof(struct glamo_spi));
-+
-+	sp->master = spi_master_get(master);
-+	sp->info = pdev->dev.platform_data;
-+	if (!sp->info) {
-+		dev_err(&pdev->dev, "can't operate without platform data\n");
-+		ret = -EIO;
-+		goto err_no_pdev;
-+	}
-+	dev_dbg(&pdev->dev, "sp->info(pdata) = %p\n", sp->info);
-+
-+	sp->dev = &pdev->dev;
-+
-+	platform_set_drvdata(pdev, sp);
-+
-+	sp->bitbang.master = sp->master;
-+	sp->bitbang.setup_transfer = glamo_spi_setupxfer;
-+	sp->bitbang.chipselect = glamo_spi_chipsel;
-+	sp->bitbang.txrx_bufs = glamo_spi_txrx;
-+	sp->bitbang.master->setup = glamo_spi_setup;
-+
-+	ret = spi_bitbang_start(&sp->bitbang);
-+	if (ret)
-+		goto err_no_bitbang;
-+
-+	/* register the chips to go with the board */
-+
-+	glamofb_cmd_mode(sp->info->glamofb_handle, 1);
-+
-+	for (i = 0; i < sp->info->board_size; i++) {
-+		dev_info(&pdev->dev, "registering %p: %s\n",
-+			 &sp->info->board_info[i],
-+			 sp->info->board_info[i].modalias);
-+
-+		sp->info->board_info[i].controller_data = sp;
-+		spi_new_device(master, sp->info->board_info + i);
-+	}
-+
-+	return 0;
-+
-+err_no_bitbang:
-+	platform_set_drvdata(pdev, NULL);
-+err_no_pdev:
-+	spi_master_put(sp->bitbang.master);
-+err:
-+	return ret;
-+
-+}
-+
-+static int glamo_spi_remove(struct platform_device *pdev)
-+{
-+	struct glamo_spi *sp = platform_get_drvdata(pdev);
-+
-+	spi_bitbang_stop(&sp->bitbang);
-+	spi_master_put(sp->bitbang.master);
-+
-+	return 0;
-+}
-+
-+#define glamo_spi_suspend NULL
-+#define glamo_spi_resume NULL
-+
-+static struct platform_driver glamo_spi_drv = {
-+	.probe		= glamo_spi_probe,
-+        .remove		= glamo_spi_remove,
-+        .suspend	= glamo_spi_suspend,
-+        .resume		= glamo_spi_resume,
-+        .driver		= {
-+		.name	= "glamo-lcm-spi",
-+		.owner	= THIS_MODULE,
-+        },
-+};
-+
-+static int __init glamo_spi_init(void)
-+{
-+        return platform_driver_register(&glamo_spi_drv);
-+}
-+
-+static void __exit glamo_spi_exit(void)
-+{
-+        platform_driver_unregister(&glamo_spi_drv);
-+}
-+
-+module_init(glamo_spi_init);
-+module_exit(glamo_spi_exit);
-+
-+MODULE_DESCRIPTION("Smedia Glamo 336x/337x LCM serial command SPI Driver");
-+MODULE_AUTHOR("Harald Welte <laforge at openmoko.org>")
-+MODULE_LICENSE("GPL");
 Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-core.c
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-core.c
-@@ -0,0 +1,795 @@
+@@ -0,0 +1,1017 @@
 +/* Smedia Glamo 336x/337x driver
 + *
 + * (C) 2007 by OpenMoko, Inc.
@@ -829,18 +599,6 @@
 +
 +#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
 +
-+struct glamo_core {
-+	int irq;
-+	struct resource *mem;
-+	struct resource *mem_core;
-+	void __iomem *base;
-+	struct platform_device *pdev;
-+	struct glamofb_platform_data *pdata;
-+	u_int16_t type;
-+	u_int16_t revision;
-+	spinlock_t lock;
-+};
-+
 +static struct glamo_core *glamo_handle;
 +
 +static inline void __reg_write(struct glamo_core *glamo,
@@ -878,6 +636,18 @@
 +	spin_unlock(&glamo->lock);
 +}
 +
++static inline void __reg_set_bit(struct glamo_core *glamo,
++				 u_int16_t reg, u_int16_t bit)
++{
++	__reg_set_bit_mask(glamo, reg, bit, 0xffff);
++}
++
++static inline void __reg_clear_bit(struct glamo_core *glamo,
++				   u_int16_t reg, u_int16_t bit)
++{
++	__reg_set_bit_mask(glamo, reg, bit, 0);
++}
++
 +static inline void glamo_vmem_write(struct glamo_core *glamo, u_int32_t addr,
 +				    u_int16_t *src, int len)
 +{
@@ -942,6 +712,78 @@
 +	.num_resources	= ARRAY_SIZE(glamo_mmc_resources),
 +};
 +
++static struct resource glamo_jpeg_resources[] = {
++	{
++		.start	= GLAMO_REGOFS_JPEG,
++		.end	= GLAMO_REGOFS_MPEG,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_GLAMO_JPEG,
++		.end	= IRQ_GLAMO_JPEG,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device glamo_jpeg_dev = {
++	.name		= "glamo-jpeg",
++	.resource	= glamo_jpeg_resources,
++	.num_resources	= ARRAY_SIZE(glamo_jpeg_resources),
++};
++
++static struct resource glamo_mpeg_resources[] = {
++	{
++		.start	= GLAMO_REGOFS_MPEG,
++		.end	= GLAMO_REGOFS_LCD,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_GLAMO_MPEG,
++		.end	= IRQ_GLAMO_MPEG,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device glamo_mpeg_dev = {
++	.name		= "glamo-mpeg",
++	.resource	= glamo_mpeg_resources,
++	.num_resources	= ARRAY_SIZE(glamo_mpeg_resources),
++};
++
++static struct resource glamo_2d_resources[] = {
++	{
++		.start	= GLAMO_REGOFS_2D,
++		.end	= GLAMO_REGOFS_3D,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_GLAMO_2D,
++		.end	= IRQ_GLAMO_2D,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device glamo_2d_dev = {
++	.name		= "glamo-2d",
++	.resource	= glamo_2d_resources,
++	.num_resources	= ARRAY_SIZE(glamo_2d_resources),
++};
++
++static struct resource glamo_3d_resources[] = {
++	{
++		.start	= GLAMO_REGOFS_3D,
++		.end	= GLAMO_REGOFS_3D + 0x600,
++		.flags	= IORESOURCE_MEM,
++	},
++};
++
++static struct platform_device glamo_3d_dev = {
++	.name		= "glamo-3d",
++	.resource	= glamo_2d_resources,
++	.num_resources	= ARRAY_SIZE(glamo_2d_resources),
++};
++
++static struct platform_device glamo_spigpio_dev = {
++	.name		= "glamo-spi-gpio",
++};
++
 +/* 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 */
@@ -1150,9 +992,49 @@
 +}
 +EXPORT_SYMBOL_GPL(glamo_engine_disable);
 +
++struct glamo_script reset_regs[] = {
++	[GLAMO_ENGINE_LCD] = {
++		GLAMO_REG_CLOCK_LCD, GLAMO_CLOCK_LCD_RESET
++	},
++#if 0
++	[GLAMO_ENGINE_HOST] = {
++		GLAMO_REG_CLOCK_HOST, GLAMO_CLOCK_HOST_RESET
++	},
++	[GLAMO_ENGINE_MEM] = {
++		GLAMO_REG_CLOCK_MEM, GLAMO_CLOCK_MEM_RESET
++	},
++#endif
++	[GLAMO_ENGINE_MMC] = {
++		GLAMO_REG_CLOCK_MMC, GLAMO_CLOCK_MMC_RESET
++	},
++	[GLAMO_ENGINE_2D] = {
++		GLAMO_REG_CLOCK_2D, GLAMO_CLOCK_2D_RESET
++	},
++	[GLAMO_ENGINE_JPEG] = {
++		GLAMO_REG_CLOCK_JPEG, GLAMO_CLOCK_JPEG_RESET
++	},
++};
++
 +void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine)
 +{
-+	/* FIXME: Implementation */
++	struct glamo_script *rst;
++
++	if (engine >= ARRAY_SIZE(reset_regs)) {
++		dev_warn(&glamo->pdev->dev, "unknown engine %u ", engine);
++		return;
++	}
++
++	rst = &reset_regs[engine];
++
++	spin_lock(&glamo->lock);
++	__reg_set_bit(glamo, rst->reg, rst->val);
++	spin_unlock(&glamo->lock);
++
++	msleep(1);
++
++	spin_lock(&glamo->lock);
++	__reg_clear_bit(glamo, rst->reg, rst->val);
++	spin_unlock(&glamo->lock);
 +}
 +EXPORT_SYMBOL_GPL(glamo_engine_reset);
 +
@@ -1215,12 +1097,12 @@
 +	{ GLAMO_REG_CLOCK_MPEG,		0x0000 },
 +	{ GLAMO_REG_CLOCK_MPROC,	0x0000 },
 +		{ 0xfffe, 1 },
-+	{ GLAMO_REG_PLL_GEN1,		0x0588 },
-+	{ GLAMO_REG_PLL_GEN3,		0x0a27 },
++	{ GLAMO_REG_PLL_GEN1,		0x05db },	/* 48MHz */
++	{ GLAMO_REG_PLL_GEN3,		0x09c3 },	/* 80MHz */
 +		{ 0xfffe, 300 },
 +	{ GLAMO_REG_IRQ_ENABLE,		0xffff },
 +	{ GLAMO_REG_CLOCK_GEN6,		0x2000 },
-+	{ GLAMO_REG_CLOCK_GEN7,		0x010b },
++	{ GLAMO_REG_CLOCK_GEN7,		0x0102 },
 +	{ GLAMO_REG_CLOCK_GEN8,		0x0100 },
 +	{ GLAMO_REG_CLOCK_HOST,		0x000d },
 +	{ 0x200,	0x0ef0 },
@@ -1308,7 +1190,86 @@
 +};
 +#endif
 +
++enum glamo_pll {
++	GLAMO_PLL1,
++	GLAMO_PLL2,
++};
 +
++static int glamo_pll_rate(struct glamo_core *glamo,
++				   enum glamo_pll pll)
++{
++	u_int16_t reg;
++	unsigned int div = 512;
++	/* FIXME: move osci into platform_data */
++	unsigned int osci = 32768;
++
++	if (osci == 32768)
++		div = 1;
++
++	switch (pll) {
++	case GLAMO_PLL1:
++		reg = __reg_read(glamo, GLAMO_REG_PLL_GEN1);
++		break;
++	case GLAMO_PLL2:
++		reg = __reg_read(glamo, GLAMO_REG_PLL_GEN3);
++		break;
++	default:
++		return -EINVAL;
++	}
++	return (osci/div)*reg;
++}
++
++enum glamo_power {
++	GLAMO_POWER_ON,
++	GLAMO_POWER_STANDBY,
++	GLAMO_POWER_SUSPEND,
++};
++
++static void glamo_power(struct glamo_core *glamo,
++			enum glamo_power new_state)
++{
++	spin_lock(&glamo->lock);
++
++	switch (new_state) {
++	case GLAMO_POWER_ON:
++		/* power up PLL1 and PLL2 */
++		__reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN6, 0x0001, 0xffff);
++		__reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0x0000);
++		/* enable memory clock and get it out of deep pwrdown */
++		__reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
++				   GLAMO_CLOCK_MEM_EN_MOCACLK, 0xffff);
++		__reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
++				   GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0x0000);
++		__reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
++				   GLAMO_MEM_DRAM1_SELF_REFRESH, 0x0000);
++		/* FIXME: reset pll's */
++		break;
++	case GLAMO_POWER_STANDBY:
++		/* enable memory self-refresh */
++		__reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM1,
++				   GLAMO_MEM_DRAM1_SELF_REFRESH, 0xffff);
++		/* stop memory clock */
++		__reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
++				   GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
++		/* power down PLL2 and then PLL1 */
++		__reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
++		__reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
++		break;
++	case GLAMO_POWER_SUSPEND:
++		__reg_set_bit_mask(glamo, GLAMO_REG_MEM_DRAM2,
++				   GLAMO_MEM_DRAM2_DEEP_PWRDOWN, 0xffff);
++		/* stop memory clock */
++		__reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_MEMORY,
++				   GLAMO_CLOCK_MEM_EN_MOCACLK, 0x0000);
++		/* power down PLL2 and then PLL1 */
++		__reg_set_bit_mask(glamo, GLAMO_REG_PLL_GEN3, 0x2000, 0xffff);
++		__reg_set_bit_mask(glamo, GLAMO_REG_DFT_GEN5, 0x0001, 0xffff);
++		break;
++	}
++
++	spin_unlock(&glamo->lock);
++}
++
 +#define MEMDETECT_RETRY	6
 +static unsigned int detect_memsize(struct glamo_core *glamo)
 +{
@@ -1368,6 +1329,7 @@
 +#endif
 +	}
 +
++	return 0;
 +}
 +
 +/* Find out if we can support this version of the Glamo chip */
@@ -1378,9 +1340,6 @@
 +	dev_id = __reg_read(glamo, GLAMO_REG_DEVICE_ID);
 +	rev_id = __reg_read(glamo, GLAMO_REG_REVISION_ID);
 +
-+	dev_info(&glamo->pdev->dev, "Detected Glamo core %04x Revision %04x\n",
-+		 dev_id, rev_id);
-+
 +	switch (dev_id) {
 +	case 0x3650:
 +		switch (rev_id) {
@@ -1401,11 +1360,16 @@
 +	case 0x3600:
 +	case 0x3700:
 +	default:
-+		dev_err(&glamo->pdev->dev, "unsupported glamo device %04x\n",
++		dev_err(&glamo->pdev->dev, "unsupported Glamo device %04x\n",
 +			dev_id);
 +		return 0;
 +	}
 +
++	dev_info(&glamo->pdev->dev, "Detected Glamo core %04x Revision %04x "
++		 "(%uHz CPU / %uHz Memory)\n", dev_id, rev_id,
++		 glamo_pll_rate(glamo, GLAMO_PLL1),
++		 glamo_pll_rate(glamo, GLAMO_PLL2));
++
 +	return 1;
 +}
 +
@@ -1452,6 +1416,26 @@
 +			     glamo_mmc_dev.num_resources, glamo->mem);
 +	platform_device_register(&glamo_mmc_dev);
 +
++	glamo_2d_dev.dev.parent = &pdev->dev;
++	mangle_mem_resources(glamo_2d_dev.resource,
++			     glamo_2d_dev.num_resources, glamo->mem);
++	platform_device_register(&glamo_2d_dev);
++
++	glamo_3d_dev.dev.parent = &pdev->dev;
++	mangle_mem_resources(glamo_3d_dev.resource,
++			     glamo_3d_dev.num_resources, glamo->mem);
++	platform_device_register(&glamo_3d_dev);
++
++	glamo_jpeg_dev.dev.parent = &pdev->dev;
++	mangle_mem_resources(glamo_jpeg_dev.resource,
++			     glamo_jpeg_dev.num_resources, glamo->mem);
++	platform_device_register(&glamo_jpeg_dev);
++
++	glamo_mpeg_dev.dev.parent = &pdev->dev;
++	mangle_mem_resources(glamo_mpeg_dev.resource,
++			     glamo_mpeg_dev.num_resources, glamo->mem);
++	platform_device_register(&glamo_mpeg_dev);
++
 +	glamo->pdata->glamo = glamo;
 +	glamo_fb_dev.dev.parent = &pdev->dev;
 +	glamo_fb_dev.dev.platform_data = glamo->pdata;
@@ -1459,15 +1443,20 @@
 +			     glamo_fb_dev.num_resources, glamo->mem);
 +	platform_device_register(&glamo_fb_dev);
 +
-+	glamo->mem = request_mem_region(glamo->mem->start, 0x400,
-+					"glamo-core");
++	glamo->pdata->spigpio_info->glamo = glamo;
++	glamo_spigpio_dev.dev.parent = &pdev->dev;
++	glamo_spigpio_dev.dev.platform_data = glamo->pdata->spigpio_info;
++	platform_device_register(&glamo_spigpio_dev);
++
++	/* only request the generic, hostbus and memory controller MMIO */
++	glamo->mem = request_mem_region(glamo->mem->start,
++					GLAMO_REGOFS_VIDCAP, "glamo-core");
 +	if (!glamo->mem) {
 +		dev_err(&pdev->dev, "failed to request memory region\n");
 +		goto out_free;
 +	}
 +
-+	/* we want to remap only the registers required for this core
-+	 * driver. */
++	/* only remap the generic, hostbus and memory controller registers */
 +	glamo->base = ioremap(glamo->mem->start, GLAMO_REGOFS_VIDCAP);
 +	if (!glamo->base) {
 +		dev_err(&pdev->dev, "failed to ioremap() memory region\n");
@@ -1484,6 +1473,10 @@
 +	printk("running init script\n");
 +	glamo_run_script(glamo, glamo_init_script, ARRAY_SIZE(glamo_init_script));
 +
++	dev_info(&glamo->pdev->dev, "Glamo core now %uHz CPU / %uHz Memory)\n",
++		 glamo_pll_rate(glamo, GLAMO_PLL1),
++		 glamo_pll_rate(glamo, GLAMO_PLL2));
++
 +	printk("interrupts\n");
 +
 +	/* FIXME: do we need to request_irq() it ? */
@@ -1495,7 +1488,6 @@
 +	set_irq_chained_handler(glamo->irq, glamo_irq_demux_handler);
 +	set_irq_type(glamo->irq, IRQT_FALLING);
 +
-+
 +	return 0;
 +
 +out_free:
@@ -1618,7 +1610,7 @@
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-fb.c
-@@ -0,0 +1,494 @@
+@@ -0,0 +1,547 @@
 +/* Smedia Glamo 336x/337x driver
 + *
 + * (C) 2007 by OpenMoko, Inc.
@@ -1685,6 +1677,7 @@
 +	char __iomem *base;
 +	struct glamofb_platform_data *mach_info;
 +	struct glamo_core *glamo;
++	u_int32_t pseudo_pal[16];
 +};
 +
 +/* 'sibling' spi device for lcm init */
@@ -1821,6 +1814,8 @@
 +		return -EINVAL;
 +		break;
 +	}
++
++	return 0;
 +}
 +
 +static int glamofb_set_par(struct fb_info *info)
@@ -1829,6 +1824,21 @@
 +	struct fb_var_screeninfo *var = &info->var;
 +
 +	/* FIXME */
++
++	switch (var->bits_per_pixel) {
++	case 16:
++		glamo->fb->fix.visual = FB_VISUAL_DIRECTCOLOR;
++		break;
++	case 32:
++		glamo->fb->fix.visual = FB_VISUAL_TRUECOLOR;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	glamo->fb->fix.line_length = (var->width * var->bits_per_pixel) / 8;
++	glamo->fb->fix.smem_len = info->fix.line_length * var->yres_virtual;
++
 +	return 0;
 +}
 +
@@ -1838,10 +1848,39 @@
 +	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;
 +}
 +
@@ -1967,7 +2006,7 @@
 +		dev_err(&pdev->dev, "failed to ioremap() mmio memory\n");
 +		goto out_release_fb;
 +	}
-+	fbinfo->fix.smem_start = (unsigned long) glamofb->base;
++	fbinfo->fix.smem_start = (unsigned long) glamofb->fb_res->start;
 +
 +	fbinfo->screen_base = ioremap(glamofb->fb_res->start,
 +				       RESSIZE(glamofb->fb_res));
@@ -1996,7 +2035,7 @@
 +
 +	fbinfo->fbops = &glamofb_ops;
 +	fbinfo->flags = FBINFO_FLAG_DEFAULT;
-+	//fbinfo->pseudo_palette =
++	fbinfo->pseudo_palette = &glamofb->pseudo_pal;
 +
 +	fbinfo->var.xres = mach_info->xres.defval;
 +	fbinfo->var.xres_virtual = mach_info->xres.defval;
@@ -2026,8 +2065,12 @@
 +			       mach_info->yres.max *
 +			       mach_info->bpp.max / 8;
 +
++	memset(fbinfo->screen_base, 0, fbinfo->fix.smem_len);
++
++	glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD);
++	glamo_engine_reset(mach_info->glamo, GLAMO_ENGINE_LCD);
 +	glamofb_run_script(glamofb, glamo_regs, ARRAY_SIZE(glamo_regs));
-+	glamo_engine_enable(mach_info->glamo, GLAMO_ENGINE_LCD);
++	glamofb_cmd_mode(glamofb, 0);
 +
 +	rc = register_framebuffer(fbinfo);
 +	if (rc < 0) {
@@ -2035,11 +2078,13 @@
 +		goto out_unmap_fb;
 +	}
 +
-+	/* register the sibling spi device */
-+	mach_info->spi_info->glamofb_handle = glamofb;
-+	glamo_spi_dev.dev.parent = &pdev->dev;
-+	glamo_spi_dev.dev.platform_data = mach_info->spi_info;
-+	platform_device_register(&glamo_spi_dev);
++	if (mach_info->spi_info) {
++		/* register the sibling spi device */
++		mach_info->spi_info->glamofb_handle = glamofb;
++		glamo_spi_dev.dev.parent = &pdev->dev;
++		glamo_spi_dev.dev.platform_data = mach_info->spi_info;
++		platform_device_register(&glamo_spi_dev);
++	}
 +
 +	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 +		fbinfo->node, fbinfo->fix.id);
@@ -2117,7 +2162,7 @@
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/include/linux/glamofb.h
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
 +#ifndef _LINUX_GLAMOFB_H
 +#define _LINUX_GLAMOFB_H
 +
@@ -2139,6 +2184,7 @@
 +	struct glamofb_val bpp;
 +
 +	struct glamo_spi_info *spi_info;
++	struct glamo_spigpio_info *spigpio_info;
 +	struct glamo_core *glamo;
 +};
 +
@@ -2150,12 +2196,15 @@
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/include/linux/spi/glamo.h
-@@ -0,0 +1,13 @@
+@@ -0,0 +1,28 @@
 +#ifndef __GLAMO_SPI_H
 +#define __GLAMO_SPI_H
 +
++#include <linux/glamo-gpio.h>
++
 +struct spi_board_info;
 +struct glamofb_handle;
++struct glamo_core;
 +
 +struct glamo_spi_info {
 +	unsigned long 		board_size;
@@ -2163,16 +2212,38 @@
 +	struct glamofb_handle	*glamofb_handle;
 +};
 +
++struct glamo_spigpio_info {
++	unsigned int		pin_clk;
++	unsigned int		pin_mosi;
++	unsigned int		pin_miso;
++	unsigned int 		pin_cs;
++
++	unsigned int		board_size;
++	struct spi_board_info*	board_info;
++	struct glamo_core	*glamo;
++};
++
++
 +#endif
 Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-core.h
 ===================================================================
 --- /dev/null
 +++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-core.h
-@@ -0,0 +1,40 @@
+@@ -0,0 +1,51 @@
 +#ifndef __GLAMO_CORE_H
 +#define __GLAMO_CORE_H
 +
-+struct glamo_core;
++struct glamo_core {
++	int irq;
++	struct resource *mem;
++	struct resource *mem_core;
++	void __iomem *base;
++	struct platform_device *pdev;
++	struct glamofb_platform_data *pdata;
++	u_int16_t type;
++	u_int16_t revision;
++	spinlock_t lock;
++};
 +
 +struct glamo_script {
 +	u_int16_t reg;
@@ -2207,5 +2278,678 @@
 +
 +int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine);
 +int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine);
++void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine);
 +
 +#endif /* __GLAMO_CORE_H */
+Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-gpio.c
+===================================================================
+--- /dev/null
++++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-gpio.c
+@@ -0,0 +1,62 @@
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/io.h>
++
++#include <linux/glamo-gpio.h>
++
++#include "glamo-core.h"
++#include "glamo-regs.h"
++
++void glamo_gpio_setpin(struct glamo_core *glamo, unsigned int pin,
++		       unsigned int value)
++{
++	unsigned int reg = REG_OF_GPIO(pin);
++	u_int16_t tmp;
++
++	spin_lock(&glamo->lock);
++	tmp = readw(glamo->base + reg);
++	if (value)
++		tmp |= OUTPUT_BIT(pin);
++	else
++		tmp &= ~OUTPUT_BIT(pin);
++	writew(tmp, glamo->base + reg);
++	spin_unlock(&glamo->lock);
++}
++EXPORT_SYMBOL(glamo_gpio_setpin);
++
++int glamo_gpio_getpin(struct glamo_core *glamo, unsigned int pin)
++{
++	return readw(REG_OF_GPIO(pin)) & INPUT_BIT(pin) ? 1 : 0;
++}
++EXPORT_SYMBOL(glamo_gpio_getpin);
++
++void glamo_gpio_cfgpin(struct glamo_core *glamo, unsigned int pinfunc)
++{
++	unsigned int reg = REG_OF_GPIO(pinfunc);
++	u_int16_t tmp;
++
++	spin_lock(&glamo->lock);
++	tmp = readw(glamo->base + reg);
++
++	if ((pinfunc & 0x00f0) == GLAMO_GPIO_F_FUNC) {
++		/* pin is a function pin: clear gpio bit */
++		tmp &= ~FUNC_BIT(pinfunc);
++	} else {
++		/* pin is gpio: set gpio bit */
++		tmp |= FUNC_BIT(pinfunc);
++
++		if (pinfunc & GLAMO_GPIO_F_IN) {
++			/* gpio input: set bit to disable output mode */
++			tmp |= GPIO_OUT_BIT(pinfunc);
++		} else if (pinfunc & GLAMO_GPIO_F_OUT) {
++			/* gpio output: clear bit to enable output mode */
++			tmp &= ~GPIO_OUT_BIT(pinfunc);
++		}
++	}
++	writew(tmp, glamo->base + reg);
++	spin_unlock(&glamo->lock);
++}
++EXPORT_SYMBOL(glamo_gpio_cfgpin);
++
+Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-lcm-spi.c
+===================================================================
+--- /dev/null
++++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-lcm-spi.c
+@@ -0,0 +1,241 @@
++/*
++ * Copyright (C) 2007 OpenMoko, Inc.
++ * Author: Harald Welte <laforge at openmoko.org>
++ *
++ * Smedia Glamo GPIO based SPI driver
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This driver currently only implements a minimum subset of the hardware
++ * features, esp. those features that are required to drive the jbt6k74
++ * LCM controller asic in the TD028TTEC1 LCM.
++ *
++*/
++
++#define DEBUG
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/glamo.h>
++
++#include <linux/glamofb.h>
++
++#include <asm/hardware.h>
++
++#include "glamo-core.h"
++#include "glamo-regs.h"
++
++struct glamo_spi {
++	struct spi_bitbang	bitbang;
++	struct spi_master	*master;
++	struct glamo_spi_info	*info;
++	struct device		*dev;
++};
++
++static inline struct glamo_spi *to_gs(struct spi_device *spi)
++{
++	return spi->controller_data;
++}
++
++static int glamo_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
++{
++	struct glamo_spi *gs = to_gs(spi);
++	unsigned int bpw;
++
++	bpw = t ? t->bits_per_word : spi->bits_per_word;
++
++	if (bpw != 9 && bpw != 8) {
++		dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static void glamo_spi_chipsel(struct spi_device *spi, int value)
++{
++#if 0
++	struct glamo_spi *gs = to_gs(spi);
++
++	dev_dbg(&spi->dev, "chipsel %d: spi=%p, gs=%p, info=%p, handle=%p\n",
++		value, spi, gs, gs->info, gs->info->glamofb_handle);
++
++	glamofb_cmd_mode(gs->info->glamofb_handle, value);
++#endif
++}
++
++static int glamo_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
++{
++	struct glamo_spi *gs = to_gs(spi);
++	const u_int16_t *ui16 = (const u_int16_t *) t->tx_buf;
++	u_int16_t nine_bits;
++	int i;
++
++	dev_dbg(&spi->dev, "txrx: tx %p, rx %p, bpw %d, len %d\n",
++		t->tx_buf, t->rx_buf, t->bits_per_word, t->len);
++
++	if (spi->bits_per_word == 9)
++		nine_bits = (1 << 9);
++	else
++		nine_bits = 0;
++
++	if (t->len > 3 * sizeof(u_int16_t)) {
++		dev_err(&spi->dev, "this driver doesn't support "
++			"%u sized xfers\n", t->len);
++		return -EINVAL;
++	}
++
++	for (i = 0; i < t->len/sizeof(u_int16_t); i++) {
++		/* actually transfer the data */
++#if 1
++		glamofb_cmd_write(gs->info->glamofb_handle,
++				  GLAMO_LCD_CMD_TYPE_SERIAL | nine_bits |
++				  (1 << 10) | (1 << 11) | (ui16[i] & 0x1ff));
++#endif
++		/* FIXME: fire ?!? */
++		if (i == 0 && (ui16[i] & 0x1ff) == 0x29) {
++			dev_dbg(&spi->dev, "leaving command mode\n");
++			glamofb_cmd_mode(gs->info->glamofb_handle, 0);
++		}
++	}
++
++	return t->len;
++}
++
++static int glamo_spi_setup(struct spi_device *spi)
++{
++	int ret;
++
++	if (!spi->bits_per_word)
++		spi->bits_per_word = 9;
++
++	/* FIXME: hardware can do this */
++	if (spi->mode & SPI_LSB_FIRST)
++		return -EINVAL;
++
++	ret = glamo_spi_setupxfer(spi, NULL);
++	if (ret < 0) {
++		dev_err(&spi->dev, "setupxfer returned %d\n", ret);
++		return ret;
++	}
++
++	dev_dbg(&spi->dev, "%s: mode %d, %u bpw\n",
++		__FUNCTION__, spi->mode, spi->bits_per_word);
++
++	return 0;
++}
++
++static int glamo_spi_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct glamo_spi *sp;
++	int ret;
++	int i;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(struct glamo_spi));
++	if (master == NULL) {
++		dev_err(&pdev->dev, "failed to allocate spi master\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	sp = spi_master_get_devdata(master);
++	memset(sp, 0, sizeof(struct glamo_spi));
++
++	sp->master = spi_master_get(master);
++	sp->info = pdev->dev.platform_data;
++	if (!sp->info) {
++		dev_err(&pdev->dev, "can't operate without platform data\n");
++		ret = -EIO;
++		goto err_no_pdev;
++	}
++	dev_dbg(&pdev->dev, "sp->info(pdata) = %p\n", sp->info);
++
++	sp->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, sp);
++
++	sp->bitbang.master = sp->master;
++	sp->bitbang.setup_transfer = glamo_spi_setupxfer;
++	sp->bitbang.chipselect = glamo_spi_chipsel;
++	sp->bitbang.txrx_bufs = glamo_spi_txrx;
++	sp->bitbang.master->setup = glamo_spi_setup;
++
++	ret = spi_bitbang_start(&sp->bitbang);
++	if (ret)
++		goto err_no_bitbang;
++
++	/* register the chips to go with the board */
++
++	glamofb_cmd_mode(sp->info->glamofb_handle, 1);
++
++	for (i = 0; i < sp->info->board_size; i++) {
++		dev_info(&pdev->dev, "registering %p: %s\n",
++			 &sp->info->board_info[i],
++			 sp->info->board_info[i].modalias);
++
++		sp->info->board_info[i].controller_data = sp;
++		spi_new_device(master, sp->info->board_info + i);
++	}
++
++	return 0;
++
++err_no_bitbang:
++	platform_set_drvdata(pdev, NULL);
++err_no_pdev:
++	spi_master_put(sp->bitbang.master);
++err:
++	return ret;
++
++}
++
++static int glamo_spi_remove(struct platform_device *pdev)
++{
++	struct glamo_spi *sp = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&sp->bitbang);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++#define glamo_spi_suspend NULL
++#define glamo_spi_resume NULL
++
++static struct platform_driver glamo_spi_drv = {
++	.probe		= glamo_spi_probe,
++        .remove		= glamo_spi_remove,
++        .suspend	= glamo_spi_suspend,
++        .resume		= glamo_spi_resume,
++        .driver		= {
++		.name	= "glamo-lcm-spi",
++		.owner	= THIS_MODULE,
++        },
++};
++
++static int __init glamo_spi_init(void)
++{
++        return platform_driver_register(&glamo_spi_drv);
++}
++
++static void __exit glamo_spi_exit(void)
++{
++        platform_driver_unregister(&glamo_spi_drv);
++}
++
++module_init(glamo_spi_init);
++module_exit(glamo_spi_exit);
++
++MODULE_DESCRIPTION("Smedia Glamo 336x/337x LCM serial command SPI Driver");
++MODULE_AUTHOR("Harald Welte <laforge at openmoko.org>")
++MODULE_LICENSE("GPL");
+Index: linux-2.6.21.3-moko/drivers/video/glamo/glamo-spi-gpio.c
+===================================================================
+--- /dev/null
++++ linux-2.6.21.3-moko/drivers/video/glamo/glamo-spi-gpio.c
+@@ -0,0 +1,250 @@
++/*
++ * Copyright (C) 2007 OpenMoko, Inc.
++ * Author: Harald Welte <laforge at openmoko.org>
++ *
++ * Smedia Glamo GPIO based SPI driver
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This driver currently only implements a minimum subset of the hardware
++ * features, esp. those features that are required to drive the jbt6k74
++ * LCM controller asic in the TD028TTEC1 LCM.
++ *
++*/
++
++#define DEBUG
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/glamo.h>
++
++#include <linux/glamofb.h>
++
++#include <asm/hardware.h>
++
++#include "glamo-core.h"
++#include "glamo-regs.h"
++
++struct glamo_spigpio {
++	struct spi_bitbang		bitbang;
++	struct spi_master		*master;
++	struct glamo_spigpio_info	*info;
++	struct glamo_core		*glamo;
++	//struct device			*dev;
++};
++
++static inline struct glamo_spigpio *to_sg(struct spi_device *spi)
++{
++	return spi->controller_data;
++}
++
++static inline void setsck(struct spi_device *dev, int on)
++{
++	struct glamo_spigpio *sg = to_sg(dev);
++	glamo_gpio_setpin(sg->glamo, sg->info->pin_clk, on ? 1 : 0);
++}
++
++static inline void setmosi(struct spi_device *dev, int on)
++{
++	struct glamo_spigpio *sg = to_sg(dev);
++	glamo_gpio_setpin(sg->glamo, sg->info->pin_mosi, on ? 1 : 0);
++}
++
++static inline u32 getmiso(struct spi_device *dev)
++{
++	struct glamo_spigpio *sg = to_sg(dev);
++	if (sg->info->pin_miso)
++		return glamo_gpio_getpin(sg->glamo, sg->info->pin_miso) ? 1 : 0;
++	else
++		return 0;
++}
++
++#define spidelay(x) ndelay(x)
++
++#define EXPAND_BITBANG_TXRX
++#include <linux/spi/spi_bitbang.h>
++
++static u32 glamo_spigpio_txrx_mode0(struct spi_device *spi,
++				    unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
++}
++
++static u32 glamo_spigpio_txrx_mode1(struct spi_device *spi,
++				    unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
++}
++
++static u32 glamo_spigpio_txrx_mode2(struct spi_device *spi,
++				    unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
++}
++
++static u32 glamo_spigpio_txrx_mode3(struct spi_device *spi,
++				    unsigned nsecs, u32 word, u8 bits)
++{
++	return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
++}
++
++
++#if 0
++static int glamo_spigpio_setupxfer(struct spi_device *spi, struct spi_transfer *t)
++{
++	struct glamo_spi *gs = to_sg(spi);
++	unsigned int bpw;
++
++	bpw = t ? t->bits_per_word : spi->bits_per_word;
++
++	if (bpw != 9 && bpw != 8) {
++		dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++#endif
++
++static void glamo_spigpio_chipsel(struct spi_device *spi, int value)
++{
++	struct glamo_spigpio *gs = to_sg(spi);
++#if 0
++	dev_dbg(&spi->dev, "chipsel %d: spi=%p, gs=%p, info=%p, handle=%p\n",
++		value, spi, gs, gs->info, gs->info->glamo);
++#endif
++	glamo_gpio_setpin(gs->glamo, gs->info->pin_cs, value ? 0 : 1);
++}
++
++
++static int glamo_spigpio_probe(struct platform_device *pdev)
++{
++	struct spi_master *master;
++	struct glamo_spigpio *sp;
++	int ret;
++	int i;
++
++	master = spi_alloc_master(&pdev->dev, sizeof(struct glamo_spigpio));
++	if (master == NULL) {
++		dev_err(&pdev->dev, "failed to allocate spi master\n");
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	sp = spi_master_get_devdata(master);
++	platform_set_drvdata(pdev, sp);
++	sp->info = pdev->dev.platform_data;
++	if (!sp->info) {
++		dev_err(&pdev->dev, "can't operate without platform data\n");
++		ret = -EIO;
++		goto err_no_pdev;
++	}
++
++
++	//memset(sp, 0, sizeof(struct glamo_spigpio));
++
++	sp->master = spi_master_get(master);
++	sp->glamo = sp->info->glamo;
++
++	sp->bitbang.master = sp->master;
++	sp->bitbang.chipselect = glamo_spigpio_chipsel;
++	sp->bitbang.txrx_word[SPI_MODE_0] = glamo_spigpio_txrx_mode0;
++	sp->bitbang.txrx_word[SPI_MODE_1] = glamo_spigpio_txrx_mode1;
++	sp->bitbang.txrx_word[SPI_MODE_2] = glamo_spigpio_txrx_mode2;
++	sp->bitbang.txrx_word[SPI_MODE_3] = glamo_spigpio_txrx_mode3;
++
++	/* set state of spi pins */
++	glamo_gpio_setpin(sp->glamo, sp->info->pin_clk, 0);
++	glamo_gpio_setpin(sp->glamo, sp->info->pin_mosi, 0);
++	glamo_gpio_setpin(sp->glamo, sp->info->pin_cs, 1);
++
++	glamo_gpio_cfgpin(sp->glamo, sp->info->pin_clk);
++	glamo_gpio_cfgpin(sp->glamo, sp->info->pin_mosi);
++	glamo_gpio_cfgpin(sp->glamo, sp->info->pin_cs);
++	if (sp->info->pin_miso)
++		glamo_gpio_cfgpin(sp->glamo, sp->info->pin_miso);
++
++#if 0
++	sp->dev = &pdev->dev;
++
++	sp->bitbang.setup_transfer = glamo_spi_setupxfer;
++	sp->bitbang.txrx_bufs = glamo_spi_txrx;
++	sp->bitbang.master->setup = glamo_spi_setup;
++#endif
++
++	ret = spi_bitbang_start(&sp->bitbang);
++	if (ret)
++		goto err_no_bitbang;
++
++	/* register the chips to go with the board */
++
++	for (i = 0; i < sp->info->board_size; i++) {
++		dev_info(&pdev->dev, "registering %p: %s\n",
++			 &sp->info->board_info[i],
++			 sp->info->board_info[i].modalias);
++
++		sp->info->board_info[i].controller_data = sp;
++		spi_new_device(master, sp->info->board_info + i);
++	}
++
++	return 0;
++
++err_no_bitbang:
++	platform_set_drvdata(pdev, NULL);
++err_no_pdev:
++	spi_master_put(sp->bitbang.master);
++err:
++	return ret;
++
++}
++
++static int glamo_spigpio_remove(struct platform_device *pdev)
++{
++	struct glamo_spigpio *sp = platform_get_drvdata(pdev);
++
++	spi_bitbang_stop(&sp->bitbang);
++	spi_master_put(sp->bitbang.master);
++
++	return 0;
++}
++
++#define glamo_spigpio_suspend NULL
++#define glamo_spigpio_resume NULL
++
++static struct platform_driver glamo_spi_drv = {
++	.probe		= glamo_spigpio_probe,
++        .remove		= glamo_spigpio_remove,
++        .suspend	= glamo_spigpio_suspend,
++        .resume		= glamo_spigpio_resume,
++        .driver		= {
++		.name	= "glamo-spi-gpio",
++		.owner	= THIS_MODULE,
++        },
++};
++
++static int __init glamo_spi_init(void)
++{
++        return platform_driver_register(&glamo_spi_drv);
++}
++
++static void __exit glamo_spi_exit(void)
++{
++        platform_driver_unregister(&glamo_spi_drv);
++}
++
++module_init(glamo_spi_init);
++module_exit(glamo_spi_exit);
++
++MODULE_DESCRIPTION("Smedia Glamo 336x/337x LCM serial command SPI Driver");
++MODULE_AUTHOR("Harald Welte <laforge at openmoko.org>")
++MODULE_LICENSE("GPL");
+Index: linux-2.6.21.3-moko/include/linux/glamo-gpio.h
+===================================================================
+--- /dev/null
++++ linux-2.6.21.3-moko/include/linux/glamo-gpio.h
+@@ -0,0 +1,99 @@
++#ifndef __GLAMO_GPIO_H
++#define __GLAMO_GPIO_H
++
++struct glamo_core;
++
++#define GLAMO_GPIO_BANKA	0x0000
++#define GLAMO_GPIO_BANKB	0x1000
++#define GLAMO_GPIO_BANKC	0x2000
++#define GLAMO_GPIO_BANKD	0x3000
++
++#define GLAMO_GPIONO(bank, pin)	((bank & 0xf000) | ((pin & 0xf) << 8))
++
++#define GLAMO_GPIO_F_IN		0x0010
++#define GLAMO_GPIO_F_OUT	0x0020
++#define GLAMO_GPIO_F_FUNC	0x0030
++
++#define GLAMO_GPIO0		GLAMO_GPIONO(GLAMO_GPIO_BANKA, 0)
++#define GLAMO_GPIO0_INPUT	(GLAMO_GPIO0 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO0_OUTPUT	(GLAMO_GPIO0 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO0_HA20	(GLAMO_GPIO0 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO1		GLAMO_GPIONO(GLAMO_GPIO_BANKA, 1)
++#define GLAMO_GPIO1_INPUT	(GLAMO_GPIO1 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO1_OUTPUT	(GLAMO_GPIO1 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO1_HA21	(GLAMO_GPIO1 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO2		GLAMO_GPIONO(GLAMO_GPIO_BANKA, 2)
++#define GLAMO_GPIO2_INPUT	(GLAMO_GPIO2 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO2_OUTPUT	(GLAMO_GPIO2 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO2_HA22	(GLAMO_GPIO2 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO3		GLAMO_GPIONO(GLAMO_GPIO_BANKA, 3)
++#define GLAMO_GPIO3_INPUT	(GLAMO_GPIO3 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO3_OUTPUT	(GLAMO_GPIO3 | GLAMO_GPIO_F_OUT)
++#define	GLAMO_GPIO3_HA23	(GLAMO_GPIO3 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO4		GLAMO_GPIONO(GLAMO_GPIO_BANKB, 0)
++#define GLAMO_GPIO4_INPUT	(GLAMO_GPIO4 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO4_OUTPUT	(GLAMO_GPIO4 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO4_nLCS0	(GLAMO_GPIO4 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO5		GLAMO_GPIONO(GLAMO_GPIO_BANKB, 1)
++#define GLAMO_GPIO5_INPUT	(GLAMO_GPIO5 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO5_OUTPUT	(GLAMO_GPIO5 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO5_nLCS1	(GLAMO_GPIO5 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO6		GLAMO_GPIONO(GLAMO_GPIO_BANKB, 2)
++#define GLAMO_GPIO6_INPUT
++#define GLAMO_GPIO6_OUTPUT
++#define GLAMO_GPIO6_LDCLK
++
++#define GLAMO_GPIO7		GLAMO_GPIONO(GLAMO_GPIO_BANKB, 3)
++#define GLAMO_GPIO7_INPUT
++#define GLAMO_GPIO7_OUTPUT
++#define GLAMO_GPIO7_nLDE
++
++#define GLAMO_GPIO8		GLAMO_GPIONO(GLAMO_GPIO_BANKC, 0)
++#define GLAMO_GPIO8_INPUT
++#define GLAMO_GPIO8_OUTPUT
++#define GLAMO_GPIO8_LD16
++
++#define GLAMO_GPIO9		GLAMO_GPIONO(GLAMO_GPIO_BANKC, 1)
++#define GLAMO_GPIO9_INPUT
++#define GLAMO_GPIO9_OUTPUT
++#define GLAMO_GPIO9_LD17
++
++#define GLAMO_GPIO10		GLAMO_GPIONO(GLAMO_GPIO_BANKC, 2)
++#define GLAMO_GPIO10_INPUT	(GLAMO_GPIO10 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO10_OUTPUT	(GLAMO_GPIO10 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO10_LSCK	(GLAMO_GPIO10 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO11		GLAMO_GPIONO(GLAMO_GPIO_BANKC, 3)
++#define GLAMO_GPIO11_INPUT	(GLAMO_GPIO11 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO11_OUTPUT	(GLAMO_GPIO11 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO11_LSDA	(GLAMO_GPIO11 | GLAMO_GPIO_F_FUNC)
++
++#define GLAMO_GPIO12		GLAMO_GPIONO(GLAMO_GPIO_BANKD, 0)
++#define GLAMO_GPIO12_INPUT	(GLAMO_GPIO12 | GLAMO_GPIO_F_IN)
++#define GLAMO_GPIO12_OUTPUT	(GLAMO_GPIO12 | GLAMO_GPIO_F_OUT)
++#define GLAMO_GPIO12_LSA0	(GLAMO_GPIO12 | GLAMO_GPIO_F_FUNC)
++
++
++/* shift by 11 is implicit of shift by 12, multiplied by 2 */
++#define REG_OF_GPIO(gpio)	(((gpio & 0xf000) >> 11) + GLAMO_REG_GPIO_GEN1)
++#define NUM_OF_GPIO(gpio)	((gpio & 0x0f00) >> 8)
++#define GPIO_OUT_BIT(gpio)	(1 << (NUM_OF_GPIO(gpio) + 0))
++#define OUTPUT_BIT(gpio)	(1 << (NUM_OF_GPIO(gpio) + 4))
++#define INPUT_BIT(gpio)		(1 << (NUM_OF_GPIO(gpio) + 8))
++#define FUNC_BIT(gpio)		(1 << (NUM_OF_GPIO(gpio) + 12))
++
++void glamo_gpio_setpin(struct glamo_core *glamo, unsigned int pin,
++		       unsigned int value);
++
++int glamo_gpio_getpin(struct glamo_core *glamo, unsigned int pin);
++
++void glamo_gpio_cfgpin(struct glamo_core *glamo, unsigned int pinfunc);
++
++
++#endif /* _GLAMO_GPIO */





More information about the commitlog mailing list