generic-poky/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aav...

3343 lines
97 KiB
Diff

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