diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch | 1648 |
1 files changed, 1648 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-ifxgps-driver.patch new file mode 100644 index 000000000..f23aec3c6 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-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 */ |