aboutsummaryrefslogtreecommitdiffstats
path: root/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch
diff options
context:
space:
mode:
authorJoshua Lock <josh@linux.intel.com>2010-05-18 14:51:13 +0100
committerJoshua Lock <josh@linux.intel.com>2010-05-19 12:20:16 +0100
commit5e8c7c54a9b297dae0081dd19a7bb94e23040a3d (patch)
tree948e3642c1bf426870b83c72c68c997dce66766c /meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch
parent5e07bc91281969d54896dd0a13e3d6134e432027 (diff)
downloadopenembedded-core-contrib-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.gz
linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0
Signed-off-by: Joshua Lock <josh@linux.intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch1648
1 files changed, 1648 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch
new file mode 100644
index 0000000000..f23aec3c65
--- /dev/null
+++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch
@@ -0,0 +1,1648 @@
+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 */