summaryrefslogtreecommitdiffstats
path: root/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch3342
1 files changed, 3342 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch
new file mode 100644
index 0000000000..7336ae66ca
--- /dev/null
+++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch
@@ -0,0 +1,3342 @@
+From: Prajwal Mohan <prajwal.karur.mohan@intel.com>
+Date: Tue, 27 Apr 2010 11:23:00 -0700
+Subject: [PATCH] Aava specific patches
+
+This driver is from aava
+
+Signed-off-by: Prajwal Mohan <prajwal.karur.mohan@intel.com>
+Patch-mainline: 2.6.34
+---
+Index: linux-2.6.33/drivers/misc/mrst_test_ipc/ipc_module.c
+===================================================================
+--- linux-2.6.33.orig/drivers/misc/mrst_test_ipc/ipc_module.c
++++ linux-2.6.33/drivers/misc/mrst_test_ipc/ipc_module.c
+@@ -44,8 +44,13 @@
+ #include <linux/uaccess.h>
+ #include <linux/time.h>
+
++
++
+ #include <asm/ipc_defs.h>
+
++#include <linux/device.h>
++#include <linux/ipc_module.h>
++
+ static u32 major;
+ #define MAX_FW_SIZE 264192
+
+@@ -53,9 +58,11 @@ int init_ipc_driver(void);
+ int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long arg);
+ const struct file_operations ipc_fops = {
++owner:THIS_MODULE,
+ ioctl:ipc_ioctl,
+ };
+
++static struct class *mid_ipc_class;
+
+ int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long arg)
+@@ -71,6 +78,18 @@ int ipc_ioctl(struct inode *inode, struc
+ u8 *fw_buf = NULL ;
+
+ switch (cmd) {
++ case IPC_IOC_PMIC_REG_READ:
++ cmd = IPC_PMIC_REGISTER_READ;
++ break;
++ case IPC_IOC_PMIC_REG_WRITE:
++ cmd = IPC_PMIC_REGISTER_WRITE;
++ break;
++ default:
++ printk(KERN_INFO "ioctl <UNRECOGNIZED> received\n");
++ break;
++ }
++
++ switch (cmd) {
+ case IPC_PMIC_REGISTER_READ:
+ {
+ printk(KERN_INFO
+@@ -169,6 +188,8 @@ int ipc_ioctl(struct inode *inode, struc
+
+ static int __init ipc_module_init(void)
+ {
++ struct device *dev;
++
+ printk(KERN_INFO "Init ipc_module\n");
+
+ major = register_chrdev(0, "mid_ipc", &ipc_fops);
+@@ -177,6 +198,23 @@ static int __init ipc_module_init(void)
+ return major;
+ }
+
++ mid_ipc_class = class_create(THIS_MODULE, "mid_ipc");
++ if (IS_ERR(mid_ipc_class)) {
++ unregister_chrdev(major, "mid_ipc");
++ return PTR_ERR(mid_ipc_class);
++ }
++
++ dev = device_create(mid_ipc_class,
++ NULL,
++ MKDEV(major, 0),
++ NULL,
++ "mid_ipc" );
++ if (IS_ERR(dev)) {
++ class_destroy(mid_ipc_class);
++ unregister_chrdev(major, "mid_ipc");
++ return PTR_ERR(dev);
++ }
++
+ init_ipc_driver ( ) ;
+ return SUCCESS;
+
+@@ -184,6 +222,8 @@ static int __init ipc_module_init(void)
+
+ static void __exit ipc_module_exit(void)
+ {
++ device_destroy(mid_ipc_class, MKDEV(major, 0));
++ class_destroy(mid_ipc_class);
+ unregister_chrdev(major, "mid_ipc");
+ }
+
+Index: linux-2.6.33/include/linux/Kbuild
+===================================================================
+--- linux-2.6.33.orig/include/linux/Kbuild
++++ linux-2.6.33/include/linux/Kbuild
+@@ -385,3 +385,5 @@ unifdef-y += xfrm.h
+ objhdr-y += version.h
+ header-y += wimax.h
+ header-y += wimax/
++header-y += ipc_module.h
++
+Index: linux-2.6.33/drivers/gpio/gpiolib.c
+===================================================================
+--- linux-2.6.33.orig/drivers/gpio/gpiolib.c
++++ linux-2.6.33/drivers/gpio/gpiolib.c
+@@ -228,11 +228,14 @@ static ssize_t gpio_direction_show(struc
+
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
+ status = -EIO;
+- else
+- status = sprintf(buf, "%s\n",
+- test_bit(FLAG_IS_OUT, &desc->flags)
+- ? "out" : "in");
+-
++ else {
++ status = sprintf(buf,
++ "%s\n",
++ gpio_get_direction( (desc - gpio_desc) ) ==
++ DIRECTION_OUT ?
++ "out" :
++ "in");
++ }
+ mutex_unlock(&sysfs_lock);
+ return status;
+ }
+@@ -1507,6 +1510,29 @@ void gpio_set_value_cansleep(unsigned gp
+ }
+ EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+
++enum gpio_direction gpio_get_direction(unsigned gpio)
++{
++ struct gpio_chip *chip;
++ struct gpio_desc *desc = &gpio_desc[gpio];
++
++ chip = gpio_to_chip(gpio);
++ might_sleep_if(extra_checks && chip->can_sleep);
++
++ if (chip->get_direction) {
++ if (chip->get_direction(chip, gpio - chip->base) ==
++ DIRECTION_IN) {
++ clear_bit(FLAG_IS_OUT, &desc->flags);
++ return DIRECTION_IN;
++ } else {
++ set_bit(FLAG_IS_OUT, &desc->flags);
++ return DIRECTION_OUT;
++ }
++ }
++ return test_bit(FLAG_IS_OUT, &desc->flags) ?
++ DIRECTION_OUT :
++ DIRECTION_IN;
++}
++EXPORT_SYMBOL_GPL(gpio_get_direction);
+
+ #ifdef CONFIG_DEBUG_FS
+
+Index: linux-2.6.33/drivers/gpio/langwell_gpio.c
+===================================================================
+--- linux-2.6.33.orig/drivers/gpio/langwell_gpio.c
++++ linux-2.6.33/drivers/gpio/langwell_gpio.c
+@@ -107,6 +107,19 @@ static int lnw_gpio_direction_output(str
+ return 0;
+ }
+
++static enum gpio_direction lnw_gpio_get_direction(struct gpio_chip *chip,
++ unsigned offset)
++{
++ struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
++ u8 reg = offset / 32;
++ void __iomem *gpdr;
++
++ gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
++ if (readl(gpdr) & BIT(offset % 32))
++ return DIRECTION_OUT;
++ return DIRECTION_IN;
++}
++
+ static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+ {
+ struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+@@ -240,6 +253,7 @@ static int __devinit lnw_gpio_probe(stru
+ lnw->chip.label = dev_name(&pdev->dev);
+ lnw->chip.direction_input = lnw_gpio_direction_input;
+ lnw->chip.direction_output = lnw_gpio_direction_output;
++ lnw->chip.get_direction = lnw_gpio_get_direction;
+ lnw->chip.get = lnw_gpio_get;
+ lnw->chip.set = lnw_gpio_set;
+ lnw->chip.to_irq = lnw_gpio_to_irq;
+Index: linux-2.6.33/drivers/gpio/langwell_pmic_gpio.c
+===================================================================
+--- linux-2.6.33.orig/drivers/gpio/langwell_pmic_gpio.c
++++ linux-2.6.33/drivers/gpio/langwell_pmic_gpio.c
+@@ -165,15 +165,33 @@ static int pmic_gpio_direction_output(st
+ return rc;
+ }
+
+-static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
++static enum gpio_direction pmic_gpio_get_direction(struct gpio_chip *chip,
++ unsigned offset)
+ {
+- /* we only have 8 GPIO can use as input */
+ if (offset > 8) {
+- printk(KERN_ERR
+- "%s: only pin 0-7 support input\n", __func__);
+- return -1;
++ /* GPOWSs and GPOs are always outputs */
++ return DIRECTION_OUT;
+ }
+- return ipc_read_char(GPIO0 + offset) & GPIO_DIN;
++ if (ipc_read_char(GPIO0 + offset) & GPIO_DIR)
++ return DIRECTION_IN;
++ return DIRECTION_OUT;
++}
++
++static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ if (offset < 8) {
++ /* GPIOSW: Get state according to direction */
++ if (pmic_gpio_get_direction( chip, offset ) == DIRECTION_IN)
++ return (ipc_read_char(GPIO0 + offset) & GPIO_DIN);
++ return (ipc_read_char(GPIO0 + offset) & GPIO_DOU);
++ } else if (offset < 16) {
++ /* GPOSW */
++ return (ipc_read_char(GPOSWCTL0 + offset - 8) & GPOSW_DOU);
++ } else if (offset < 24) {
++ /* GPO */
++ return (ipc_read_char(GPO) & (1 << (offset - 16)));
++ }
++ return 0;
+ }
+
+ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+@@ -284,6 +302,7 @@ static int __devinit pmic_gpio_probe(str
+ pg->chip.label = "langwell_pmic";
+ pg->chip.direction_input = pmic_gpio_direction_input;
+ pg->chip.direction_output = pmic_gpio_direction_output;
++ pg->chip.get_direction = pmic_gpio_get_direction;
+ pg->chip.get = pmic_gpio_get;
+ pg->chip.set = pmic_gpio_set;
+ pg->chip.to_irq = pmic_gpio_to_irq;
+Index: linux-2.6.33/drivers/gpio/pca953x.c
+===================================================================
+--- linux-2.6.33.orig/drivers/gpio/pca953x.c
++++ linux-2.6.33/drivers/gpio/pca953x.c
+@@ -144,6 +144,24 @@ static int pca953x_gpio_direction_output
+ return 0;
+ }
+
++static enum gpio_direction pca953x_gpio_get_direction(struct gpio_chip *gc,
++ unsigned off)
++{
++ struct pca953x_chip *chip;
++ uint16_t reg_val;
++ int ret;
++
++ chip = container_of(gc, struct pca953x_chip, gpio_chip);
++
++ ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &reg_val);
++ if (ret == 0) {
++ if ( reg_val & (1u << off) )
++ return DIRECTION_IN;
++ return DIRECTION_OUT;
++ }
++ return DIRECTION_IN;
++}
++
+ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+ {
+ struct pca953x_chip *chip;
+@@ -199,6 +217,7 @@ static void pca953x_setup_gpio(struct pc
+
+ gc->direction_input = pca953x_gpio_direction_input;
+ gc->direction_output = pca953x_gpio_direction_output;
++ gc->get_direction = pca953x_gpio_get_direction;
+ gc->get = pca953x_gpio_get_value;
+ gc->set = pca953x_gpio_set_value;
+ gc->to_irq = pca953x_gpio_to_irq;
+Index: linux-2.6.33/include/asm-generic/gpio.h
+===================================================================
+--- linux-2.6.33.orig/include/asm-generic/gpio.h
++++ linux-2.6.33/include/asm-generic/gpio.h
+@@ -101,6 +101,8 @@ struct gpio_chip {
+ char **names;
+ unsigned can_sleep:1;
+ unsigned exported:1;
++ enum gpio_direction (*get_direction)(struct gpio_chip *chip,
++ unsigned offset);
+ };
+
+ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
+@@ -120,6 +122,7 @@ extern void gpio_free(unsigned gpio);
+
+ extern int gpio_direction_input(unsigned gpio);
+ extern int gpio_direction_output(unsigned gpio, int value);
++extern enum gpio_direction gpio_get_direction(unsigned gpio);
+
+ extern int gpio_get_value_cansleep(unsigned gpio);
+ extern void gpio_set_value_cansleep(unsigned gpio, int value);
+Index: linux-2.6.33/include/linux/gpio.h
+===================================================================
+--- linux-2.6.33.orig/include/linux/gpio.h
++++ linux-2.6.33/include/linux/gpio.h
+@@ -3,6 +3,11 @@
+
+ /* see Documentation/gpio.txt */
+
++enum gpio_direction {
++ DIRECTION_IN = 0,
++ DIRECTION_OUT = 1,
++};
++
+ #ifdef CONFIG_GENERIC_GPIO
+ #include <asm/gpio.h>
+
+@@ -126,6 +131,13 @@ static inline int irq_to_gpio(unsigned i
+ return -EINVAL;
+ }
+
++static inline enum gpio_direction gpio_get_direction(unsigned gpio)
++{
++ /* GPIO can never have been requested or set as {in,out}put */
++ WARN_ON(1);
++ return DIRECTION_IN;
++}
++
+ #endif
+
+ #endif /* __LINUX_GPIO_H */
+Index: linux-2.6.33/include/linux/ipc_module.h
+===================================================================
+--- /dev/null
++++ linux-2.6.33/include/linux/ipc_module.h
+@@ -0,0 +1,60 @@
++/*
++ * include/linux/ipc_module.h
++ *
++ * Copyright (C) 2009 Aava Mobile Oy
++ * Written by Mikko Kovanen <mikko.kovanen@aavamobile.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef IPC_MODULE_H
++#define IPC_MODULE_H
++
++#include <linux/types.h>
++
++#ifndef __IPC_DEFS_H__
++#define E_INVALID_CMD -249
++#define E_READ_USER_CMD -250
++#define E_READ_USER_DATA -251
++#define E_WRITE_USER_DATA -252
++#define E_PMIC_MALLOC -253
++
++#define MAX_PMICREGS 5
++#define MAX_PMIC_MOD_REGS 4
++
++struct pmicreg {
++ __u16 register_address;
++ __u8 value;
++};
++
++struct ipc_pmic_reg_data {
++ _Bool ioc;
++ struct pmicreg pmic_reg_data[MAX_PMICREGS];
++ __u8 num_entries;
++};
++#endif /* __IPC_DEFS_H__ */
++
++#define IPC_IOC_MAGIC 'a'
++
++
++#define IPC_IOC_PMIC_REG_READ _IOR(IPC_IOC_MAGIC, \
++ 0, \
++ struct ipc_pmic_reg_data)
++
++#define IPC_IOC_PMIC_REG_WRITE _IOW(IPC_IOC_MAGIC, \
++ 1, \
++ struct ipc_pmic_reg_data)
++
++#endif /* IPC_MODULE_H */
++
+Index: linux-2.6.33/drivers/input/keyboard/mrst_keypad.c
+===================================================================
+--- linux-2.6.33.orig/drivers/input/keyboard/mrst_keypad.c
++++ linux-2.6.33/drivers/input/keyboard/mrst_keypad.c
+@@ -40,6 +40,9 @@
+ #include <linux/device.h>
+ #include <linux/err.h>
+ #include <linux/gpio.h>
++/*jhuot start*/
++#include <asm/ipc_defs.h>
++/*jhuot end*/
+
+ /*
+ * Keypad Controller registers
+@@ -116,10 +119,10 @@ MODULE_DEVICE_TABLE(pci, keypad_pci_tbl)
+ #define keypad_writel(off, v) writel((v), keypad->mmio_base + (off))
+
+ #define MAX_MATRIX_KEY_NUM (8 * 8)
+-#define MAX_DIRECT_KEY_NUM (4)
++#define MAX_DIRECT_KEY_NUM (2)
+
+-#define MAX_MATRIX_KEY_ROWS (8)
+-#define MAX_MATRIX_KEY_COLS (8)
++#define MAX_MATRIX_KEY_ROWS (7)
++#define MAX_MATRIX_KEY_COLS (7)
+ #define DEBOUNCE_INTERVAL 100
+
+ #define KEY_HALFSHUTTER KEY_PROG1
+@@ -167,7 +170,7 @@ static unsigned int mrst_keycode_fn[MAX_
+
+ /* direct key map */
+ static unsigned int mrst_direct_keycode[MAX_DIRECT_KEY_NUM] = {
+- KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_HALFSHUTTER, KEY_FULLSHUTTER,
++ KEY_VOLUMEUP, KEY_VOLUMEDOWN, //KEY_HALFSHUTTER, KEY_FULLSHUTTER,
+ };
+
+ struct mrst_keypad {
+@@ -430,6 +433,8 @@ scan:
+ if ((bits_changed & (1 << row)) == 0)
+ continue;
+
++ printk(KERN_INFO "BUTTONS: "
++ "report key row %d, col %d\n", row, col);
+ input_report_key(keypad->input_dev,
+ lookup_matrix_keycode(keypad, row, col),
+ new_state[col] & (1 << row));
+@@ -513,6 +518,8 @@ static void mrst_keypad_scan_direct(stru
+
+ for (i = 0; i < keypad->direct_key_num; i++) {
+ if (bits_changed & (1 << i)) {
++ printk(KERN_INFO "BUTTONS: "
++ "scan_direct %d\n", keypad->direct_key_map[i]);
+ input_report_key(keypad->input_dev,
+ keypad->direct_key_map[i],
+ (new_state & (1 << i)));
+@@ -528,10 +535,13 @@ static irqreturn_t mrst_keypad_irq_handl
+ struct mrst_keypad *keypad = dev_id;
+ unsigned long kpc = keypad_readl(KPC);
+
++ printk(KERN_INFO "BUTTONS: irq_handler, kpc %lu\n", kpc);
+ if (kpc & KPC_DI)
++ printk(KERN_INFO "BUTTONS: mrst_keypad_scan_direct\n");
+ mrst_keypad_scan_direct(keypad);
+
+ if (kpc & KPC_MI)
++ printk(KERN_INFO "BUTTONS: mrst_keypad_scan_matrix\n");
+ mrst_keypad_scan_matrix(keypad);
+
+ return IRQ_HANDLED;
+@@ -544,13 +554,47 @@ static int mrst_keypad_gpio_init(void)
+ MAX_MATRIX_KEY_COLS + MAX_DIRECT_KEY_NUM;
+
+ /* explicitely tell which pins have been occupied... */
++/*
+ for (i = KEYPAD_MATRIX_GPIO_IN_PIN; i < pins; i++, cnt++) {
+ err = gpio_request(i, NULL);
+ if (err) {
+ printk(KERN_ERR "GPIO pin %d failed to request.\n", i);
+ goto err_request;
+ }
+- }
++ }*/
++
++ for (i = 0; i < MAX_MATRIX_KEY_ROWS; i++){
++ err = gpio_request(KEYPAD_MATRIX_GPIO_IN_PIN + i,NULL);
++
++ if (err) {
++ printk(KERN_ERR "GPIO pin %d failed to request.\n", i);
++ goto err_request;
++ }
++
++ }
++
++ for (i = 0; i < MAX_MATRIX_KEY_COLS; i++)
++ {
++ err = gpio_request(KEYPAD_MATRIX_GPIO_OUT_PIN + i, NULL);
++ if (err) {
++ printk(KERN_ERR "GPIO pin %d failed to request.\n", i);
++ goto err_request;
++ }
++
++ }
++
++ for (i = 0; i < MAX_DIRECT_KEY_NUM; i++)
++ {
++ err = gpio_request(KEYPAD_DIRECT_GPIO_IN_PIN + i,NULL);
++
++ if (err) {
++ printk(KERN_ERR "GPIO pin %d failed to request.\n", i);
++ goto err_request;
++ }
++
++
++ }
++
+
+ for (i = 0; i < MAX_MATRIX_KEY_ROWS; i++)
+ gpio_direction_input(KEYPAD_MATRIX_GPIO_IN_PIN + i);
+@@ -642,6 +686,9 @@ static int __devinit mrst_keypad_probe(s
+ struct mrst_keypad *keypad;
+ struct input_dev *input_dev;
+ int error;
++/* jhuot start */
++ struct ipc_io_bus_master_regs *p_reg_data;
++/* jhuot end */
+
+ #ifndef MODULE
+ printk(KERN_INFO MRST_KEYPAD_DRIVER_NAME "\n");
+@@ -711,6 +758,18 @@ static int __devinit mrst_keypad_probe(s
+ goto failed_free_dev;
+ }
+
++
++/* jhuot start */
++ /* Enable 75 kOhm internal pull-ups for KBD_DKIN0 and KBD_DKIN1 */
++ /*bus: 0x4h, address: 0x20h, bits 0...3 */
++ p_reg_data = kzalloc(sizeof(struct ipc_io_bus_master_regs), GFP_KERNEL);
++ /*01 = W, 04 = bus, 20 = address*/
++ p_reg_data->ctrl_reg_addr = 0x01040020;
++ /*b3-b0 = 1010 (75kOhm pull-ups) = 0xAh*/
++ p_reg_data->ctrl_reg_data = 0xA;
++ ipc_program_io_bus_master(p_reg_data);
++/* jhuot end */
++
+ /* Register the input device */
+ error = input_register_device(input_dev);
+ if (error) {
+Index: linux-2.6.33/drivers/gpu/drm/mrst/Kconfig
+===================================================================
+--- linux-2.6.33.orig/drivers/gpu/drm/mrst/Kconfig
++++ linux-2.6.33/drivers/gpu/drm/mrst/Kconfig
+@@ -23,6 +23,20 @@ config IMG_DOES_NOT_SUPPORT_MENLOW
+ help
+ Choose Menlow
+
++config DRM_MRST_AAVA
++ bool "Aava platform specific MIPI display"
++ depends on DRM_MRST
++ default n
++ help
++ Choose Aava platform MIPI display, temp option
++
++config DRM_MRST_CDK
++ bool "Aava platform specific MIPI display"
++ depends on DRM_MRST && !DRM_MRST_AAVA
++ default y
++ help
++ Choose CDK
++
+ config PVR_RELEASE
+ string "Build IMG kernel services as release"
+ depends on DRM_MRST
+Index: linux-2.6.33/drivers/misc/Makefile
+===================================================================
+--- linux-2.6.33.orig/drivers/misc/Makefile
++++ linux-2.6.33/drivers/misc/Makefile
+@@ -21,7 +21,7 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/
+ obj-$(CONFIG_SGI_GRU) += sgi-gru/
+ obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
+ obj-$(CONFIG_HP_ILO) += hpilo.o
+-obj-$(CONFIG_MRST) += intel_mrst.o
++obj-$(CONFIG_X86_MRST) += intel_mrst.o
+ obj-$(CONFIG_ISL29003) += isl29003.o
+ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar.o
+ memrar-y := memrar_allocator.o memrar_handler.o
+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
+@@ -112,6 +112,48 @@ static int intel_mrst_sdio_EVP_power_dow
+
+ static int intel_mrst_sdio_8688_power_up(void)
+ {
++/*ouljhuot start*/
++/*WLAN / BT power-up sequence:*/
++/*1. power (GPO4) & reset (GPO3) low*/
++/*2. power (GPO4) high*/
++/*3. reset (GPO3) high*/
++
++/*GPS power-up sequence:*/
++/*1. power (GPO1) & reset (GPO2) low*/
++/*2. VDD_IO and VDD_LP_PLLREG_IN high*/
++/*VDD_IO & VDD_LP_PLLREG_IN == VPMIC_1V8*/
++/*3. usleep(1) (tvddio_nreset min. 500ns)*/
++/*4. reset (GPO2) high*/
++/*5. VDD_COREREG_IN and VDD_RFREG_IN high*/
++ /*VDD_COREREG_IN == VWLAN_GPS_1V8 (GYMXIO)*/
++ /*VDD_RFREG_IN == VGPS_ANA_3V3 (GYMX33)*/
++/*6. power (GPO1) high*/
++/*7. msleep(1);*/
++ unsigned int temp = 0;
++
++ /* Register 0xf4 has 4 GPIO lines connected to the MRVL 8688 * IFX GPS:
++ * bit 4: WiFi PDn
++ * bit 3: WiFi RESETn
++ * bit 2: GPS RESET_N
++ * bit 1: GPS PD_N*/
++
++ /*WLAN POWER and RESET low*/
++ intel_mrst_pmic_read(0xf4, &temp);
++ temp &= ~0x18;
++ intel_mrst_pmic_write(0xf4, temp);
++/* msleep(1);*/
++
++ /*GPS RESET low & POWER low*/
++ intel_mrst_pmic_read(0xf4, &temp);
++ temp &= ~0x6;
++ intel_mrst_pmic_write(0xf4, temp);
++/* usleep(1);*/
++
++ msleep(1);
++ /*GPS RESET high*/
++ temp |= 0x4;
++ intel_mrst_pmic_write(0xf4, temp);
++/*ouljhuot end*/
+ intel_mrst_pmic_write(0x37, 0x3f); /* Set VDDQ for Marvell 8688 */
+ intel_mrst_pmic_write(0x4a, 0x3f); /* Set GYMXIOCNT for Marvell 8688 */
+ intel_mrst_pmic_write(0x4e, 0x3f); /* Set GYMX33CNT for Marvell 8688 */
+@@ -124,6 +166,22 @@ static int intel_mrst_sdio_8688_power_up
+ intel_mrst_pmic_write(0x4c, 0x27); /* Enable V1p8_VWYMXARF for
+ MRVL8688 */
+
++
++/*ouljhuot start*/
++ /*WLAN POWER high*/
++ temp |= 0x10;
++ intel_mrst_pmic_write(0xf4, temp);
++
++ /*WLAN RESET high*/
++ temp |= 0x8;
++ intel_mrst_pmic_write(0xf4, temp);
++
++ /*GPS POWER high*/
++ temp |= 0x2;
++ intel_mrst_pmic_write(0xf4, temp);
++/* msleep(16);*/
++/*ouljhuot end*/
++
+ return 0;
+ }
+
+@@ -153,6 +211,35 @@ static int intel_mrst_bringup_8688_sdio2
+ return 0;
+ }
+
++
++
++
++ /*ouljhuot start*/
++static int intel_mrst_sdio_gps_power_up(void)
++ {
++ unsigned int temp = 0;
++
++ /*GPS RESET low & POWER low*/
++ intel_mrst_pmic_read(0xf4, &temp);
++ temp &= ~0x6;
++ intel_mrst_pmic_write(0xf4, temp);
++ msleep(1);
++ /*GPS RESET high*/
++ temp |= 0x4;
++ intel_mrst_pmic_write(0xf4, temp);
++
++ intel_mrst_pmic_write(0x4a, 0x3f); /* Ensure GYMXIOCNT */
++ intel_mrst_pmic_write(0x4e, 0x3f); /* Ensure GYMX33CNT */
++
++ /*GPS POWER high*/
++ temp |= 0x2;
++ intel_mrst_pmic_write(0xf4, temp);
++ /* Wait to settle */
++ msleep(16);
++
++ return 0;
++ }
++
+ static int intel_mrst_bringup_EVP_sdio2_Option_spi(void)
+ {
+ unsigned int temp = 0;
+@@ -199,7 +286,10 @@ static int __init intel_mrst_module_init
+
+ printk(KERN_INFO "intel_mrst_module_init: bringing up power for "
+ "8688 WLAN on SDIO2 & IFX GPS over SPI...\n");
+- ret = intel_mrst_bringup_8688_sdio2();
++/*ouljhuot start*/
++ ret = intel_mrst_sdio_8688_power_up();
++/* ret = intel_mrst_sdio_gps_power_up();*/
++/*ouljhuot end*/
+
+ #endif /* CONFIG_8688_RC */
+
+Index: linux-2.6.33/drivers/hwmon/lis331dl.c
+===================================================================
+--- linux-2.6.33.orig/drivers/hwmon/lis331dl.c
++++ linux-2.6.33/drivers/hwmon/lis331dl.c
+@@ -45,6 +45,8 @@ MODULE_LICENSE("GPL v2");
+ #define ACCEL_NORMAL_MODE 0
+ #define ACCEL_MEMORY_REBOOT 1
+
++#define POS_READ_MAX_RETRY (5)
++
+ /* internal return values */
+
+ struct acclero_data {
+@@ -93,9 +95,24 @@ static ssize_t x_pos_show(struct device
+ {
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val;
++ int retry = 0;
+
++x_retry:
+ ret_val = i2c_smbus_read_byte_data(client, 0x29);
+- return sprintf(buf, "%d\n", ret_val);
++ if (ret_val == -ETIMEDOUT) {
++ dev_dbg(dev, "x pos read timed out, retry %d\n", retry);
++ retry++;
++ if (retry <= POS_READ_MAX_RETRY) {
++ msleep(10);
++ goto x_retry;
++ } else {
++ ret_val = 0;
++ dev_err(dev, "x pos read failed %d retries\n", retry);
++ }
++ }
++ /* ouljkorh, 09.11.2009, change start */
++ return sprintf(buf, "%d\n", (signed char)ret_val);
++ /* ouljkorh, 09.11.2009, change end */
+ }
+
+ static ssize_t y_pos_show(struct device *dev,
+@@ -103,9 +120,24 @@ static ssize_t y_pos_show(struct device
+ {
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val;
++ int retry = 0;
+
++y_retry:
+ ret_val = i2c_smbus_read_byte_data(client, 0x2B);
+- return sprintf(buf, "%d\n", ret_val);
++ if (ret_val == -ETIMEDOUT) {
++ dev_dbg(dev, "y pos read timed out, retry %d\n", retry);
++ retry++;
++ if (retry <= POS_READ_MAX_RETRY) {
++ msleep(10);
++ goto y_retry;
++ } else {
++ ret_val = 0;
++ dev_err(dev, "y pos read failed %d retries\n", retry);
++ }
++ }
++ /* ouljkorh, 09.11.2009, change start */
++ return sprintf(buf, "%d\n", (signed char)ret_val);
++ /* ouljkorh, 09.11.2009, change end */
+ }
+
+ static ssize_t z_pos_show(struct device *dev,
+@@ -113,9 +145,24 @@ static ssize_t z_pos_show(struct device
+ {
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val;
++ int retry = 0;
+
++z_retry:
+ ret_val = i2c_smbus_read_byte_data(client, 0x2D);
+- return sprintf(buf, "%d\n", ret_val);
++ if (ret_val == -ETIMEDOUT) {
++ dev_dbg(dev, "z pos read timed out, retry %d\n", retry);
++ retry++;
++ if (retry <= POS_READ_MAX_RETRY) {
++ msleep(10);
++ goto z_retry;
++ } else {
++ ret_val = 0;
++ dev_err(dev, "z pos read failed %d retries\n", retry);
++ }
++ }
++ /* ouljkorh, 09.11.2009, change start */
++ return sprintf(buf, "%d\n", (signed char)ret_val);
++ /* ouljkorh, 09.11.2009, change end */
+ }
+
+ static ssize_t xyz_pos_show(struct device *dev,
+@@ -123,11 +170,38 @@ static ssize_t xyz_pos_show(struct devic
+ {
+ int x, y, z;
+ struct i2c_client *client = to_i2c_client(dev);
++ int retry = 0;
+
++xyz_retry:
++ if (retry > POS_READ_MAX_RETRY) {
++ dev_err(dev, "xyz read retry failed\n");
++ x = y = z = 0;
++ return sprintf(buf, "(%d,%d,%d)\n", (signed char)x,
++ (signed char)y, (signed char)z);
++ }
++ retry++;
+ x = i2c_smbus_read_byte_data(client, 0x29);
++ if (x == -ETIMEDOUT) {
++ msleep(100);
++ goto xyz_retry;
++ }
++ msleep(100);
+ y = i2c_smbus_read_byte_data(client, 0x2B);
++ if (y == -ETIMEDOUT) {
++ msleep(100);
++ goto xyz_retry;
++ }
++ msleep(100);
+ z = i2c_smbus_read_byte_data(client, 0x2D);
+- return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
++ if (z == -ETIMEDOUT) {
++ msleep(100);
++ goto xyz_retry;
++ }
++
++ /* ouljkorh, 09.11.2009, change start */
++ return sprintf(buf, "(%d,%d,%d)\n", (signed char)x,
++ (signed char)y, (signed char)z);
++ /* ouljkorh, 09.11.2009, change end */
+ }
+
+ static ssize_t data_rate_store(struct device *dev,
+Index: linux-2.6.33/drivers/usb/gadget/u_serial.c
+===================================================================
+--- linux-2.6.33.orig/drivers/usb/gadget/u_serial.c
++++ linux-2.6.33/drivers/usb/gadget/u_serial.c
+@@ -783,11 +783,6 @@ static int gs_open(struct tty_struct *tt
+ port->open_count = 1;
+ port->openclose = false;
+
+- /* low_latency means ldiscs work in tasklet context, without
+- * needing a workqueue schedule ... easier to keep up.
+- */
+- tty->low_latency = 1;
+-
+ /* if connected, start the I/O stream */
+ if (port->port_usb) {
+ struct gserial *gser = port->port_usb;
+Index: linux-2.6.33/drivers/i2c/busses/i2c-mrst.c
+===================================================================
+--- linux-2.6.33.orig/drivers/i2c/busses/i2c-mrst.c
++++ linux-2.6.33/drivers/i2c/busses/i2c-mrst.c
+@@ -37,7 +37,7 @@
+
+ #include "i2c-mrst.h"
+
+-#define MAX_T_POLL_COUNT 4000 /* FIXME */
++#define MAX_T_POLL_COUNT 8000 /* FIXME */
+ #define DEF_BAR 0
+ #define VERSION "Version 0.5"
+
+Index: linux-2.6.33/arch/x86/kernel/mrst.c
+===================================================================
+--- linux-2.6.33.orig/arch/x86/kernel/mrst.c
++++ linux-2.6.33/arch/x86/kernel/mrst.c
+@@ -23,6 +23,9 @@
+ #include <linux/input.h>
+ #include <linux/platform_device.h>
+ #include <linux/irq.h>
++/*jhuot, added for MAX3107 data*/
++#include <linux/spi/mrst_spi.h>
++
+
+ #include <asm/string.h>
+ #include <asm/setup.h>
+@@ -267,6 +270,27 @@ void __init x86_mrst_early_setup(void)
+ #define MRST_SPI2_CS_START 4
+ static struct langwell_pmic_gpio_platform_data pmic_gpio_pdata;
+
++#ifdef CONFIG_SERIAL_MAX3107
++static struct mrst_spi_chip spi_slave0 = {
++ .poll_mode = 1,
++ .enable_dma = 0,
++ .type = SPI_FRF_SPI,
++};
++
++static struct spi_board_info mrst_spi_board_info[] __initdata = {
++ {
++ /* the modalias must be the same as spi device driver name */
++ .modalias = "max3107", /* spi_driver name driving device */
++ .max_speed_hz = 3125000,/* default value */
++ .bus_num = 0, /* SPI0 */
++ .chip_select = 0, /* Framework chip select. */
++ .platform_data = NULL, /* fill later */
++ .controller_data = &spi_slave0,
++ .irq = 0x13d,
++ },
++};
++#endif
++
+ static int __init sfi_parse_spib(struct sfi_table_header *table)
+ {
+ struct sfi_table_simple *sb;
+@@ -290,31 +314,48 @@ static int __init sfi_parse_spib(struct
+ pr_info("Moorestown SPI devices info:\n");
+
+ for (i = 0, j = 0; i < num; i++, pentry++) {
+- strncpy(info[j].modalias, pentry->name, 16);
+- info[j].irq = pentry->irq_info;
+- info[j].bus_num = pentry->host_num;
+- info[j].chip_select = pentry->cs;
+- info[j].max_speed_hz = 3125000; /* hard coded */
+- if (info[i].chip_select >= MRST_SPI2_CS_START) {
+- /* these SPI2 devices are not exposed to system as PCI
+- * devices, but they have separate RTE entry in IOAPIC
+- * so we have to enable them one by one here
+- */
+- ioapic = mp_find_ioapic(info[j].irq);
+- irq_attr.ioapic = ioapic;
+- irq_attr.ioapic_pin = info[j].irq;
+- irq_attr.trigger = 1;
+- irq_attr.polarity = 1;
+- io_apic_set_pci_routing(NULL, info[j].irq,
++#ifdef CONFIG_SERIAL_MAX3107
++ if (j != 1) { /*other devices info*/
++#endif
++ strncpy(info[j].modalias, pentry->name, 16);
++ info[j].irq = pentry->irq_info;
++ info[j].bus_num = pentry->host_num;
++ info[j].chip_select = pentry->cs;
++ info[j].max_speed_hz = 3125000; /* hard coded */
++ if (info[i].chip_select >= MRST_SPI2_CS_START) {
++ /* these SPI2 devices are not exposed to system as PCI
++ * devices, but they have separate RTE entry in IOAPIC
++ * so we have to enable them one by one here
++ */
++ ioapic = mp_find_ioapic(info[j].irq);
++ irq_attr.ioapic = ioapic;
++ irq_attr.ioapic_pin = info[j].irq;
++ irq_attr.trigger = 1;
++ irq_attr.polarity = 1;
++ io_apic_set_pci_routing(NULL, info[j].irq,
+ &irq_attr);
+- }
+- info[j].platform_data = pentry->dev_info;
++ }
+
+- if (!strcmp(pentry->name, "pmic_gpio")) {
+- memcpy(&pmic_gpio_pdata, pentry->dev_info, 8);
+- pmic_gpio_pdata.gpiointr = 0xffffeff8;
+- info[j].platform_data = &pmic_gpio_pdata;
++ info[j].platform_data = pentry->dev_info;
++
++ if (!strcmp(pentry->name, "pmic_gpio")) {
++ memcpy(&pmic_gpio_pdata, pentry->dev_info, 8);
++ pmic_gpio_pdata.gpiointr = 0xffffeff8;
++ info[j].platform_data = &pmic_gpio_pdata;
++ }
++#ifdef CONFIG_SERIAL_MAX3107
++ } else { /*MAX3107 info*/
++ info[j] = mrst_spi_board_info[0];
++ }
++
++#endif
++ /* jhuot edit start: change GPS chip select from 2 to 3 */
++ if (info[j].bus_num == 0 && info[j].chip_select == 2) {
++ info[j].chip_select = 3;
++ } else if (info[j].bus_num == 0 && info[j].chip_select == 3) {
++ info[j].chip_select = 2;
+ }
++ /* jhuot edit end */
+ pr_info("info[%d]: name = %16s, irq = 0x%04x, bus = %d, "
+ "cs = %d\n", j, info[j].modalias, info[j].irq,
+ info[j].bus_num, info[j].chip_select);
+Index: linux-2.6.33/drivers/serial/Kconfig
+===================================================================
+--- linux-2.6.33.orig/drivers/serial/Kconfig
++++ linux-2.6.33/drivers/serial/Kconfig
+@@ -540,6 +540,21 @@ config SERIAL_S5PC100
+ help
+ Serial port support for the Samsung S5PC100 SoCs
+
++config SERIAL_MAX3107
++ tristate "MAX3107 support"
++ depends on SPI
++ select SERIAL_CORE
++ help
++ MAX3107 chip support
++
++config MAX3107_LOW_POWER
++ boolean "Enable very low power consumption scheme for Max3107"
++ default n
++ depends on SERIAL_MAX3107
++ help
++ Adds hardware suspend for MAX3107 instead of sleep/auto-sleep,
++ but causes longer latency in wake-up (re-initialization of the chip).
++
+ config SERIAL_MAX3100
+ tristate "MAX3100 support"
+ depends on SPI
+Index: linux-2.6.33/drivers/serial/Makefile
+===================================================================
+--- linux-2.6.33.orig/drivers/serial/Makefile
++++ linux-2.6.33/drivers/serial/Makefile
+@@ -46,6 +46,7 @@ obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.
+ obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
+ obj-$(CONFIG_SERIAL_S5PC100) += s3c6400.o
+ obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
++obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+ obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
+ obj-$(CONFIG_SERIAL_MUX) += mux.o
+ obj-$(CONFIG_SERIAL_68328) += 68328serial.o
+Index: linux-2.6.33/drivers/serial/max3107.c
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/serial/max3107.c
+@@ -0,0 +1,1484 @@
++/*
++ * max3107.c - spi uart protocol driver for Maxim 3107
++ * Based on max3100.c
++ * by Christian Pellegrin <chripell@evolware.org>
++ * and max3110.c
++ * by Feng Tang <feng.tang@intel.com>
++ *
++ * Copyright (C) Aavamobile 2009
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/serial_core.h>
++#include <linux/serial.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/mrst_spi.h>
++#include <linux/freezer.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/serial_max3107.h>
++
++/* Debug trace definitions */
++#define DBG_LEVEL 0
++
++#if (DBG_LEVEL > 0)
++#define DBG_TRACE(format,args...) printk(KERN_ERR "%s: " format, \
++ __FUNCTION__ , ## args)
++#else
++#define DBG_TRACE(format,args...)
++#endif
++
++#if (DBG_LEVEL > 1)
++#define DBG_TRACE_SPI_DATA
++#endif
++
++struct max3107_port {
++ /* UART port structure */
++ struct uart_port port;
++
++ /* SPI device structure */
++ struct spi_device *spi;
++
++ /* GPIO chip stucture */
++ struct gpio_chip chip;
++
++ /* Workqueue that does all the magic */
++ struct workqueue_struct *workqueue;
++ struct work_struct work;
++
++ /* Lock for shared data */
++ spinlock_t data_lock;
++
++ /* Device configuration */
++ int ext_clk; /* 1 if external clock used */
++ int loopback; /* Current loopback mode state */
++ int baud; /* Current baud rate */
++
++ /* State flags */
++ int suspended; /* Indicates suspend mode */
++ int tx_fifo_empty; /* Flag for TX FIFO state */
++ int rx_enabled; /* Flag for receiver state */
++ int tx_enabled; /* Flag for transmitter state */
++
++ /* Shared data */
++ u16 irqen_reg; /* Current IRQ enable register value */
++ u16 mode1_reg; /* Current mode1 register value*/
++ int mode1_commit; /* Flag for setting new mode1 register value */
++ u16 lcr_reg; /* Current LCR register value */
++ int lcr_commit; /* Flag for setting new LCR register value */
++ u32 brg_cfg; /* Current Baud rate generator config */
++ int brg_commit; /* Flag for setting new baud rate generator
++ * config
++ */
++
++ int handle_irq; /* Indicates that IRQ should be handled */
++};
++
++/* Platform data structure */
++struct max3107_plat {
++ /* Loopback mode enable */
++ int loopback;
++ /* External clock enable */
++ int ext_clk;
++ /* HW suspend function */
++ void (*max3107_hw_suspend) (struct max3107_port *s, int suspend);
++ /* Polling mode enable */
++ int polled_mode;
++ /* Polling period if polling mode enabled */
++ int poll_time;
++};
++
++
++/* Perform SPI transfer for write/read of device register(s) */
++static int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
++{
++ struct spi_message spi_msg;
++ struct spi_transfer spi_xfer;
++
++ DBG_TRACE("enter\n");
++
++ /* Initialize SPI ,message */
++ spi_message_init(&spi_msg);
++
++ /* Initialize SPI transfer */
++ memset(&spi_xfer, 0, sizeof spi_xfer);
++ spi_xfer.len = len;
++ spi_xfer.tx_buf = tx;
++ spi_xfer.rx_buf = rx;
++ spi_xfer.speed_hz = MAX3107_SPI_SPEED;
++
++ /* Add SPI transfer to SPI message */
++ spi_message_add_tail(&spi_xfer, &spi_msg);
++
++#ifdef DBG_TRACE_SPI_DATA
++ {
++ int i;
++ printk("tx len %d:\n", spi_xfer.len);
++ for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) {
++ printk(" %x", ((u8*)spi_xfer.tx_buf)[i]);
++ }
++ printk("\n");
++ }
++#endif
++
++ /* Perform synchronous SPI transfer */
++ if (spi_sync(s->spi, &spi_msg)) {
++ dev_err(&s->spi->dev, "spi_sync failure\n");
++ return -EIO;
++ }
++
++#ifdef DBG_TRACE_SPI_DATA
++ if (spi_xfer.rx_buf) {
++ int i;
++ printk("rx len %d:\n", spi_xfer.len);
++ for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) {
++ printk(" %x", ((u8*)spi_xfer.rx_buf)[i]);
++ }
++ printk("\n");
++ }
++#endif
++ return 0;
++}
++
++/* Puts received data to circular buffer */
++static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
++ int len)
++{
++ struct uart_port *port = &s->port;
++ struct tty_struct *tty;
++
++ DBG_TRACE("enter\n");
++
++ if (!port->state) {
++ /* UART is not open */
++ dev_warn(&s->spi->dev, "UART is closed\n");
++ return;
++ }
++
++ tty = port->state->port.tty;
++ if (!tty) {
++ /* TTY is not open */
++ dev_warn(&s->spi->dev, "TTY is closed\n");
++ return;
++ }
++
++ /* Insert received data */
++ tty_insert_flip_string(tty, data, len);
++ /* Update RX counter */
++ port->icount.rx += len;
++}
++
++/* Handle data receiving */
++static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
++{
++ int i;
++ int j;
++ int len; /* SPI transfer buffer length */
++ u16 buf[MAX3107_RX_FIFO_SIZE+2]; /* SPI transfer buffer
++ * +2 for RX FIFO interrupt
++ * disabling and RX level query
++ */
++ u8 valid_str[MAX3107_RX_FIFO_SIZE];
++
++ DBG_TRACE("enter\n");
++
++ if (!s->rx_enabled) {
++ /* RX is disabled */
++ return;
++ }
++
++ if (rxlvl == 0) {
++ /* RX fifo is empty */
++ return;
++ } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
++ dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
++ /* Ensure sanity of RX level */
++ rxlvl = MAX3107_RX_FIFO_SIZE;
++ }
++
++ while (rxlvl) {
++ DBG_TRACE("rxlvl %d\n", rxlvl);
++ /* Clear buffer */
++ memset(buf, 0, sizeof(buf));
++ len = 0;
++ if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
++ /* First disable RX FIFO interrupt */
++ DBG_TRACE("Disabling RX INT\n");
++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
++ spin_lock(&s->data_lock);
++ s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
++ buf[0] |= s->irqen_reg;
++ spin_unlock(&s->data_lock);
++ len++;
++ }
++ /* Just increase the length by amount of words in FIFO since
++ * buffer was zeroed and SPI transfer of 0x0000 means reading
++ * from RX FIFO
++ */
++ len += rxlvl;
++ /* Append RX level query */
++ buf[len] = MAX3107_RXFIFOLVL_REG;
++ len++;
++
++ /* Perform the SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len*2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for RX handling failed\n");
++ return;
++ }
++
++ /* Skip RX FIFO interrupt disabling word if it was added */
++ j = ((len-1)-rxlvl);
++ /* Read received words */
++ for (i = 0; i < rxlvl; i++, j++) {
++ valid_str[i] = (u8)buf[j];
++ }
++ put_data_to_circ_buf(s, valid_str, rxlvl);
++ /* Get new RX level */
++ rxlvl = (buf[len-1] & MAX3107_SPI_RX_DATA_MASK);
++ }
++
++ if (s->rx_enabled) {
++ /* RX still enabled, re-enable RX FIFO interrupt */
++ DBG_TRACE("Enabling RX INT\n");
++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
++ spin_lock(&s->data_lock);
++ s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
++ buf[0] |= s->irqen_reg;
++ spin_unlock(&s->data_lock);
++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
++ dev_err(&s->spi->dev,
++ "RX FIFO interrupt enabling failed\n");
++ }
++ }
++
++ /* Push the received data to receivers */
++ tty_flip_buffer_push(s->port.state->port.tty);
++}
++
++
++/* Handle data sending */
++static void max3107_handletx(struct max3107_port *s)
++{
++ struct circ_buf *xmit = &s->port.state->xmit;
++ int i;
++ int len; /* SPI transfer buffer length */
++ u16 buf[MAX3107_TX_FIFO_SIZE+3]; /* SPI transfer buffer
++ * +3 for TX FIFO empty
++ * interrupt disabling and
++ * enabling and TX enabling
++ */
++
++ DBG_TRACE("enter\n");
++
++ if (!s->tx_fifo_empty) {
++ /* Don't send more data before previous data is sent */
++ return;
++ }
++
++ if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port)) {
++ /* No data to send or TX is stopped */
++ return;
++ }
++
++ /* Get length of data pending in circular buffer */
++ len = uart_circ_chars_pending(xmit);
++ if (len) {
++ /* Limit to size of TX FIFO */
++ if (len > MAX3107_TX_FIFO_SIZE)
++ len = MAX3107_TX_FIFO_SIZE;
++
++ DBG_TRACE("txlen %d\n", len);
++
++ /* Update TX counter */
++ s->port.icount.tx += len;
++
++ /* TX FIFO will no longer be empty */
++ s->tx_fifo_empty = 0;
++
++ i = 0;
++ if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
++ /* First disable TX empty interrupt */
++ DBG_TRACE("Disabling TE INT\n");
++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
++ spin_lock(&s->data_lock);
++ s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
++ buf[i] |= s->irqen_reg;
++ spin_unlock(&s->data_lock);
++ i++;
++ len++;
++ }
++
++ /* Add data to send */
++ for ( ; i < len ; i++ ) {
++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
++ buf[i] |= ((u16)xmit->buf[xmit->tail] &
++ MAX3107_SPI_TX_DATA_MASK);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ }
++
++ if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
++ /* Enable TX empty interrupt */
++ DBG_TRACE("Enabling TE INT\n");
++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
++ spin_lock(&s->data_lock);
++ s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
++ buf[i] |= s->irqen_reg;
++ spin_unlock(&s->data_lock);
++ i++;
++ len++;
++ }
++ if (!s->tx_enabled) {
++ /* Enable TX */
++ DBG_TRACE("Enable TX\n");
++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
++ spin_lock(&s->data_lock);
++ s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
++ buf[i] |= s->mode1_reg;
++ spin_unlock(&s->data_lock);
++ s->tx_enabled = 1;
++ i++;
++ len++;
++ }
++
++ /* Perform the SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for TX handling failed\n");
++ return;
++ }
++ }
++
++ /* Indicate wake up if circular buffer is getting low on data */
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&s->port);
++
++}
++
++/* Handle interrupts
++ * Also reads and returns current RX FIFO level
++ */
++static u16 handle_interrupt(struct max3107_port *s)
++{
++ u16 buf[4]; /* Buffer for SPI transfers */
++ u8 irq_status;
++ u16 rx_level;
++
++ DBG_TRACE("enter\n");
++
++ /* Read IRQ status register */
++ buf[0] = MAX3107_IRQSTS_REG;
++ /* Read status IRQ status register */
++ buf[1] = MAX3107_STS_IRQSTS_REG;
++ /* Read LSR IRQ status register */
++ buf[2] = MAX3107_LSR_IRQSTS_REG;
++ /* Query RX level */
++ buf[3] = MAX3107_RXFIFOLVL_REG;
++
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for interrupt handling failed\n");
++ return 0;
++ }
++
++ irq_status = (u8)buf[0];
++ DBG_TRACE("IRQSTS %x\n", irq_status);
++ rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
++
++ if (irq_status & MAX3107_IRQ_LSR_BIT) {
++ /* LSR interrupt */
++ if ( buf[2] & MAX3107_LSR_RXTO_BIT ) {
++ /* RX timeout interrupt,
++ * handled by normal RX handling
++ */
++ DBG_TRACE("RX TO INT\n");
++ }
++ }
++
++ if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
++ /* Tx empty interrupt,
++ * disable TX and set tx_fifo_empty flag
++ */
++ DBG_TRACE("TE INT, disabling TX\n");
++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
++ spin_lock(&s->data_lock);
++ s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
++ buf[0] |= s->mode1_reg;
++ spin_unlock(&s->data_lock);
++ if (max3107_rw(s, (u8 *)buf, NULL, 2))
++ dev_err(&s->spi->dev,
++ "SPI transfer for TX disabling failed\n");
++ s->tx_enabled = 0;
++ s->tx_fifo_empty = 1;
++ }
++
++ if (irq_status & MAX3107_IRQ_RXFIFO_BIT) {
++ /* RX FIFO interrupt,
++ * handled by normal RX handling
++ */
++ DBG_TRACE("RFIFO INT\n");
++ }
++
++ /* Return RX level */
++ return rx_level;
++}
++
++/* Trigger work thread*/
++static void max3107_dowork(struct max3107_port *s)
++{
++ if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
++ queue_work(s->workqueue, &s->work);
++}
++
++/* Work thread */
++static void max3107_work(struct work_struct *w)
++{
++ struct max3107_port *s = container_of(w, struct max3107_port, work);
++ u16 rxlvl = 0;
++ int len; /* SPI transfer buffer length */
++ u16 buf[5]; /* Buffer for SPI transfers */
++
++ DBG_TRACE("enter\n");
++
++ /* Start by reading current RX FIFO level */
++ buf[0] = MAX3107_RXFIFOLVL_REG;
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for RX level query failed\n");
++ rxlvl = 0;
++ } else {
++ rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
++ }
++
++ do {
++ DBG_TRACE("rxlvl %d\n", rxlvl);
++
++ /* Handle RX */
++ max3107_handlerx(s, rxlvl);
++ rxlvl = 0;
++
++ if (s->handle_irq) {
++ /* Handle pending interrupts
++ * We also get new RX FIFO level since new data may
++ * have been received while pushing received data to
++ * receivers
++ */
++ s->handle_irq = 0;
++ rxlvl = handle_interrupt(s);
++ }
++
++ /* Handle TX */
++ max3107_handletx(s);
++
++ /* Handle configuration changes */
++ len = 0;
++ spin_lock(&s->data_lock);
++ if (s->mode1_commit) {
++ DBG_TRACE("mode1_commit\n");
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
++ buf[len++] |= s->mode1_reg;
++ s->mode1_commit = 0;
++ }
++ if (s->lcr_commit) {
++ DBG_TRACE("lcr_commit\n");
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
++ buf[len++] |= s->lcr_reg;
++ s->lcr_commit = 0;
++ }
++ if (s->brg_commit) {
++ DBG_TRACE("brg_commit\n");
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
++ buf[len++] |= ((s->brg_cfg >> 16) &
++ MAX3107_SPI_TX_DATA_MASK);
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
++ buf[len++] |= ((s->brg_cfg >> 8) &
++ MAX3107_SPI_TX_DATA_MASK);
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
++ buf[len++] |= ((s->brg_cfg) & 0xff);
++ s->brg_commit = 0;
++ }
++ spin_unlock(&s->data_lock);
++
++ if (len > 0) {
++ if (max3107_rw(s, (u8 *)buf, NULL, len*2))
++ dev_err(&s->spi->dev,
++ "SPI transfer for config failed\n");
++ }
++
++ /* Reloop if interrupt handling indicated data in RX FIFO */
++ } while (rxlvl);
++
++}
++
++/* Set sleep mode */
++static void max3107_set_sleep(struct max3107_port *s, int mode)
++{
++ u16 buf[1]; /* Buffer for SPI transfer */
++
++ DBG_TRACE("enter, mode %d\n", mode);
++
++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
++ spin_lock(&s->data_lock);
++ switch (mode) {
++ case MAX3107_DISABLE_FORCED_SLEEP:
++ s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
++ break;
++ case MAX3107_ENABLE_FORCED_SLEEP:
++ s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
++ break;
++ case MAX3107_DISABLE_AUTOSLEEP:
++ s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
++ break;
++ case MAX3107_ENABLE_AUTOSLEEP:
++ s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
++ break;
++ default:
++ spin_unlock(&s->data_lock);
++ dev_warn(&s->spi->dev, "invalid sleep mode\n");
++ return;
++ }
++ buf[0] |= s->mode1_reg;
++ spin_unlock(&s->data_lock);
++
++ if (max3107_rw(s, (u8 *)buf, NULL, 2))
++ dev_err(&s->spi->dev, "SPI transfer for sleep mode failed\n");
++
++ if (mode == MAX3107_DISABLE_AUTOSLEEP ||
++ mode == MAX3107_DISABLE_FORCED_SLEEP ) {
++ msleep(MAX3107_WAKEUP_DELAY);
++ }
++}
++
++/* Perform full register initialization */
++static void max3107_register_init(struct max3107_port *s)
++{
++ int len = 0; /* SPI transfer buffer length */
++ u16 buf[11]; /* Buffer for SPI transfers */
++
++ DBG_TRACE("enter\n");
++
++ /* 1. Configure baud rate, 9600 as default */
++ s->baud = 9600;
++ if (s->ext_clk)
++ s->brg_cfg = MAX3107_BRG_B9600;
++ else
++ s->brg_cfg = MAX3107_BRG_IB9600;
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
++ buf[len++] |= ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
++ buf[len++] |= ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
++ buf[len++] |= ((s->brg_cfg) & 0xff);
++
++ /* 2. Configure LCR register, 8N1 mode by default */
++ s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
++ buf[len++] |= s->lcr_reg;
++
++ /* 3. Configure MODE 1 register */
++ s->mode1_reg = 0;
++ /* Enable IRQ pin */
++ s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
++ /* Disable TX */
++ s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
++ s->tx_enabled = 0;
++ /* RX is enabled */
++ s->rx_enabled = 1;
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
++ buf[len++] |= s->mode1_reg;
++
++ /* 4. Configure MODE 2 register */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
++ if (s->loopback) {
++ /* Enable loopback */
++ buf[len] |= MAX3107_MODE2_LOOPBACK_BIT;
++ }
++ /* Reset FIFOs */
++ buf[len++] |= MAX3107_MODE2_FIFORST_BIT;
++ s->tx_fifo_empty = 1;
++
++ /* 5. Configure FIFO trigger level register */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
++ /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
++ buf[len++] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
++
++ /* 6. Configure flow control levels */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
++ /* Flow control halt level 96, resume level 48 */
++ buf[len++] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
++
++ /* 7. Configure flow control */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
++ /* Enable auto CTS and auto RTS flow control */
++ buf[len++] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT |
++ MAX3107_FLOWCTRL_AUTORTS_BIT);
++
++ /* 8. Configure RX timeout register */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
++ /* Timeout after 48 character intervals */
++ buf[len++] |= 0x0030;
++
++ /* 9. Configure LSR interrupt enable register */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
++ /* Enable RX timeout interrupt */
++ buf[len++] |= MAX3107_LSR_RXTO_BIT;
++
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, len*2))
++ dev_err(&s->spi->dev, "SPI transfer for init failed\n");
++
++ len = 0;
++ /* 10. Clear IRQ status register by reading it */
++ buf[len++] = MAX3107_IRQSTS_REG;
++
++ /* 11. Configure interrupt enable register */
++ /* Enable LSR interrupt */
++ s->irqen_reg = MAX3107_IRQ_LSR_BIT;
++ /* Enable RX FIFO interrupt */
++ s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
++ buf[len++] |= s->irqen_reg;
++
++ /* 12. Clear FIFO reset that was set in step 6 */
++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
++ if (s->loopback) {
++ /* Keep loopback enabled */
++ buf[len] |= MAX3107_MODE2_LOOPBACK_BIT;
++ }
++ buf[len++] |= 0x0000;
++
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len*2))
++ dev_err(&s->spi->dev, "SPI transfer for init failed\n");
++
++}
++
++/* IRQ handler */
++static irqreturn_t max3107_irq(int irqno, void *dev_id)
++{
++ struct max3107_port *s = dev_id;
++
++ if (irqno != s->spi->irq) {
++ /* Unexpected IRQ */
++ return IRQ_NONE;
++ }
++
++ /* Indicate irq */
++ s->handle_irq = 1;
++
++ /* Trigger work thread */
++ max3107_dowork(s);
++
++ return IRQ_HANDLED;
++}
++
++/* HW suspension function
++ *
++ * Currently autosleep is used to decrease current consumption, alternative
++ * approach would be to set the chip to reset mode if UART is not being
++ * used but that would mess the GPIOs
++ *
++ */
++static void max3107_hw_susp(struct max3107_port *s, int suspend)
++{
++ DBG_TRACE("enter, suspend %d\n", suspend);
++
++ if (suspend) {
++ /* Suspend requested,
++ * enable autosleep to decrease current consumption
++ */
++ s->suspended = 1;
++ max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
++ } else {
++ /* Resume requested,
++ * disable autosleep
++ */
++ s->suspended = 0;
++ max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
++ }
++}
++
++/* Modem status IRQ enabling */
++static void max3107_enable_ms(struct uart_port *port)
++{
++ /* Modem status not supported */
++}
++
++/* Data send function */
++static void max3107_start_tx(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ DBG_TRACE("enter\n");
++
++ /* Trigger work thread for sending data */
++ max3107_dowork(s);
++}
++
++/* Function for checking that there is no pending transfers */
++static unsigned int max3107_tx_empty(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ DBG_TRACE("returning %d\n",
++ (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
++ return (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit));
++}
++
++/* Function for stopping RX */
++static void max3107_stop_rx(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ DBG_TRACE("enter\n");
++
++ /* Set RX disabled in MODE 1 register */
++ spin_lock(&s->data_lock);
++ s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
++ s->mode1_commit = 1;
++ spin_unlock(&s->data_lock);
++ /* Set RX disabled */
++ s->rx_enabled = 0;
++ /* Trigger work thread for doing the actual configuration change */
++ max3107_dowork(s);
++}
++
++/* Function for returning control pin states */
++static unsigned int max3107_get_mctrl(struct uart_port *port)
++{
++ /* DCD and DSR are not wired and CTS/RTS is handled automatically
++ * so just indicate DSR and CAR asserted
++ */
++ return (TIOCM_DSR | TIOCM_CAR);
++}
++
++/* Function for setting control pin states */
++static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
++ * so do nothing
++ */
++}
++
++/* Function for configuring UART parameters */
++static void max3107_set_termios(struct uart_port *port,
++ struct ktermios *termios,
++ struct ktermios *old)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++ struct tty_struct *tty;
++ int baud;
++ u16 new_lcr = 0;
++ u32 new_brg = 0;
++
++ DBG_TRACE("enter\n");
++
++ if (!port->state) {
++ /* UART is not open */
++ dev_warn(&s->spi->dev, "UART is closed\n");
++ return;
++ }
++
++ tty = port->state->port.tty;
++ if (!tty) {
++ /* TTY is not open */
++ dev_warn(&s->spi->dev, "TTY is closed\n");
++ return;
++ }
++
++ if (old) {
++ if ((termios->c_cflag == old->c_cflag) &&
++ (RELEVANT_IFLAG(termios->c_iflag) ==
++ RELEVANT_IFLAG(old->c_iflag))) {
++ /* Nothing relevant is changing */
++ return;
++ }
++ }
++
++ /* Get new LCR register values */
++ /* Word size */
++ if ((termios->c_cflag & CSIZE) == CS7)
++ new_lcr |= MAX3107_LCR_WORD_LEN_7;
++ else
++ new_lcr |= MAX3107_LCR_WORD_LEN_8;
++
++ /* Parity */
++ if (termios->c_cflag & PARENB) {
++ new_lcr |= MAX3107_LCR_PARITY_BIT;
++ if (!(termios->c_cflag & PARODD))
++ new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
++ }
++
++ /* Stop bits */
++ if (termios->c_cflag & CSTOPB) {
++ /* 2 stop bits */
++ new_lcr |= MAX3107_LCR_STOPLEN_BIT;
++ }
++
++ /* Mask termios capabilities we don't support */
++ termios->c_cflag &= ~CMSPAR;
++
++ /* Set status ignore mask */
++ s->port.ignore_status_mask = 0;
++ if (termios->c_iflag & IGNPAR)
++ s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
++
++ /* Set low latency to immediately handle pushed data */
++ s->port.state->port.tty->low_latency = 1;
++
++ /* Get new baud rate generator configuration */
++ baud = tty_get_baud_rate(tty);
++ switch (baud) {
++ case 300:
++ new_brg = s->ext_clk ? MAX3107_BRG_B300 : MAX3107_BRG_IB300;
++ break;
++ case 600:
++ new_brg = s->ext_clk ? MAX3107_BRG_B600 : MAX3107_BRG_IB600;
++ break;
++ case 1200:
++ new_brg = s->ext_clk ? MAX3107_BRG_B1200 : MAX3107_BRG_IB1200;
++ break;
++ case 2400:
++ new_brg = s->ext_clk ? MAX3107_BRG_B2400 : MAX3107_BRG_IB2400;
++ break;
++ case 4800:
++ new_brg = s->ext_clk ? MAX3107_BRG_B4800 : MAX3107_BRG_IB4800;
++ break;
++ case 9600:
++ new_brg = s->ext_clk ? MAX3107_BRG_B9600 : MAX3107_BRG_IB9600;
++ break;
++ case 19200:
++ new_brg = s->ext_clk ? MAX3107_BRG_B19200 : MAX3107_BRG_IB19200;
++ break;
++ case 38400:
++ new_brg = s->ext_clk ? MAX3107_BRG_B38400 : MAX3107_BRG_IB38400;
++ break;
++ case 57600:
++ new_brg = s->ext_clk ? MAX3107_BRG_B57600 : MAX3107_BRG_IB57600;
++ break;
++ case 115200:
++ new_brg = s->ext_clk ? MAX3107_BRG_B115200 : MAX3107_BRG_IB115200;
++ break;
++ case 230400:
++ new_brg = s->ext_clk ? MAX3107_BRG_B230400 : MAX3107_BRG_IB230400;
++ break;
++ case 460800:
++ new_brg = s->ext_clk ? MAX3107_BRG_B460800 : MAX3107_BRG_IB460800;
++ break;
++ case 921600:
++ new_brg = s->ext_clk ? MAX3107_BRG_B921600 : MAX3107_BRG_IB921600;
++ break;
++ default:
++ /* Use previous */
++ baud = s->baud;
++ new_brg = s->brg_cfg;
++ tty_termios_encode_baud_rate(termios, baud, baud);
++ }
++ s->baud = baud;
++
++ /* Update timeout according to new baud rate */
++ uart_update_timeout(port, termios->c_cflag, baud);
++
++ spin_lock(&s->data_lock);
++ if (s->lcr_reg != new_lcr) {
++ s->lcr_reg = new_lcr;
++ s->lcr_commit = 1;
++ }
++ if (s->brg_cfg != new_brg) {
++ s->brg_cfg = new_brg;
++ s->brg_commit = 1;
++ }
++ spin_unlock(&s->data_lock);
++
++ /* Trigger work thread for doing the actual configuration change */
++ max3107_dowork(s);
++}
++
++/* Port shutdown function */
++static void max3107_shutdown(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ DBG_TRACE("enter\n");
++
++ if (s->suspended) {
++ /* Resume HW */
++ max3107_hw_susp(s, 0);
++ }
++
++ /* Free the interrupt */
++ free_irq(s->spi->irq, s);
++
++ if (s->workqueue) {
++ /* Flush and destroy work queue */
++ flush_workqueue(s->workqueue);
++ destroy_workqueue(s->workqueue);
++ s->workqueue = NULL;
++ }
++
++ /* Suspend HW */
++ max3107_hw_susp(s, 1);
++}
++
++/* Port startup function */
++static int max3107_startup(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ DBG_TRACE("enter\n");
++
++ /* Initialize work queue */
++ s->workqueue = create_freezeable_workqueue("max3107");
++ if (!s->workqueue) {
++ dev_err(&s->spi->dev, "Workqueue creation failed\n");
++ return -EBUSY;
++ }
++ INIT_WORK(&s->work, max3107_work);
++
++ /* Setup IRQ */
++ if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
++ "max3107", s)) {
++ dev_err(&s->spi->dev, "IRQ reguest failed\n");
++ destroy_workqueue(s->workqueue);
++ s->workqueue = NULL;
++ return -EBUSY;
++ }
++
++ /* Resume HW */
++ max3107_hw_susp(s, 0);
++
++ /* Init registers */
++ max3107_register_init(s);
++
++ return 0;
++}
++
++/* Port type function */
++static const char *max3107_type(struct uart_port *port)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++ return s->spi->modalias;
++}
++
++/* Port release function */
++static void max3107_release_port(struct uart_port *port)
++{
++ /* Do nothing */
++}
++
++/* Port request function */
++static int max3107_request_port(struct uart_port *port)
++{
++ /* Do nothing */
++ return 0;
++}
++
++/* Port config function */
++static void max3107_config_port(struct uart_port *port, int flags)
++{
++ struct max3107_port *s = container_of(port, struct max3107_port, port);
++
++ /* Use PORT_MAX3100 since we are at least int the same serie */
++ s->port.type = PORT_MAX3100;
++}
++
++/* Port verify function */
++static int max3107_verify_port(struct uart_port *port,
++ struct serial_struct *ser)
++{
++ if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100)
++ return 0;
++
++ return -EINVAL;
++}
++
++/* Port stop TX function */
++static void max3107_stop_tx(struct uart_port *port)
++{
++ /* Do nothing */
++}
++
++/* Port break control function */
++static void max3107_break_ctl(struct uart_port *port, int break_state)
++{
++ /* We don't support break control, do nothing */
++}
++
++/* GPIO direction query function */
++static enum gpio_direction max3107_gpio_get_direction(struct gpio_chip *chip,
++ unsigned offset)
++{
++ struct max3107_port *s = container_of(chip, struct max3107_port, chip);
++ u16 buf[1]; /* Buffer for SPI transfer */
++
++ DBG_TRACE("enter\n");
++
++ if (offset >= MAX3107_GPIO_COUNT) {
++ dev_err(&s->spi->dev, "Invalid GPIO\n");
++ return -EINVAL;
++ }
++
++ /* Read current GPIO configuration register */
++ buf[0] = MAX3107_GPIOCFG_REG;
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO config read failed\n");
++ return -EIO;
++ }
++ buf[0] &= MAX3107_SPI_RX_DATA_MASK;
++
++ /* Check the direction bit */
++ if (buf[0] & (0x0001 << offset))
++ return DIRECTION_OUT;
++ return DIRECTION_IN;
++}
++
++/* GPIO direction to input function */
++static int max3107_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
++{
++ struct max3107_port *s = container_of(chip, struct max3107_port, chip);
++ u16 buf[1]; /* Buffer for SPI transfer */
++
++ DBG_TRACE("enter\n");
++
++ if (offset >= MAX3107_GPIO_COUNT) {
++ dev_err(&s->spi->dev, "Invalid GPIO\n");
++ return -EINVAL;
++ }
++
++ /* Read current GPIO configuration register */
++ buf[0] = MAX3107_GPIOCFG_REG;
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO config read failed\n");
++ return -EIO;
++ }
++ buf[0] &= MAX3107_SPI_RX_DATA_MASK;
++
++ /* Set GPIO to input */
++ buf[0] &= ~(0x0001 << offset);
++
++ /* Write new GPIO configuration register value */
++ buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO config write failed\n");
++ return -EIO;
++ }
++ return 0;
++}
++
++/* GPIO direction to output function */
++static int max3107_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
++ int value)
++{
++ struct max3107_port *s = container_of(chip, struct max3107_port, chip);
++ u16 buf[2]; /* Buffer for SPI transfers */
++
++ DBG_TRACE("enter\n");
++
++ if (offset >= MAX3107_GPIO_COUNT) {
++ dev_err(&s->spi->dev, "Invalid GPIO\n");
++ return -EINVAL;
++ }
++
++ /* Read current GPIO configuration and data registers */
++ buf[0] = MAX3107_GPIOCFG_REG;
++ buf[1] = MAX3107_GPIODATA_REG;
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO config and data read failed\n");
++ return -EIO;
++ }
++ buf[0] &= MAX3107_SPI_RX_DATA_MASK;
++ buf[1] &= MAX3107_SPI_RX_DATA_MASK;
++
++ /* Set GPIO to output */
++ buf[0] |= (0x0001 << offset);
++ /* Set value */
++ if (value)
++ buf[1] |= (0x0001 << offset);
++ else
++ buf[1] &= ~(0x0001 << offset);
++
++ /* Write new GPIO configuration and data register values */
++ buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIOCFG_REG);
++ buf[1] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO config and data write failed\n");
++ return -EIO;
++ }
++ return 0;
++}
++
++/* GPIO value query function */
++static int max3107_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct max3107_port *s = container_of(chip, struct max3107_port, chip);
++ u16 buf[1]; /* Buffer for SPI transfer */
++
++ DBG_TRACE("enter\n");
++
++ if (offset >= MAX3107_GPIO_COUNT) {
++ dev_err(&s->spi->dev, "Invalid GPIO\n");
++ return -EINVAL;
++ }
++
++ /* Read current GPIO data register */
++ buf[0] = MAX3107_GPIODATA_REG;
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO data read failed\n");
++ return -EIO;
++ }
++ buf[0] &= MAX3107_SPI_RX_DATA_MASK;
++
++ /* Return value */
++ return buf[0] & (0x0001 << offset);
++}
++
++/* GPIO value set function */
++static void max3107_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++ struct max3107_port *s = container_of(chip, struct max3107_port, chip);
++ u16 buf[2]; /* Buffer for SPI transfers */
++
++ DBG_TRACE("enter\n");
++
++ if (offset >= MAX3107_GPIO_COUNT) {
++ dev_err(&s->spi->dev, "Invalid GPIO\n");
++ return;
++ }
++
++ /* Read current GPIO configuration registers*/
++ buf[0] = MAX3107_GPIODATA_REG;
++ buf[1] = MAX3107_GPIOCFG_REG;
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 4)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO data and config read failed\n");
++ return;
++ }
++ buf[0] &= MAX3107_SPI_RX_DATA_MASK;
++ buf[1] &= MAX3107_SPI_RX_DATA_MASK;
++
++ if (!(buf[1] & (0x0001 << offset))) {
++ /* Configured as input, can't set value */
++ dev_warn(&s->spi->dev,
++ "Trying to set value for input GPIO\n");
++ return;
++ }
++
++ /* Set value */
++ if (value)
++ buf[0] |= (0x0001 << offset);
++ else
++ buf[0] &= ~(0x0001 << offset);
++
++ /* Write new GPIO data register value */
++ buf[0] |= (MAX3107_WRITE_BIT | MAX3107_GPIODATA_REG);
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) {
++ dev_err(&s->spi->dev,
++ "SPI transfer for GPIO data write failed\n");
++ }
++}
++
++/* Platform data */
++static struct max3107_plat max3107_plat_data = {
++ .loopback = 0,
++ .ext_clk = 1,
++#ifdef CONFIG_MAX3107_LOW_POWER
++ .max3107_hw_suspend = &max3107_hw_susp,
++#endif /* CONFIG_MAX3107_LOW_POWER */
++ .polled_mode = 0,
++ .poll_time = 0,
++};
++
++/* Port functions */
++static struct uart_ops max3107_ops = {
++ .tx_empty = max3107_tx_empty,
++ .set_mctrl = max3107_set_mctrl,
++ .get_mctrl = max3107_get_mctrl,
++ .stop_tx = max3107_stop_tx,
++ .start_tx = max3107_start_tx,
++ .stop_rx = max3107_stop_rx,
++ .enable_ms = max3107_enable_ms,
++ .break_ctl = max3107_break_ctl,
++ .startup = max3107_startup,
++ .shutdown = max3107_shutdown,
++ .set_termios = max3107_set_termios,
++ .type = max3107_type,
++ .release_port = max3107_release_port,
++ .request_port = max3107_request_port,
++ .config_port = max3107_config_port,
++ .verify_port = max3107_verify_port,
++};
++
++/* UART driver data */
++static struct uart_driver max3107_uart_driver = {
++ .owner = THIS_MODULE,
++ .driver_name = "ttyMAX",
++ .dev_name = "ttyMAX",
++ .major = MAX3107_MAJOR,
++ .minor = MAX3107_MINOR,
++ .nr = 1,
++};
++
++/* GPIO chip data */
++static struct gpio_chip max3107_gpio_chip = {
++ .owner = THIS_MODULE,
++ .get_direction = max3107_gpio_get_direction,
++ .direction_input = max3107_gpio_direction_in,
++ .direction_output = max3107_gpio_direction_out,
++ .get = max3107_gpio_get,
++ .set = max3107_gpio_set,
++ .can_sleep = 1,
++ .base = MAX3107_GPIO_BASE,
++ .ngpio = MAX3107_GPIO_COUNT,
++};
++
++/* Device probe function */
++static int __devinit max3107_probe(struct spi_device *spi)
++{
++ struct max3107_port *s;
++ struct max3107_plat *pdata = &max3107_plat_data;
++ u16 buf[2]; /* Buffer for SPI transfers */
++ int retval;
++
++ DBG_TRACE("enter\n");
++
++ /* Reset the chip */
++ if (gpio_request(MAX3107_RESET_GPIO, "max3107")) {
++ printk(KERN_ERR "Requesting RESET GPIO failed\n");
++ return -EIO;
++ }
++ if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) {
++ printk(KERN_ERR "Setting RESET GPIO to 0 failed\n");
++ gpio_free(MAX3107_RESET_GPIO);
++ return -EIO;
++ }
++ msleep(MAX3107_RESET_DELAY);
++ if (gpio_direction_output(MAX3107_RESET_GPIO, 1)) {
++ printk(KERN_ERR "Setting RESET GPIO to 1 failed\n");
++ gpio_free(MAX3107_RESET_GPIO);
++ return -EIO;
++ }
++ gpio_free(MAX3107_RESET_GPIO);
++ msleep(MAX3107_WAKEUP_DELAY);
++
++ /* Allocate port structure */
++ s = kzalloc(sizeof(*s), GFP_KERNEL);
++ if (!s) {
++ printk(KERN_ERR "Allocating port structure failed\n");
++ return -ENOMEM;
++ }
++
++ /* Initialize shared data lock */
++ spin_lock_init(&s->data_lock);
++
++ /* SPI intializations */
++ dev_set_drvdata(&spi->dev, s);
++ spi->mode = SPI_MODE_0;
++ spi->dev.platform_data = pdata;
++ spi->bits_per_word = 16;
++ s->ext_clk = pdata->ext_clk;
++ s->loopback = pdata->loopback;
++ spi_setup(spi);
++ s->spi = spi;
++
++ /* Check REV ID to ensure we are talking to what we expect */
++ buf[0] = MAX3107_REVID_REG;
++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
++ dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
++ return -EIO;
++ }
++ if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
++ (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
++ dev_err(&s->spi->dev, "REVID %x does not match\n",
++ (buf[0] & MAX3107_SPI_RX_DATA_MASK) );
++ return -ENODEV;
++ }
++
++ /* Disable all interrupts */
++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
++ buf[0] |= 0x0000;
++
++ /* Configure clock source */
++ buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
++ if (s->ext_clk) {
++ /* External clock */
++ buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
++ }
++ /* PLL bypass */
++ buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
++
++ /* Perform SPI transfer */
++ if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
++ dev_err(&s->spi->dev, "SPI transfer for init failed\n");
++ return -EIO;
++ }
++
++
++ /* Register UART driver */
++ retval = uart_register_driver(&max3107_uart_driver);
++ if (retval) {
++ dev_err(&s->spi->dev, "Registering UART driver failed\n");
++ return retval;
++ }
++
++ /* Initialize UART port data */
++ s->port.fifosize = 128;
++ s->port.ops = &max3107_ops;
++ s->port.line = 0;
++ s->port.dev = &spi->dev;
++ s->port.uartclk = 9600;
++ s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
++ s->port.irq = s->spi->irq;
++ /* Use PORT_MAX3100 since we are at least int the same serie */
++ s->port.type = PORT_MAX3100;
++
++ /* Add UART port */
++ retval = uart_add_one_port(&max3107_uart_driver, &s->port);
++ if (retval < 0) {
++ dev_err(&s->spi->dev, "Adding UART port failed\n");
++ return retval;
++ }
++
++ /* Initialize GPIO chip data */
++ s->chip = max3107_gpio_chip;
++ s->chip.label = spi->modalias;
++ s->chip.dev = &spi->dev;
++
++ /* Add GPIO chip */
++ retval = gpiochip_add(&s->chip);
++ if (retval) {
++ dev_err(&s->spi->dev, "Adding GPIO chip failed\n");
++ return retval;
++ }
++
++ /* Go to suspend mode */
++ max3107_hw_susp(s, 1);
++
++ return 0;
++}
++
++/* Driver remove function */
++static int __devexit max3107_remove(struct spi_device *spi)
++{
++ struct max3107_port *s = dev_get_drvdata(&spi->dev);
++
++ DBG_TRACE("enter\n");
++
++ /* Remove GPIO chip */
++ if (gpiochip_remove(&s->chip))
++ dev_warn(&s->spi->dev, "Removing GPIO chip failed\n");
++
++ /* Remove port */
++ if (uart_remove_one_port(&max3107_uart_driver, &s->port))
++ dev_warn(&s->spi->dev, "Removing UART port failed\n");
++
++ /* Unregister UART driver */
++ uart_unregister_driver(&max3107_uart_driver);
++
++ /* Free port structure */
++ kfree(s);
++
++ return 0;
++}
++
++/* Driver suspend function */
++static int max3107_suspend(struct spi_device *spi, pm_message_t state)
++{
++#ifdef CONFIG_PM
++ struct max3107_port *s = dev_get_drvdata(&spi->dev);
++
++ DBG_TRACE("enter\n");
++
++ /* Suspend UART port */
++ uart_suspend_port(&max3107_uart_driver, &s->port);
++
++ /* Go to suspend mode */
++ max3107_hw_susp(s, 1);
++#endif /* CONFIG_PM */
++ return 0;
++}
++
++/* Driver resume function */
++static int max3107_resume(struct spi_device *spi)
++{
++#ifdef CONFIG_PM
++ struct max3107_port *s = dev_get_drvdata(&spi->dev);
++
++ DBG_TRACE("enter\n");
++
++ /* Resume from suspend */
++ max3107_hw_susp(s, 0);
++
++ /* Resume UART port */
++ uart_resume_port(&max3107_uart_driver, &s->port);
++#endif /* CONFIG_PM */
++ return 0;
++}
++
++/* Spi driver data */
++static struct spi_driver max3107_driver = {
++ .driver = {
++ .name = "max3107",
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = max3107_probe,
++ .remove = __devexit_p(max3107_remove),
++ .suspend = max3107_suspend,
++ .resume = max3107_resume,
++};
++
++/* Driver init function */
++static int __init max3107_init(void)
++{
++ DBG_TRACE("enter\n");
++ return spi_register_driver(&max3107_driver);
++}
++
++/* Driver exit function */
++static void __exit max3107_exit(void)
++{
++ DBG_TRACE("enter\n");
++ spi_unregister_driver(&max3107_driver);
++}
++
++module_init(max3107_init);
++module_exit(max3107_exit);
++
++MODULE_DESCRIPTION("MAX3107 driver");
++MODULE_AUTHOR("Aavamobile");
++MODULE_ALIAS("max3107-spi-uart");
++MODULE_LICENSE("GPLv2");
+Index: linux-2.6.33/drivers/spi/mrst_spi.c
+===================================================================
+--- linux-2.6.33.orig/drivers/spi/mrst_spi.c
++++ linux-2.6.33/drivers/spi/mrst_spi.c
+@@ -1364,8 +1364,16 @@ static struct pci_driver mrst_spi_driver
+ .resume = mrst_spi_resume,
+ };
+
++/*
++ * spi_register_master will call scan board info, and MRST
++ * should only have one board_info registered
++ */
+ static int __init mrst_spi_init(void)
+ {
++/*#ifdef CONFIG_SERIAL_MAX3107*/
++/* spi_register_board_info(mrst_spi_board_info,*/
++/* ARRAY_SIZE(mrst_spi_board_info));*/
++/*#endif*/
+ return pci_register_driver(&mrst_spi_driver);
+ }
+
+Index: linux-2.6.33/include/linux/serial_max3107.h
+===================================================================
+--- /dev/null
++++ linux-2.6.33/include/linux/serial_max3107.h
+@@ -0,0 +1,352 @@
++/*
++ * max3107.h - spi uart protocol driver header for Maxim 3107
++ *
++ * Copyright (C) Aavamobile 2009
++ * Based on serial_max3100.h by Christian Pellegrin
++ *
++ * 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; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef _LINUX_SERIAL_MAX3107_H
++#define _LINUX_SERIAL_MAX3107_H
++
++/* Serial definitions */
++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
++
++/* Serial error status definitions */
++#define MAX3107_PARITY_ERROR 1
++#define MAX3107_FRAME_ERROR 2
++#define MAX3107_OVERRUN_ERROR 4
++#define MAX3107_ALL_ERRORS (MAX3107_PARITY_ERROR | \
++ MAX3107_FRAME_ERROR | \
++ MAX3107_OVERRUN_ERROR)
++
++
++/* TTY definitions */
++#define MAX3107_MAJOR TTY_MAJOR
++#define MAX3107_MINOR 65
++
++
++/* GPIO definitions */
++#define MAX3107_GPIO_BASE 88
++#define MAX3107_GPIO_COUNT 4
++
++
++/* GPIO connected to chip's reset pin */
++#define MAX3107_RESET_GPIO 87
++
++
++/* Chip reset delay */
++#define MAX3107_RESET_DELAY 10
++
++/* Chip wakeup delay */
++#define MAX3107_WAKEUP_DELAY 50
++
++
++/* Sleep mode definitions */
++#define MAX3107_DISABLE_FORCED_SLEEP 0
++#define MAX3107_ENABLE_FORCED_SLEEP 1
++#define MAX3107_DISABLE_AUTOSLEEP 2
++#define MAX3107_ENABLE_AUTOSLEEP 3
++
++
++/* Definitions for register access with SPI transfers
++ *
++ * SPI transfer format:
++ *
++ * Master to slave bits xzzzzzzzyyyyyyyy
++ * Slave to master bits aaaaaaaabbbbbbbb
++ *
++ * where:
++ * x = 0 for reads, 1 for writes
++ * z = register address
++ * y = new register value if write, 0 if read
++ * a = unspecified
++ * b = register value if read, unspecified if write
++ */
++
++/* SPI speed */
++#define MAX3107_SPI_SPEED (3125000 * 2)
++
++/* Write bit */
++#define MAX3107_WRITE_BIT (1 << 15)
++
++/* SPI TX data mask */
++#define MAX3107_SPI_RX_DATA_MASK (0x00ff)
++
++/* SPI RX data mask */
++#define MAX3107_SPI_TX_DATA_MASK (0x00ff)
++
++/* Register access masks */
++#define MAX3107_RHR_REG (0x0000) /* RX FIFO */
++#define MAX3107_THR_REG (0x0000) /* TX FIFO */
++#define MAX3107_IRQEN_REG (0x0100) /* IRQ enable */
++#define MAX3107_IRQSTS_REG (0x0200) /* IRQ status */
++#define MAX3107_LSR_IRQEN_REG (0x0300) /* LSR IRQ enable */
++#define MAX3107_LSR_IRQSTS_REG (0x0400) /* LSR IRQ status */
++#define MAX3107_SPCHR_IRQEN_REG (0x0500) /* Special char IRQ enable */
++#define MAX3107_SPCHR_IRQSTS_REG (0x0600) /* Special char IRQ status */
++#define MAX3107_STS_IRQEN_REG (0x0700) /* Status IRQ enable */
++#define MAX3107_STS_IRQSTS_REG (0x0800) /* Status IRQ status */
++#define MAX3107_MODE1_REG (0x0900) /* MODE1 */
++#define MAX3107_MODE2_REG (0x0a00) /* MODE2 */
++#define MAX3107_LCR_REG (0x0b00) /* LCR */
++#define MAX3107_RXTO_REG (0x0c00) /* RX timeout */
++#define MAX3107_HDPIXDELAY_REG (0x0d00) /* Auto transceiver delays */
++#define MAX3107_IRDA_REG (0x0e00) /* IRDA settings */
++#define MAX3107_FLOWLVL_REG (0x0f00) /* Flow control levels */
++#define MAX3107_FIFOTRIGLVL_REG (0x1000) /* FIFO IRQ trigger levels */
++#define MAX3107_TXFIFOLVL_REG (0x1100) /* TX FIFO level */
++#define MAX3107_RXFIFOLVL_REG (0x1200) /* RX FIFO level */
++#define MAX3107_FLOWCTRL_REG (0x1300) /* Flow control */
++#define MAX3107_XON1_REG (0x1400) /* XON1 character */
++#define MAX3107_XON2_REG (0x1500) /* XON2 character */
++#define MAX3107_XOFF1_REG (0x1600) /* XOFF1 character */
++#define MAX3107_XOFF2_REG (0x1700) /* XOFF2 character */
++#define MAX3107_GPIOCFG_REG (0x1800) /* GPIO config */
++#define MAX3107_GPIODATA_REG (0x1900) /* GPIO data */
++#define MAX3107_PLLCFG_REG (0x1a00) /* PLL config */
++#define MAX3107_BRGCFG_REG (0x1b00) /* Baud rate generator conf */
++#define MAX3107_BRGDIVLSB_REG (0x1c00) /* Baud rate divisor LSB */
++#define MAX3107_BRGDIVMSB_REG (0x1d00) /* Baud rate divisor MSB */
++#define MAX3107_CLKSRC_REG (0x1e00) /* Clock source */
++#define MAX3107_REVID_REG (0x1f00) /* Revision identification */
++
++/* IRQ register bits */
++#define MAX3107_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
++#define MAX3107_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
++#define MAX3107_IRQ_STS_BIT (1 << 2) /* Status interrupt */
++#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
++#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
++#define MAX3107_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */
++#define MAX3107_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */
++#define MAX3107_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */
++
++/* LSR register bits */
++#define MAX3107_LSR_RXTO_BIT (1 << 0) /* RX timeout */
++#define MAX3107_LSR_RXOVR_BIT (1 << 1) /* RX overrun */
++#define MAX3107_LSR_RXPAR_BIT (1 << 2) /* RX parity error */
++#define MAX3107_LSR_FRERR_BIT (1 << 3) /* Frame error */
++#define MAX3107_LSR_RXBRK_BIT (1 << 4) /* RX break */
++#define MAX3107_LSR_RXNOISE_BIT (1 << 5) /* RX noise */
++#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
++#define MAX3107_LSR_CTS_BIT (1 << 7) /* CTS pin state */
++
++/* Special character register bits */
++#define MAX3107_SPCHR_XON1_BIT (1 << 0) /* XON1 character */
++#define MAX3107_SPCHR_XON2_BIT (1 << 1) /* XON2 character */
++#define MAX3107_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */
++#define MAX3107_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */
++#define MAX3107_SPCHR_BREAK_BIT (1 << 4) /* RX break */
++#define MAX3107_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */
++#define MAX3107_SPCHR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
++#define MAX3107_SPCHR_UNDEF7_BIT (1 << 7) /* Undefined/not used */
++
++/* Status register bits */
++#define MAX3107_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */
++#define MAX3107_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */
++#define MAX3107_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */
++#define MAX3107_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */
++#define MAX3107_STS_UNDEF4_BIT (1 << 4) /* Undefined/not used */
++#define MAX3107_STS_CLKREADY_BIT (1 << 5) /* Clock ready */
++#define MAX3107_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */
++#define MAX3107_STS_UNDEF7_BIT (1 << 7) /* Undefined/not used */
++
++/* MODE1 register bits */
++#define MAX3107_MODE1_RXDIS_BIT (1 << 0) /* RX disable */
++#define MAX3107_MODE1_TXDIS_BIT (1 << 1) /* TX disable */
++#define MAX3107_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */
++#define MAX3107_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */
++#define MAX3107_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */
++#define MAX3107_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */
++#define MAX3107_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */
++#define MAX3107_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */
++
++/* MODE2 register bits */
++#define MAX3107_MODE2_RST_BIT (1 << 0) /* Chip reset */
++#define MAX3107_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */
++#define MAX3107_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */
++#define MAX3107_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */
++#define MAX3107_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */
++#define MAX3107_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */
++#define MAX3107_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */
++#define MAX3107_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */
++
++/* LCR register bits */
++#define MAX3107_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
++#define MAX3107_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
++ *
++ * Word length bits table:
++ * 00 -> 5 bit words
++ * 01 -> 6 bit words
++ * 10 -> 7 bit words
++ * 11 -> 8 bit words
++ */
++#define MAX3107_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
++ *
++ * STOP length bit table:
++ * 0 -> 1 stop bit
++ * 1 -> 1-1.5 stop bits if
++ * word length is 5,
++ * 2 stop bits otherwise
++ */
++#define MAX3107_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
++#define MAX3107_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
++#define MAX3107_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
++#define MAX3107_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
++#define MAX3107_LCR_RTS_BIT (1 << 7) /* RTS pin control */
++#define MAX3107_LCR_WORD_LEN_5 (0x0000)
++#define MAX3107_LCR_WORD_LEN_6 (0x0001)
++#define MAX3107_LCR_WORD_LEN_7 (0x0002)
++#define MAX3107_LCR_WORD_LEN_8 (0x0003)
++
++
++/* IRDA register bits */
++#define MAX3107_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
++#define MAX3107_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
++#define MAX3107_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
++#define MAX3107_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
++#define MAX3107_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
++#define MAX3107_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
++#define MAX3107_IRDA_UNDEF6_BIT (1 << 6) /* Undefined/not used */
++#define MAX3107_IRDA_UNDEF7_BIT (1 << 7) /* Undefined/not used */
++
++/* Flow control trigger level register masks */
++#define MAX3107_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
++#define MAX3107_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
++#define MAX3107_FLOWLVL_HALT(words) ((words/8) & 0x000f)
++#define MAX3107_FLOWLVL_RES(words) (((words/8) & 0x000f) << 4)
++
++/* FIFO interrupt trigger level register masks */
++#define MAX3107_FIFOTRIGLVL_TX_MASK (0x000f) /* TX FIFO trigger level */
++#define MAX3107_FIFOTRIGLVL_RX_MASK (0x00f0) /* RX FIFO trigger level */
++#define MAX3107_FIFOTRIGLVL_TX(words) ((words/8) & 0x000f)
++#define MAX3107_FIFOTRIGLVL_RX(words) (((words/8) & 0x000f) << 4)
++
++/* Flow control register bits */
++#define MAX3107_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */
++#define MAX3107_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */
++#define MAX3107_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
++ * are used in conjunction with
++ * XOFF2 for definition of
++ * special character */
++#define MAX3107_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
++#define MAX3107_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
++#define MAX3107_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
++ *
++ * SWFLOW bits 1 & 0 table:
++ * 00 -> no transmitter flow
++ * control
++ * 01 -> receiver compares
++ * XON2 and XOFF2
++ * and controls
++ * transmitter
++ * 10 -> receiver compares
++ * XON1 and XOFF1
++ * and controls
++ * transmitter
++ * 11 -> receiver compares
++ * XON1, XON2, XOFF1 and
++ * XOFF2 and controls
++ * transmitter
++ */
++#define MAX3107_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */
++#define MAX3107_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3
++ *
++ * SWFLOW bits 3 & 2 table:
++ * 00 -> no received flow
++ * control
++ * 01 -> transmitter generates
++ * XON2 and XOFF2
++ * 10 -> transmitter generates
++ * XON1 and XOFF1
++ * 11 -> transmitter generates
++ * XON1, XON2, XOFF1 and
++ * XOFF2
++ */
++
++/* GPIO configuration register bits */
++#define MAX3107_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
++#define MAX3107_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
++#define MAX3107_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
++#define MAX3107_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
++#define MAX3107_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
++#define MAX3107_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
++#define MAX3107_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
++#define MAX3107_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
++
++/* GPIO DATA register bits */
++#define MAX3107_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
++#define MAX3107_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
++#define MAX3107_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
++#define MAX3107_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
++#define MAX3107_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
++#define MAX3107_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
++#define MAX3107_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
++#define MAX3107_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
++
++/* PLL configuration register masks */
++#define MAX3107_PLLCFG_PREDIV_MASK (0x003f) /* PLL predivision value */
++#define MAX3107_PLLCFG_PLLFACTOR_MASK (0x00c0) /* PLL multiplication factor */
++
++/* Baud rate generator configuration register masks and bits */
++#define MAX3107_BRGCFG_FRACT_MASK (0x000f) /* Fractional portion of
++ * Baud rate generator divisor
++ */
++#define MAX3107_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
++#define MAX3107_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */
++#define MAX3107_BRGCFG_UNDEF6_BIT (1 << 6) /* Undefined/not used */
++#define MAX3107_BRGCFG_UNDEF7_BIT (1 << 7) /* Undefined/not used */
++
++/* Clock source register bits */
++#define MAX3107_CLKSRC_INTOSC_BIT (1 << 0) /* Internal osc enable */
++#define MAX3107_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */
++#define MAX3107_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */
++#define MAX3107_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */
++#define MAX3107_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
++#define MAX3107_CLKSRC_UNDEF5_BIT (1 << 5) /* Undefined/not used */
++#define MAX3107_CLKSRC_UNDEF6_BIT (1 << 6) /* Undefined/not used */
++#define MAX3107_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
++
++
++/* HW definitions */
++#define MAX3107_RX_FIFO_SIZE 128
++#define MAX3107_TX_FIFO_SIZE 128
++#define MAX3107_REVID1 0x00a0
++#define MAX3107_REVID2 0x00a1
++
++
++/* Baud rate generator configuration values for external clock */
++#define MAX3107_BRG_B300 (0x0A9400 | 0x05)
++#define MAX3107_BRG_B600 (0x054A00 | 0x03)
++#define MAX3107_BRG_B1200 (0x02A500 | 0x01)
++#define MAX3107_BRG_B2400 (0x015200 | 0x09)
++#define MAX3107_BRG_B4800 (0x00A900 | 0x04)
++#define MAX3107_BRG_B9600 (0x005400 | 0x0A)
++#define MAX3107_BRG_B19200 (0x002A00 | 0x05)
++#define MAX3107_BRG_B38400 (0x001500 | 0x03)
++#define MAX3107_BRG_B57600 (0x000E00 | 0x02)
++#define MAX3107_BRG_B115200 (0x000700 | 0x01)
++#define MAX3107_BRG_B230400 (0x000300 | 0x08)
++#define MAX3107_BRG_B460800 (0x000100 | 0x0c)
++#define MAX3107_BRG_B921600 (0x000100 | 0x1c)
++
++/* Baud rate generator configuration values for internal clock */
++#define MAX3107_BRG_IB300 (0x008000 | 0x00)
++#define MAX3107_BRG_IB600 (0x004000 | 0x00)
++#define MAX3107_BRG_IB1200 (0x002000 | 0x00)
++#define MAX3107_BRG_IB2400 (0x001000 | 0x00)
++#define MAX3107_BRG_IB4800 (0x000800 | 0x00)
++#define MAX3107_BRG_IB9600 (0x000400 | 0x00)
++#define MAX3107_BRG_IB19200 (0x000200 | 0x00)
++#define MAX3107_BRG_IB38400 (0x000100 | 0x00)
++#define MAX3107_BRG_IB57600 (0x000000 | 0x0B)
++#define MAX3107_BRG_IB115200 (0x000000 | 0x05)
++#define MAX3107_BRG_IB230400 (0x000000 | 0x03)
++#define MAX3107_BRG_IB460800 (0x000000 | 0x00)
++#define MAX3107_BRG_IB921600 (0x000000 | 0x00)
++
++#endif /* _LINUX_SERIAL_MAX3107_H */
+Index: linux-2.6.33/include/drm/drm_mode.h
+===================================================================
+--- linux-2.6.33.orig/include/drm/drm_mode.h
++++ linux-2.6.33/include/drm/drm_mode.h
+@@ -160,9 +160,9 @@ struct drm_mode_get_encoder {
+ #define DRM_MODE_CONNECTOR_DisplayPort 10
+ #define DRM_MODE_CONNECTOR_HDMIA 11
+ #define DRM_MODE_CONNECTOR_HDMIB 12
+-#define DRM_MODE_CONNECTOR_TV 13
++#define DRM_MODE_CONNECTOR_TV 15
+ #define DRM_MODE_CONNECTOR_eDP 14
+-#define DRM_MODE_CONNECTOR_MIPI 15
++#define DRM_MODE_CONNECTOR_MIPI 13
+
+ struct drm_mode_get_connector {
+
+Index: linux-2.6.33/drivers/spi/hh2serial.c
+===================================================================
+--- linux-2.6.33.orig/drivers/spi/hh2serial.c
++++ linux-2.6.33/drivers/spi/hh2serial.c
+@@ -1,7 +1,17 @@
++/******************************************************************************
++
++ Copyright (c) 2009
++ Infineon Technologies AG
++ Am Campeon 1-12; 81726 Munich, Germany
++
++ For licensing information, see the file 'LICENSE' in the root folder of
++ this software module.
++
++******************************************************************************/
+ /*
+- * HH2 SPI Serial driver
++ * HH2 SPI Serial driver Version 0.2 Beta
+ *
+- * Copyright (C) 2009 Markus Burvall (Markus.Burvall@swedenconnectivity.com)
++ * Written by: 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
+@@ -10,15 +20,10 @@
+ */
+
+
+-#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
+
++/*#define HH2SERIAL_SHOW_ERRORS*/
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -66,6 +71,7 @@ struct hh2serial_dev {
+ atomic_t tty_need_read;
+ atomic_t spi_irq_pending;
+ int mthread_up;
++ int hhRxBufferBytes;
+ };
+
+ static const char driver_name[] = "hh2serial";
+@@ -89,13 +95,7 @@ static struct hh2serial_dev priv0;
+ #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] */
+@@ -192,9 +192,7 @@ int hh2serial_spi_get_rx_len(struct hh2s
+ buf_ptr = x.rx_buf;
+
+ #ifdef HH2SERIAL_ENABLE_DEBUG
+- printk(KERN_INFO "hh2serial RD:%02X, %02X\n",
+- *buf_ptr,
+- buf_ptr[1]);
++ printk(KERN_INFO "hh2serial RD:%02X, %02X\n", *buf_ptr, buf_ptr[1]);
+ #endif
+
+ #ifndef HH2SERIAL_SPI_16BIT
+@@ -203,33 +201,56 @@ int hh2serial_spi_get_rx_len(struct hh2s
+ ret = *buf_ptr & GPSS_TCNT;
+
+ /* Check buffer overrun or underrun errors */
++#ifdef HH2SERIAL_SHOW_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");
+-
++#endif
++ if (*buf_ptr & GPSS_REMPTY)
++ {
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++ }
+ #else
+ /* 16 bit second byte is status register */
+ /* Available bytes */
+ ret = buf_ptr[1] & GPSS_TCNT;
+
+ /* Check buffer overrun or underrun errors */
++#ifdef HH2SERIAL_SHOW_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
++
++ if (buf_ptr[1] & GPSS_REMPTY)
++ {
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++ }
++#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);
++ printk(KERN_INFO "hh2serial SR:%02X, rx len %d\n", buf_ptr[1], ret);
+ #endif
+ }
++ else
++ {
++#ifdef HH2SERIAL_SHOW_ERRORS
++printk(KERN_INFO "hh2serial Rd_status, spi_sync failed: %d\n",ret);
++#endif
++ ret = 0;
++ }
+
+ kfree(local_buf);
+ return ret;
+@@ -332,11 +353,22 @@ int hh2serial_spi_read(struct hh2serial_
+ available_rd = *buf_ptr & GPSS_TCNT;
+
+ /* Check buffer overrun or underrun errors */
++#ifdef HH2SERIAL_SHOW_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");
++#endif
++
++ if (*buf_ptr & GPSS_REMPTY)
++ {
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++
++ }
+ #else
+ /* 16 bit second byte is status register */
+ /* Every other byte is status register */
+@@ -345,6 +377,7 @@ int hh2serial_spi_read(struct hh2serial_
+ available_rd = (buf_ptr[len_inc_hdr-1] & GPSS_TCNT) - 1;
+
+ /* Check buffer overrun or underrun errors */
++#ifdef HH2SERIAL_SHOW_ERRORS
+ if (buf_ptr[len_inc_hdr-1] & GPSS_TERR)
+ printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+@@ -352,6 +385,14 @@ int hh2serial_spi_read(struct hh2serial_
+ printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+ #endif
+
++ if (buf_ptr[len_inc_hdr-1] & GPSS_REMPTY)
++ {
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++ }
++#endif
+
+ #ifdef HH2SERIAL_ENABLE_DEBUG
+ printk(KERN_INFO "hh2serial_spi_read len inc hdr wr:%d, avail rd %d, cs_change:%d\n",
+@@ -388,6 +429,13 @@ int hh2serial_spi_read(struct hh2serial_
+ #endif
+
+ }
++ else
++ {
++#ifdef HH2SERIAL_SHOW_ERRORS
++printk(KERN_INFO "hh2serial spi_read, spi_sync failed: %d\n",status);
++#endif
++
++ }
+
+ kfree(local_buf);
+ return status;
+@@ -435,8 +483,8 @@ int hh2serial_spi_write(struct hh2serial
+ 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);
++ /* Allocate and make room for 1 byte header(RX and TX) */
++ local_buf = kzalloc(HH2SERIAL_BUFSIZE+2, GFP_KERNEL);
+ if (!local_buf)
+ return -ENOMEM;
+
+@@ -453,7 +501,6 @@ int hh2serial_spi_write(struct hh2serial
+ 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;
+@@ -495,24 +542,55 @@ int hh2serial_spi_write(struct hh2serial
+ available_rd = *buf_ptr & GPSS_TCNT;
+
+ /* Check buffer overrun or underrun errors */
++#ifdef HH2SERIAL_SHOW_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");
++#endif
++ if (*buf_ptr & GPSS_REMPTY)
++ {
++ /* Buffer was empty but len bytes has been written after that */
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES-len;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++ }
++ else
++ {
++ hh2serial->hhRxBufferBytes -= len;
++ }
+ #else
++ /* FIXME_Only last status is interesting or? */
++ /* Might have to check every status register to se if empty */
+ /* 16 bit second byte is status register */
+ /* Available bytes */
+- available_rd = buf_ptr[1] & GPSS_TCNT;
++ available_rd = buf_ptr[len_inc_hdr-1] & GPSS_TCNT;
+
+ /* Check buffer overrun or underrun errors */
+- if (buf_ptr[1] & GPSS_TERR)
++#ifdef HH2SERIAL_SHOW_ERRORS
++ if (buf_ptr[len_inc_hdr-1] & GPSS_TERR)
+ printk(KERN_INFO "hh2serial HH2 transmitter underrun!\n");
+
+- if (buf_ptr[1] & GPSS_RERR)
++ if (buf_ptr[len_inc_hdr-1] & GPSS_RERR)
+ printk(KERN_INFO "hh2serial HH2 receiver overrun!\n");
+ #endif
+
++ if (buf_ptr[len_inc_hdr-1] & GPSS_REMPTY)
++ {
++ /* Buffer was empty but one byte has been written after that */
++ hh2serial->hhRxBufferBytes = HH2SERIAL_SPI_MAX_BYTES-1;
++#ifdef HH2SERIAL_ENABLE_DEBUG
++ printk(KERN_INFO "hh2serial HH2 rx empty!\n");
++#endif
++ }
++ else
++ {
++ /* Only 8 bit of every 16 is data */
++ hh2serial->hhRxBufferBytes -= (len/2);
++ }
++#endif
+
+ #ifdef HH2SERIAL_ENABLE_DEBUG
+ printk(KERN_INFO "hh2serial_spi_write:%02X, %02X\n",
+@@ -526,9 +604,14 @@ int hh2serial_spi_write(struct hh2serial
+
+ *spiAvailData = available_rd;
+
+-
+ }
++ else
++ {
++#ifdef HH2SERIAL_SHOW_ERRORS
++printk(KERN_INFO "hh2serial spi_write, spi_sync failed: %d\n",status);
++#endif
+
++ }
+
+
+ kfree(local_buf);
+@@ -616,61 +699,77 @@ static inline void hh2serial_write_circ_
+ #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++) {
++ while (left || (rxlen > 0)) {
+
+- obuf[i] = (u8)xmit->buf[xmit->tail];
+-
+- xmit->tail = (xmit->tail + 1) &
+- (UART_XMIT_SIZE - 1);
+- }
+-#ifndef HH2SERIAL_SPI_16BIT
++ if (left)
++ {
++ /* FIXME len = MIN(left , hhRxBufferBytes)
++ if len 0 is then only read status register and read */
++
++ len = (left >= priv->hhRxBufferBytes) ? priv->hhRxBufferBytes : left;
++
++
++ if (len > 0)
++ {
++ 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
++
++ /* FIXME check status */
++ hh2serial_spi_write(priv, (u8 *)obuf,
++ &rxlen, len);
++
++ #else
++ /* len * 2 since 16 bits instead of 8 bits */
++ /* FIXME check status */
++ hh2serial_spi_write(priv, (u8 *)obuf,
++ &rxlen, len*2);
++
++ #endif
++ left -= len;
++ }
++ else /* Read rx len */
++ {
++ #ifdef HH2SERIAL_SHOW_ERRORS
++ printk(KERN_INFO "hh2serial wr buf2spi, rxBuf full?\n");
++ #endif
++ rxlen = hh2serial_spi_get_rx_len(priv);
+
+- 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 (rxlen > 0)
++ {
+
+- if (j)
+- hh2serial_write2tty(priv, valid_str, j);
+-
+- priv->port.icount.tx += len;
+- }
++ 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
+@@ -793,7 +892,7 @@ static int hh2serial_main_thread(void *_
+ /* Read from tty send to spi */
+ #ifdef HH2SERIAL_ENABLE_DEBUG
+ printk(KERN_INFO "hh2serial: Read from tty send to spi\n");
+-#endif
++#endif
+ /* Read from tty send to spi */
+ /* Receive data from spi send to UART */
+
+@@ -1153,11 +1252,13 @@ static int hh2serial_startup(struct uart
+ struct hh2serial_dev *priv = container_of(port, struct hh2serial_dev, port);
+ FUNC_ENTER();
+
++ /* Initialize RxBuffer to 0 */
++ priv->hhRxBufferBytes = 0;
+ #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",
++ printk(KERN_INFO "hh2serial Failed to start poll thread: %ld",
+ PTR_ERR(priv->poll_thread));
+ }
+ #endif