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