Index: linux-2.6.33/drivers/spi/Kconfig
===================================================================
--- linux-2.6.33.orig/drivers/spi/Kconfig
+++ linux-2.6.33/drivers/spi/Kconfig
@@ -339,6 +339,10 @@ config SPI_MRST_GTM501
 	tristate "SPI protocol driver for GTM501l"
 	depends on SPI_MRST
 
+config SPI_IFX_GPS
+	tristate "SPI protocol driver for IFX HH2 GPS"
+	depends on SPI_MRST
+
 config SPI_SPIDEV
 	tristate "User mode SPI device driver support"
 	depends on EXPERIMENTAL
Index: linux-2.6.33/drivers/spi/Makefile
===================================================================
--- linux-2.6.33.orig/drivers/spi/Makefile
+++ linux-2.6.33/drivers/spi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_STMP3XXX)		+= spi_stmp.
 obj-$(CONFIG_SPI_NUC900)		+= spi_nuc900.o
 obj-$(CONFIG_SPI_MRST)			+= mrst_spi.o
 obj-$(CONFIG_SPI_MRST_GTM501)		+= gtm501l_spi.o
+obj-$(CONFIG_SPI_IFX_GPS)		+= hh2serial.o
 
 # special build for s3c24xx spi driver with fiq support
 spi_s3c24xx_hw-y			:= spi_s3c24xx.o
Index: linux-2.6.33/drivers/spi/hh2serial.c
===================================================================
--- /dev/null
+++ linux-2.6.33/drivers/spi/hh2serial.c
@@ -0,0 +1,1572 @@
+/*
+ *  HH2 SPI Serial driver
+ *
+ *  Copyright (C) 2009 Markus Burvall (Markus.Burvall@swedenconnectivity.com)
+ *
+ *  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, version 2 of the License.
+ *
+ */
+
+
+#define DEBUG 1
+
+//#define HH2_TTY_ECHO
+//#define HH2_TTY_SEND_POLL
+//#define HH2_NO_SPI
+#define HH2SERIAL_SPI_16BIT
+//#define HH2SERIAL_ENABLE_DEBUG
+#define HH2SERIAL_SPI_POLL
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+
+#ifndef HH2_NO_SPI
+#include <linux/spi/spi.h>
+#include <linux/spi/mrst_spi.h>
+#endif
+
+MODULE_AUTHOR("Markus Burvall <Markus.Burvall@swedenconnectivity.com>");
+MODULE_DESCRIPTION("HH2 Serial Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("hh2serial");
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+
+#define FUNC_ENTER() do { printk("ENTER: %s\n", __func__); } while (0)
+
+#else
+
+#define FUNC_ENTER()
+
+#endif
+
+
+struct hh2serial_dev {
+    struct uart_port port;
+    bool tx_enabled;
+    bool rx_enabled;
+    struct spi_device *spi;
+
+    struct task_struct *main_thread;
+    struct task_struct *poll_thread;
+
+    wait_queue_head_t wq;
+    atomic_t spi_need_read;
+    atomic_t tty_need_read;
+    atomic_t spi_irq_pending;
+    int mthread_up;
+};
+
+static const char driver_name[] = "hh2serial";
+static const char tty_dev_name[] = "ttyHH2";
+static struct hh2serial_dev priv0;
+
+
+/* max len for a spi transfer is 18B */
+#define HH2SERIAL_SPI_MAX_BYTES 18
+/* 16 bits / byte + read and write gives 4*18 = 72 */
+#define HH2SERIAL_BUFSIZE 72
+
+
+#ifdef HH2SERIAL_SPI_POLL
+#define HH2SERIAL_POLL_TIMEOUT 100
+#endif
+
+/*      HH2 DATA OPERATIONS      */
+#define GPSD_SRREAD               0x80    /* bit 7 */
+#define GPSD_DWRITE               0x40    /* bit 6 */
+#define GPSD_DREAD                0xC0    /* bit 7 and 6 */
+#define GPSD_CRWRITE              0x00    /* All zero */
+
+#ifdef HH2SERIAL_SPI_16BIT
+/*      HH2 DATA OPERATIONS      */
+#define GPSD_16BIT_SRREAD               0x8000    /* bit 7 */
+#define GPSD_16BIT_DWRITE               0x4000    /* bit 6 */
+#define GPSD_16BIT_DREAD                0xC000    /* bit 7 and 6 */
+#define GPSD_16BIT_CRWRITE              0x0000    /* All zero */
+#endif
+
+/*      HH2 STATUS REGISTER      */
+#define GPSS_TCNT                 0x1F    /* bits [4..0] */
+#define GPSS_REMPTY               0x20    /* bit 5 */
+#define GPSS_TERR                 0x40    /* bit 6 */
+#define GPSS_RERR                 0x80    /* bit 7 */
+
+/*      HH2 CONTROL REGISTER */
+#define GPSC_ENABLE_TCNT_INTR     0x10    /* Enable Rx interrupt */
+#define GPSC_ENABLE_REMPTY_INTR   0x20    /* Enable Tx interrupt */
+#define GPSC_CLEAR_TERR           0x40    /* Clear TERR */
+#define GPSC_CLEAR_RERR           0x80    /* Clear RERR */
+#define GPSC_ENABLE_INTERRUPTS    0x30    /* Enable Interrupts through control register */
+#define GPSC_DISABLE_INTERRUPTS   0x00    /* Disable Interrupts through control register */
+
+
+/* ************************* */
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_stop_tx
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+static void hh2serial_stop_tx(struct uart_port *port)
+{
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+    FUNC_ENTER();
+    priv->tx_enabled = false;
+}
+
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_spi_get_rx_len
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+#ifndef HH2_NO_SPI
+/* Reads status register from HH2 */
+/* Negative for error */
+int hh2serial_spi_get_rx_len(struct hh2serial_dev *hh2serial)
+{
+    struct spi_device *spi = hh2serial->spi;
+    int         ret;
+    struct spi_message  message;
+    struct spi_transfer x;
+    u8          *local_buf;
+    u8          *buf_ptr;
+
+    FUNC_ENTER();
+
+    spi_message_init(&message);
+    memset(&x, 0, sizeof x);
+#ifndef HH2SERIAL_SPI_16BIT
+    x.len = 1;
+#else
+    x.len = 2;
+#endif
+    spi_message_add_tail(&x, &message);
+
+    local_buf = kzalloc((x.len * 2), GFP_KERNEL);
+    if (!local_buf)
+        return -ENOMEM;
+
+
+#ifndef HH2SERIAL_SPI_16BIT
+    local_buf[0] = GPSD_SRREAD;
+#else /* if 16 bit, write control to get status */
+    local_buf[1] = GPSD_CRWRITE;
+    local_buf[0] = GPSC_CLEAR_TERR | GPSC_CLEAR_RERR;
+    /*FIXME if not clearing errors */
+    //local_buf[0] = 0;
+#endif
+    x.tx_buf = local_buf;
+    x.rx_buf = local_buf + x.len;
+
+    x.cs_change = 0;
+    x.speed_hz = 1562500;
+
+    /* do the i/o */
+    ret = spi_sync(spi, &message);
+    if (ret == 0)
+    {
+
+        buf_ptr = x.rx_buf;
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial RD:%02X, %02X\n",
+            *buf_ptr,
+            buf_ptr[1]);
+#endif
+
+#ifndef HH2SERIAL_SPI_16BIT
+        /* 8 bit First byte is status register */
+        /* Available bytes */
+        ret = *buf_ptr & GPSS_TCNT;
+
+        /* Check buffer overrun or underrun errors */
+        if (*buf_ptr & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (*buf_ptr & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+
+#else
+        /* 16 bit second byte is status register */
+        /* Available bytes */
+        ret = buf_ptr[1] & GPSS_TCNT;
+
+        /* Check buffer overrun or underrun errors */
+        if (buf_ptr[1] & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (buf_ptr[1] & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+#endif
+        /* Take care of errors */
+        /* FIX ME */
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial SR:%02X, rx len %d\n",
+            buf_ptr[1],
+            ret);
+#endif
+    }
+
+    kfree(local_buf);
+    return ret;
+
+}
+#endif
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_spi_read
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+#ifndef HH2_NO_SPI
+/* Reads maximum 18 bytes of data from SPI buffer */
+int hh2serial_spi_read(struct hh2serial_dev *hh2serial,
+        u8 *rxbuf, u8 *spiAvailData, unsigned len)
+{
+    struct spi_device *spi = hh2serial->spi;
+    int         status, available_rd;
+    struct spi_message  message;
+    struct spi_transfer x;
+    u8          *local_buf;
+    u8          *buf_ptr;
+    unsigned len_inc_hdr;
+
+    FUNC_ENTER();
+    /* FIXME check header */
+    if ((len * 2) > HH2SERIAL_BUFSIZE || !rxbuf)
+        return -EINVAL;
+
+    spi_message_init(&message);
+    memset(&x, 0, sizeof x);
+
+    /* Add header length */
+#ifndef HH2SERIAL_SPI_16BIT
+    len_inc_hdr = len+1;
+#else
+    len_inc_hdr = len;
+#endif
+
+    x.len = len_inc_hdr;
+    spi_message_add_tail(&x, &message);
+
+    local_buf = kzalloc(HH2SERIAL_BUFSIZE, GFP_KERNEL);
+    if (!local_buf)
+        return -ENOMEM;
+
+    /* Add DATA READ as every second byte */
+    local_buf[1] = GPSD_DREAD;
+#ifdef HH2SERIAL_SPI_16BIT
+    if (len_inc_hdr > 2)
+    {
+        int byte_index = 1;
+        while (byte_index < len_inc_hdr)
+        {
+            local_buf[byte_index] = GPSD_DREAD;
+            byte_index = byte_index + 2;
+        }
+    }
+
+#endif
+
+    x.tx_buf = local_buf;
+    x.rx_buf = local_buf + len_inc_hdr;
+
+
+    x.cs_change = 0;
+    x.speed_hz = 1562500;
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    if (len > 0)
+    {
+        int byte_index = 0;
+        printk(KERN_INFO "hh2serial_spi_read:\n:wr data");
+        while (byte_index < len_inc_hdr)
+        {
+            printk(KERN_INFO "%02X", (local_buf[byte_index++]));
+        }
+
+        printk(KERN_INFO "\n");
+
+
+    }
+#endif
+    /* do the i/o */
+    status = spi_sync(spi, &message);
+    if (status == 0)
+    {
+        /* First byte of read data */
+        buf_ptr = x.rx_buf;
+
+#ifndef HH2SERIAL_SPI_16BIT
+        /* 8 bit First byte is status register */
+        /* Available bytes */
+        available_rd = *buf_ptr & GPSS_TCNT;
+
+        /* Check buffer overrun or underrun errors */
+        if (*buf_ptr & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (*buf_ptr & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+#else
+        /* 16 bit second byte is status register */
+        /* Every other byte is status register */
+        /* Last status register contains Available bytes at end of op*/
+        /* This is status before the last byte is read, so -1 */
+        available_rd = (buf_ptr[len_inc_hdr-1] & GPSS_TCNT) - 1;
+
+        /* Check buffer overrun or underrun errors */
+        if (buf_ptr[len_inc_hdr-1] & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (buf_ptr[len_inc_hdr-1] & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+#endif
+
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial_spi_read len inc hdr wr:%d, avail rd %d, cs_change:%d\n",
+            len_inc_hdr,
+            available_rd,
+            x.cs_change);
+        printk(KERN_INFO "hh2serial_spi_read:%02X, %02X\n",
+            *buf_ptr,
+            buf_ptr[1]);
+
+#endif
+
+        /* Don't copy status byte */
+#ifndef HH2SERIAL_SPI_16BIT
+        buf_ptr++;
+#endif
+
+        *spiAvailData = available_rd;
+        memcpy(rxbuf, buf_ptr, len);
+
+        /* Print incoming message */
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        if (len > 0)
+        {
+            int byte_index = 0;
+            printk(KERN_INFO "hh2serial_spi_read:\n:rd data");
+            while (byte_index < len)
+            {
+                printk(KERN_INFO "%02X", (rxbuf[byte_index++]));
+            }
+            printk(KERN_INFO "\n");
+
+        }
+#endif
+
+    }
+
+    kfree(local_buf);
+    return status;
+}
+#endif
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_spi_write
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+#ifndef HH2_NO_SPI
+int hh2serial_spi_write(struct hh2serial_dev *hh2serial,
+        const u8 *txbuf, u8 *spiAvailData, unsigned len)
+{
+    struct spi_device *spi = hh2serial->spi;
+    int         status, available_rd;
+    struct spi_message  message;
+    struct spi_transfer x;
+    u8          *local_buf;
+    u8          *buf_ptr;
+    unsigned len_inc_hdr;
+
+    FUNC_ENTER();
+
+    if ((len * 2) > HH2SERIAL_BUFSIZE )
+        return -EINVAL;
+
+
+    spi_message_init(&message);
+    memset(&x, 0, sizeof x);
+
+    /* Add header length */
+#ifndef HH2SERIAL_SPI_16BIT
+    len_inc_hdr = len+1;
+#else
+    len_inc_hdr = len;
+#endif
+
+    x.len = len_inc_hdr;
+    spi_message_add_tail(&x, &message);
+
+    /* Allocate and make room for 1 byte header */
+    local_buf = kzalloc(HH2SERIAL_BUFSIZE+1, GFP_KERNEL);
+    if (!local_buf)
+        return -ENOMEM;
+
+    /* Add write header */
+    local_buf[1] = GPSD_DWRITE;
+    local_buf[0] = txbuf[0];
+
+
+#ifndef HH2SERIAL_SPI_16BIT
+    memcpy(&(local_buf[1]), txbuf, len);
+#else
+    if (len_inc_hdr > 2)
+    {
+        int byte_index = 2;
+        while (byte_index < len_inc_hdr)
+        {
+
+            local_buf[byte_index] = txbuf[byte_index];
+            local_buf[byte_index+1] = GPSD_DWRITE;
+            byte_index = byte_index + 2;
+        }
+    }
+#endif
+
+    x.tx_buf = local_buf;
+    x.rx_buf = local_buf +(len_inc_hdr);
+
+    x.cs_change = 0;
+    x.speed_hz = 1562500;
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    if (len > 0)
+    {
+        int byte_index = 0;
+        printk(KERN_INFO "hh2serial_spi_write:\n:wr data");
+        while (byte_index < len_inc_hdr)
+        {
+            printk(KERN_INFO "%02X", (local_buf[byte_index++]));
+        }
+        printk(KERN_INFO "\n");
+
+
+    }
+#endif
+
+    /* do the i/o */
+    status = spi_sync(spi, &message);
+    if (status == 0)
+    {
+        /* read data */
+        buf_ptr = x.rx_buf;
+
+#ifndef HH2SERIAL_SPI_16BIT
+        /* 8 bit First byte is status register */
+        /* Available bytes */
+        available_rd = *buf_ptr & GPSS_TCNT;
+
+        /* Check buffer overrun or underrun errors */
+        if (*buf_ptr & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (*buf_ptr & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+#else
+        /* 16 bit second byte is status register */
+        /* Available bytes */
+        available_rd = buf_ptr[1] & GPSS_TCNT;
+
+        /* Check buffer overrun or underrun errors */
+        if (buf_ptr[1] & GPSS_TERR)
+            printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+        if (buf_ptr[1] & GPSS_RERR)
+            printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+#endif
+
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial_spi_write:%02X, %02X\n",
+            *buf_ptr,
+            buf_ptr[1]);
+
+        printk(KERN_INFO "hh2serial_spi_write: wr:%d, avail rd %d\n",
+            len,
+            available_rd);
+#endif
+
+        *spiAvailData = available_rd;
+
+
+    }
+
+
+
+    kfree(local_buf);
+    return status;
+}
+#endif
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_write2tty
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+static void hh2serial_write2tty(
+    struct hh2serial_dev *priv, unsigned char *str, int len)
+{
+    struct uart_port *port = &priv->port;
+    struct tty_struct *tty;
+    int usable;
+
+    FUNC_ENTER();
+
+    /* if uart is not opened, will just return */
+    if (!port->state)
+        return;
+
+    tty = port->state->port.tty;
+    if (!tty)
+        return; /* receive some char before the tty is opened */
+
+    /* MRB  could lock forever if no space  in tty buffer */
+    while (len) {
+        usable = tty_buffer_request_room(tty, len);
+        if (usable) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk(KERN_INFO "hh2serial_output_tty buf space: %d\n", usable);
+#endif
+            tty_insert_flip_string(tty, str, usable);
+            str += usable;
+            port->icount.rx += usable;
+            tty_flip_buffer_push(tty);
+        }
+        len -= usable;
+    }
+}
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_write_circ_buf2spi
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+#ifndef HH2_NO_SPI
+static inline void hh2serial_write_circ_buf2spi(struct hh2serial_dev *priv,
+                struct circ_buf *xmit)
+{
+    int len, left = 0;
+#ifndef HH2SERIAL_SPI_16BIT
+    u8 obuf[HH2SERIAL_SPI_MAX_BYTES], ibuf[HH2SERIAL_SPI_MAX_BYTES];
+#else
+    u16 obuf[HH2SERIAL_SPI_MAX_BYTES], ibuf[HH2SERIAL_SPI_MAX_BYTES];
+#endif
+    u8 rxlen;
+    u8 valid_str[HH2SERIAL_SPI_MAX_BYTES];
+
+    int i, j;
+
+    FUNC_ENTER();
+
+    while (!uart_circ_empty(xmit)) {
+        /*
+            printk(KERN_INFO "MrB set CR get SR: %d\n",
+            hh2serial_spi_get_rx_len(priv));
+        */
+
+        left = uart_circ_chars_pending(xmit);
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "Bytes in circ buffer: %d\n", left);
+#endif
+        while (left) {
+            /* MrB Change below to 1 and word length to 16 to write 16 bit
+               word by word */
+#ifndef HH2SERIAL_SPI_16BIT
+            len = (left >= HH2SERIAL_SPI_MAX_BYTES) ? HH2SERIAL_SPI_MAX_BYTES : left;
+#else
+            len = (left >= HH2SERIAL_SPI_MAX_BYTES) ? HH2SERIAL_SPI_MAX_BYTES : left;
+#endif
+
+            memset(obuf, 0, len);
+            memset(ibuf, 0, len);
+            for (i = 0; i < len; i++) {
+
+                obuf[i] = (u8)xmit->buf[xmit->tail];
+
+                xmit->tail = (xmit->tail + 1) &
+                        (UART_XMIT_SIZE - 1);
+            }
+#ifndef HH2SERIAL_SPI_16BIT
+
+            hh2serial_spi_write(priv, (u8 *)obuf,
+                        &rxlen, len);
+
+#else
+            /* len * 2 since 16 bits instead of 8 bits */
+            hh2serial_spi_write(priv, (u8 *)obuf,
+                        &rxlen, len*2);
+
+#endif
+            left -= len;
+        }
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial: Bytes avail to read: %d\n", rxlen);
+#endif
+        /* Read if available bytes */
+        /* FIXME: Could add a maximum read loop here */
+        while (rxlen > 0)
+        {
+
+            len = rxlen;
+#ifndef HH2SERIAL_SPI_16BIT
+            hh2serial_spi_read(priv, (u8 *)ibuf, &rxlen, len);
+#else
+            hh2serial_spi_read(priv, (u8 *)ibuf, &rxlen, len*2);
+#endif
+
+            for (i = 0, j = 0; i < len; i++) {
+                valid_str[j++] = (u8)(ibuf[i]);
+            }
+
+            if (j)
+                hh2serial_write2tty(priv, valid_str, j);
+
+            priv->port.icount.tx += len;
+        }
+    }
+}
+#endif
+
+
+/*******************************************************************************
+ * FUNCTION:    hh2serial_handle_tty_input
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ ******************************************************************************/
+static void hh2serial_handle_tty_input(struct hh2serial_dev *priv)
+{
+    struct uart_port *port = &priv->port;
+    struct circ_buf *xmit = &port->state->xmit;
+
+    FUNC_ENTER();
+
+    if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+        return;
+#ifndef HH2_NO_SPI
+    hh2serial_write_circ_buf2spi(priv, xmit);
+#endif
+    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+        uart_write_wakeup(port);
+
+    if (uart_circ_empty(xmit))
+        hh2serial_stop_tx(port);
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_transfer_spi2tty
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_transfer_spi2tty(struct hh2serial_dev *priv)
+{
+    int loop = 10, len;
+    int i, j;
+    u8 valid_str[HH2SERIAL_SPI_MAX_BYTES], rxlen = 0;
+#ifndef HH2SERIAL_SPI_16BIT
+    u8 ibuf[HH2SERIAL_SPI_MAX_BYTES];
+#else
+    u16 ibuf[HH2SERIAL_SPI_MAX_BYTES];
+#endif
+
+    FUNC_ENTER();
+
+    rxlen = hh2serial_spi_get_rx_len(priv);
+
+	/* FIXME No of loops to be investigated */
+    while (rxlen > 0 && loop > 0)
+    {
+
+        len = rxlen;
+#ifndef HH2SERIAL_SPI_16BIT
+        hh2serial_spi_read(priv, (u8 *)ibuf, &rxlen, len);
+#else
+        hh2serial_spi_read(priv, (u8 *)ibuf, &rxlen, len*2);
+#endif
+
+        for (i = 0, j = 0; i < len; i++) {
+            valid_str[j++] = (u8)(ibuf[i]);
+        }
+
+        if (j)
+            hh2serial_write2tty(priv, valid_str, j);
+
+        priv->port.icount.tx += len;
+
+        loop--;
+    }
+
+}
+
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_main_thread
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int hh2serial_main_thread(void *_priv)
+{
+    struct hh2serial_dev *priv = _priv;
+    wait_queue_head_t *wq = &priv->wq;
+
+    int ret = 0;
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    printk(KERN_INFO "hh2serial: start main thread\n");
+#endif
+    init_waitqueue_head(wq);
+
+    do {
+        //udelay(delay);
+        wait_event_interruptible(*wq, (atomic_read(&priv->spi_irq_pending) ||
+                           atomic_read(&priv->spi_need_read) ||
+                           atomic_read(&priv->tty_need_read) ||
+                           kthread_should_stop()));
+
+        priv->mthread_up = 1;
+
+        /* tty has data to be read */
+        if (atomic_read(&priv->tty_need_read)) {
+            atomic_set(&priv->tty_need_read, 0);
+            /* Read from tty send to spi */
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk(KERN_INFO "hh2serial: Read from tty send to spi\n");
+#endif
+            /* Read from tty send to spi */
+            /* Receive data from spi send to UART */
+
+            hh2serial_handle_tty_input(priv);
+
+        }
+
+#ifdef HH2SERIAL_SPI_POLL
+        if (atomic_read(&priv->spi_need_read)) {
+            atomic_set(&priv->spi_need_read, 0);
+            /* Read from SPI send to UART */
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk(KERN_INFO "hh2serial: Read from SPI send to UART\n");
+#endif
+#ifndef HH2_TTY_SEND_POLL
+            hh2serial_transfer_spi2tty(priv);
+#else
+            if (priv->tx_enabled) {
+                struct uart_port *port = &priv->port;
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                printk("TX enabled!\n");
+#endif
+                spin_lock_irqsave(&port->lock, flags);
+
+
+                if (priv->rx_enabled) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                    printk(KERN_INFO "RX enabled!\n");
+#endif
+                    hh2serial_write2tty(priv, "testar", 6);
+                }
+
+
+                spin_unlock_irqrestore(&port->lock, flags);
+            }
+#endif /* HH2_TTY_SEND_POLL */
+
+        }
+#endif
+
+
+
+        if (atomic_read(&priv->spi_irq_pending)) {
+            atomic_set(&priv->spi_irq_pending, 0);
+            /* Read from SPI send to UART */
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk(KERN_INFO "hh2serial: Read from SPI send to UART\n");
+#endif
+        }
+
+
+        priv->mthread_up = 0;
+    } while (!kthread_should_stop());
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    printk(KERN_INFO "hh2serial: stopped main thread\n");
+#endif
+    return ret;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_poll_thread
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+#ifdef HH2SERIAL_SPI_POLL
+static int hh2serial_poll_thread(void *_priv)
+{
+
+    int ret = 0;
+    struct hh2serial_dev *priv = _priv;
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    printk(KERN_INFO "hh2serial: start poll thread\n");
+#endif
+    do {
+        //udelay(delay);
+
+        if (HH2SERIAL_POLL_TIMEOUT > 999)
+            ssleep(HH2SERIAL_POLL_TIMEOUT/1000);
+        else
+            msleep(HH2SERIAL_POLL_TIMEOUT);
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk(KERN_INFO "hh2serial: poll\n");
+#endif
+        if (!priv->mthread_up)
+        {
+            /* Send poll event to main */
+            if (!atomic_read(&priv->spi_need_read)) {
+                atomic_set(&priv->spi_need_read, 1);
+                wake_up_process(priv->main_thread);
+            }
+        }
+
+    } while (!kthread_should_stop());
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    printk(KERN_INFO "hh2serial: stopped poll thread\n");
+#endif
+    return ret;
+}
+#endif /* #ifdef HH2SERIAL_SPI_POLL */
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_tx_empty
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static unsigned int hh2serial_tx_empty(struct uart_port *port)
+{
+    FUNC_ENTER();
+    return TIOCSER_TEMT;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_set_mctrl
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+    FUNC_ENTER();
+
+#ifdef HH2SERIAL_ENABLE_DEBUG
+    printk("MCTRL RTS: %d\n", mctrl & TIOCM_RTS);
+    printk("MCTRL DTR: %d\n", mctrl & TIOCM_DTR);
+    printk("MCTRL OUT1: %d\n", mctrl & TIOCM_OUT1);
+    printk("MCTRL OUT2: %d\n", mctrl & TIOCM_OUT2);
+    printk("MCTRL LOOP: %d\n", mctrl & TIOCM_LOOP);
+#endif
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_get_mctrl
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static unsigned int hh2serial_get_mctrl(struct uart_port *port)
+{
+    FUNC_ENTER();
+    return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_tx_chars
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_tx_chars(struct uart_port *port)
+{
+#ifndef HH2_TTY_ECHO
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+
+    FUNC_ENTER();
+
+    if (priv->tx_enabled) {
+
+        /* if writing to SPI enabled */
+
+        /* Send message to main thread to read from tty send to SPI */
+        /* Send poll event to main */
+        if (!atomic_read(&priv->tty_need_read)) {
+            atomic_set(&priv->tty_need_read, 1);
+            wake_up_process(priv->main_thread);
+        }
+
+
+    }
+
+#else
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+    struct circ_buf *xmit = &port->state->xmit;
+
+
+
+    struct uart_port *recv_port = &priv->port;
+    struct tty_struct *recv_tty;
+
+    unsigned long flags;
+    char ch;
+
+    FUNC_ENTER();
+
+    if (priv->tx_enabled) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+        printk("TX enabled!\n");
+#endif
+        //spin_lock_irqsave(&other_port->lock, flags);
+        if (priv->rx_enabled) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk("RX enabled!\n");
+#endif
+
+            recv_tty = recv_port->state->port.tty;
+
+            if (port->x_char) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                printk("One char %c!\n", port->x_char);
+#endif
+                tty_insert_flip_char(recv_tty, port->x_char, TTY_NORMAL);
+                tty_flip_buffer_push(recv_tty);
+                port->icount.tx++;
+                port->x_char = 0;
+                return;
+            }
+
+            if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                pr_debug("STOP TX_CHARS 1\n");
+#endif
+                hh2serial_stop_tx(port);
+                return;
+            }
+
+            while (!uart_circ_empty(xmit)) {
+
+                ch = xmit->buf[xmit->tail];
+                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                printk("Loop one char %c!\n", ch);
+#endif
+                tty_insert_flip_char(recv_tty, ch, TTY_NORMAL);
+                tty_flip_buffer_push(recv_tty);
+                port->icount.tx++;
+            }
+
+            if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+            {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                printk("Uart wakeup!\n");
+#endif
+                uart_write_wakeup(port);
+            }
+
+            if (uart_circ_empty(xmit)) {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+                pr_debug("STOP TX_CHARS 2\n");
+#endif
+                hh2serial_stop_tx(port);
+            }
+        }
+        else
+        {
+#ifdef HH2SERIAL_ENABLE_DEBUG
+            printk("Other port disabled!\n");
+#endif
+        }
+        //spin_unlock_irqrestore(&priv->other_priv->port.lock, flags);
+    }
+
+#endif
+
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_start_tx
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_start_tx(struct uart_port *port)
+{
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+    FUNC_ENTER();
+    priv->tx_enabled = true;
+
+    hh2serial_tx_chars(port);
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_stop_rx
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_stop_rx(struct uart_port *port)
+{
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+    FUNC_ENTER();
+    priv->rx_enabled = false;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_enable_ms
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_enable_ms(struct uart_port *port)
+{
+    FUNC_ENTER();
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_break_ctl
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_break_ctl(struct uart_port *port, int break_state)
+{
+    FUNC_ENTER();
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_startup
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int hh2serial_startup(struct uart_port *port)
+{
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+    FUNC_ENTER();
+
+#ifdef HH2SERIAL_SPI_POLL
+    priv->poll_thread = kthread_run(hh2serial_poll_thread,
+                    priv, "hh2serial_poll");
+    if (IS_ERR(priv->poll_thread)) {
+        printk(KERN_INFO "hh2serial Failed to start poll thread: %ld",
+            PTR_ERR(priv->poll_thread));
+    }
+#endif
+
+    spin_lock(&port->lock);
+    priv->rx_enabled = true;
+    spin_unlock(&port->lock);
+    return 0;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_shutdown
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_shutdown(struct uart_port *port)
+{
+#ifdef HH2SERIAL_SPI_POLL
+    struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+#endif
+    FUNC_ENTER();
+#ifdef HH2SERIAL_SPI_POLL
+    if (priv->poll_thread)
+        kthread_stop(priv->poll_thread);
+#endif
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_set_termios
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_set_termios(struct uart_port *port,
+                  struct ktermios *termios,
+                  struct ktermios *old)
+{
+    FUNC_ENTER();
+
+    switch (termios->c_cflag & CSIZE) {
+    case CS5:
+        pr_debug("CS5: data bits 5\n");
+        break;
+    case CS6:
+        pr_debug("CS6: data bits 6\n");
+        break;
+    case CS7:
+        pr_debug("CS7: data bits 7\n");
+        break;
+    case CS8:
+        pr_debug("CS8: data bits 8\n");
+        break;
+    default:
+        pr_debug("CS: Unknown\n");
+        break;
+    }
+
+    if (termios->c_cflag & PARENB) {
+        if (termios->c_cflag & PARODD)
+            pr_debug("PARITY ODD\n");
+        else
+            pr_debug("PARITY EVEN\n");
+    } else {
+        pr_debug("PARITY NONE\n");
+    }
+
+    if (termios->c_cflag & CSTOPB)
+        pr_debug("STOP BITS 2\n");
+    else
+        pr_debug("STOP BITS 1\n");
+
+    if (termios->c_cflag & CRTSCTS)
+        pr_debug("RTS CTS ENABLED\n");
+    else
+        pr_debug("RTS CTS DISABLED\n");
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_type
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static const char *hh2serial_type(struct uart_port *port)
+{
+    FUNC_ENTER();
+    return "VUART";
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_request_port
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int hh2serial_request_port(struct uart_port *port)
+{
+    FUNC_ENTER();
+    return 0;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_config_port
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_config_port(struct uart_port *port, int flags)
+{
+    FUNC_ENTER();
+
+    if (flags & UART_CONFIG_TYPE)
+        port->type = PORT_16550A;
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_release_port
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void hh2serial_release_port(struct uart_port *port)
+{
+    FUNC_ENTER();
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_verify_port
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int hh2serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+    FUNC_ENTER();
+    return 0;
+}
+
+static struct uart_ops hh2serial_uart_ops = {
+    .tx_empty   = hh2serial_tx_empty,
+    .set_mctrl  = hh2serial_set_mctrl,
+    .get_mctrl  = hh2serial_get_mctrl,
+    .stop_tx    = hh2serial_stop_tx,
+    .start_tx   = hh2serial_start_tx,
+    .stop_rx    = hh2serial_stop_rx,
+    .enable_ms  = hh2serial_enable_ms,
+    .break_ctl  = hh2serial_break_ctl,
+    .startup    = hh2serial_startup,
+    .shutdown   = hh2serial_shutdown,
+    .set_termios    = hh2serial_set_termios,
+    .type       = hh2serial_type,
+    .release_port   = hh2serial_release_port,
+    .request_port   = hh2serial_request_port,
+    .config_port    = hh2serial_config_port,
+    .verify_port    = hh2serial_verify_port,
+};
+
+#ifndef HH2_NO_SPI
+/* pure SPI related functions */
+/*******************************************************************************
+ * FUNCTION:	serial_hh2serial_suspend
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int serial_hh2serial_suspend(struct spi_device *spi, pm_message_t state)
+{
+    FUNC_ENTER();
+    return 0;
+}
+
+/*******************************************************************************
+ * FUNCTION:	serial_hh2serial_resume
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int serial_hh2serial_resume(struct spi_device *spi)
+{
+    FUNC_ENTER();
+    return 0;
+}
+
+
+static struct mrst_spi_chip hh2spi0 = {
+    .poll_mode = 1,
+    .enable_dma = 0,
+    .type = SPI_FRF_SPI,
+};
+
+
+/*******************************************************************************
+ * FUNCTION:	serial_hh2serial_probe
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int serial_hh2serial_probe(struct spi_device *spi)
+{
+    FUNC_ENTER();
+#ifndef HH2_NO_SPI
+
+    /* set spi info */
+    spi->mode = SPI_MODE_0;
+#ifndef HH2SERIAL_SPI_16BIT
+    spi->bits_per_word = 8; /* HH2 uses 8 bits */
+#else
+    spi->bits_per_word = 16; /* HH2 uses 8 bits, test with 16, sends byte by byte */
+#endif
+
+    spi->controller_data = &hh2spi0;
+
+    spi_setup(spi);
+    priv0.spi = spi;
+    atomic_set(&priv0.spi_irq_pending, 0);
+#endif
+
+
+    return 0;
+
+
+}
+
+/*******************************************************************************
+ * FUNCTION:	hh2serial_remove
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int hh2serial_remove(struct spi_device *dev)
+{
+    FUNC_ENTER();
+
+    return 0;
+}
+
+
+static struct spi_driver spi_hh2serial_driver = {
+    .driver = {
+            .name = "spi_ifx_gps",
+            //.name   = "spi_flash",
+            .bus    = &spi_bus_type,
+            .owner  = THIS_MODULE,
+    },
+    .probe      = serial_hh2serial_probe,
+    .remove     = __devexit_p(hh2serial_remove),
+    .suspend    = serial_hh2serial_suspend,
+    .resume     = serial_hh2serial_resume,
+};
+
+#endif
+
+static struct uart_driver hh2serial_driver = {
+    .owner      = THIS_MODULE,
+    .driver_name    = driver_name,
+    .dev_name   = tty_dev_name,
+    .major      = 240,
+    .minor      = 0,
+    .nr     = 1,
+};
+
+/*******************************************************************************
+ * FUNCTION:	__init
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static int __init
+hh2serial_init (void)
+{
+    int ret;
+
+    ret = uart_register_driver(&hh2serial_driver);
+
+    if (ret) {
+        pr_err("%s: could not register UART driver\n", driver_name);
+        goto out_register_driver;
+    }
+
+    memset(&priv0, sizeof(struct hh2serial_dev), 0);
+    priv0.port.line = 0;
+    priv0.port.ops = &hh2serial_uart_ops;
+    priv0.port.type = PORT_16550A;
+    spin_lock_init(&priv0.port.lock);
+
+    ret = uart_add_one_port(&hh2serial_driver, &priv0.port);
+
+    if (ret) {
+        pr_err("%s: could not add port hh2serial0\n", driver_name);
+        goto out_add_port0;
+    }
+
+    atomic_set(&priv0.spi_need_read, 0);
+    atomic_set(&priv0.tty_need_read, 0);
+    atomic_set(&priv0.spi_irq_pending, 0);
+
+
+
+#ifndef HH2_NO_SPI
+    /* Register SPI device driver*/
+    ret = spi_register_driver(&spi_hh2serial_driver);
+    if (ret)
+    {
+        pr_err("%s: could not register driver spi_hh2serial_driver\n", driver_name);
+        goto out_add_spi;
+    }
+#endif
+
+
+    priv0.main_thread = kthread_run(hh2serial_main_thread,
+                    &priv0, "hh2serial_main");
+    if (IS_ERR(priv0.main_thread)) {
+        ret = PTR_ERR(priv0.main_thread);
+        goto err_kthread;
+    }
+
+
+
+    printk ("Module %s loaded\n", driver_name);
+    return 0;
+
+err_kthread:
+
+#ifndef HH2_NO_SPI
+out_add_spi:
+    uart_remove_one_port(&hh2serial_driver, &priv0.port);
+#endif
+out_add_port0:
+    uart_unregister_driver(&hh2serial_driver);
+out_register_driver:
+    return ret;
+}
+
+/*******************************************************************************
+ * FUNCTION:	__exit
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS:	
+ *
+ * RETURN:	
+ *
+ ******************************************************************************/
+static void __exit
+hh2serial_exit (void)
+{
+    if (priv0.main_thread)
+        kthread_stop(priv0.main_thread);
+
+#ifndef HH2_NO_SPI
+    /* unregister SPI driver */
+    spi_unregister_driver(&spi_hh2serial_driver);
+#endif
+    uart_remove_one_port(&hh2serial_driver, &priv0.port);
+
+    uart_unregister_driver(&hh2serial_driver);
+    printk ("Module %s removed\n", driver_name);
+}
+
+
+
+module_init(hh2serial_init);
+module_exit(hh2serial_exit);
Index: linux-2.6.33/drivers/misc/intel_mrst.c
===================================================================
--- linux-2.6.33.orig/drivers/misc/intel_mrst.c
+++ linux-2.6.33/drivers/misc/intel_mrst.c
@@ -131,9 +131,11 @@ static int intel_mrst_bringup_8688_sdio2
 {
 	unsigned int temp = 0;
 
-	/* Register 0xf4 has 2 GPIO lines connected to the MRVL 8688:
+	/* Register 0xf4 has 4 GPIO lines connected to the MRVL 8688 * IFX GPS:
 	 *     bit 4: PDn
-	 *     bit 3: WiFi RESETn */
+	 *     bit 3: WiFi RESETn
+	 *     bit 2: GPS RESET_N
+	 *     bit 1: GPS PD_N*/
 
 	intel_mrst_pmic_read(0xf4, &temp);
 	temp = temp|0x8;
@@ -142,6 +144,12 @@ static int intel_mrst_bringup_8688_sdio2
 	temp = temp|0x10;
 	intel_mrst_pmic_write(0xf4, temp);
 
+	temp = temp|0x04;
+        intel_mrst_pmic_write(0xf4, temp);
+
+        temp = temp|0x02;
+        intel_mrst_pmic_write(0xf4, temp);
+
 	return 0;
 }
 
@@ -187,10 +195,10 @@ static int __init intel_mrst_module_init
 /* We only need the following PMIC register initializations if
  * we are using the Marvell 8688 WLAN card on the SDIO2 port */
 
-#ifdef CONFIG_8688_RC
+#if defined(CONFIG_8688_RC) || defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_SPI_IFX_GPS)
 
 	printk(KERN_INFO "intel_mrst_module_init: bringing up power for "
-	       "8688 WLAN on SDIO2...\n");
+	       "8688 WLAN on SDIO2 & IFX GPS over SPI...\n");
 	ret = intel_mrst_bringup_8688_sdio2();
 
 #endif /* CONFIG_8688_RC */
