diff options
author | Joshua Lock <josh@linux.intel.com> | 2010-05-18 14:51:13 +0100 |
---|---|---|
committer | Joshua Lock <josh@linux.intel.com> | 2010-05-19 12:20:16 +0100 |
commit | 5e8c7c54a9b297dae0081dd19a7bb94e23040a3d (patch) | |
tree | 948e3642c1bf426870b83c72c68c997dce66766c /meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch | |
parent | 5e07bc91281969d54896dd0a13e3d6134e432027 (diff) | |
download | openembedded-core-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.gz |
linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0
Signed-off-by: Joshua Lock <josh@linux.intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch | 3342 |
1 files changed, 3342 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch new file mode 100644 index 0000000000..7336ae66ca --- /dev/null +++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-aava-specific-changes-no-audio.patch @@ -0,0 +1,3342 @@ +From: Prajwal Mohan <prajwal.karur.mohan@intel.com> +Date: Tue, 27 Apr 2010 11:23:00 -0700 +Subject: [PATCH] Aava specific patches + +This driver is from aava + +Signed-off-by: Prajwal Mohan <prajwal.karur.mohan@intel.com> +Patch-mainline: 2.6.34 +--- +Index: linux-2.6.33/drivers/misc/mrst_test_ipc/ipc_module.c +=================================================================== +--- linux-2.6.33.orig/drivers/misc/mrst_test_ipc/ipc_module.c ++++ linux-2.6.33/drivers/misc/mrst_test_ipc/ipc_module.c +@@ -44,8 +44,13 @@ + #include <linux/uaccess.h> + #include <linux/time.h> + ++ ++ + #include <asm/ipc_defs.h> + ++#include <linux/device.h> ++#include <linux/ipc_module.h> ++ + static u32 major; + #define MAX_FW_SIZE 264192 + +@@ -53,9 +58,11 @@ int init_ipc_driver(void); + int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd, + unsigned long arg); + const struct file_operations ipc_fops = { ++owner:THIS_MODULE, + ioctl:ipc_ioctl, + }; + ++static struct class *mid_ipc_class; + + int ipc_ioctl(struct inode *inode, struct file *filp, u32 cmd, + unsigned long arg) +@@ -71,6 +78,18 @@ int ipc_ioctl(struct inode *inode, struc + u8 *fw_buf = NULL ; + + switch (cmd) { ++ case IPC_IOC_PMIC_REG_READ: ++ cmd = IPC_PMIC_REGISTER_READ; ++ break; ++ case IPC_IOC_PMIC_REG_WRITE: ++ cmd = IPC_PMIC_REGISTER_WRITE; ++ break; ++ default: ++ printk(KERN_INFO "ioctl <UNRECOGNIZED> received\n"); ++ break; ++ } ++ ++ switch (cmd) { + case IPC_PMIC_REGISTER_READ: + { + printk(KERN_INFO +@@ -169,6 +188,8 @@ int ipc_ioctl(struct inode *inode, struc + + static int __init ipc_module_init(void) + { ++ struct device *dev; ++ + printk(KERN_INFO "Init ipc_module\n"); + + major = register_chrdev(0, "mid_ipc", &ipc_fops); +@@ -177,6 +198,23 @@ static int __init ipc_module_init(void) + return major; + } + ++ mid_ipc_class = class_create(THIS_MODULE, "mid_ipc"); ++ if (IS_ERR(mid_ipc_class)) { ++ unregister_chrdev(major, "mid_ipc"); ++ return PTR_ERR(mid_ipc_class); ++ } ++ ++ dev = device_create(mid_ipc_class, ++ NULL, ++ MKDEV(major, 0), ++ NULL, ++ "mid_ipc" ); ++ if (IS_ERR(dev)) { ++ class_destroy(mid_ipc_class); ++ unregister_chrdev(major, "mid_ipc"); ++ return PTR_ERR(dev); ++ } ++ + init_ipc_driver ( ) ; + return SUCCESS; + +@@ -184,6 +222,8 @@ static int __init ipc_module_init(void) + + static void __exit ipc_module_exit(void) + { ++ device_destroy(mid_ipc_class, MKDEV(major, 0)); ++ class_destroy(mid_ipc_class); + unregister_chrdev(major, "mid_ipc"); + } + +Index: linux-2.6.33/include/linux/Kbuild +=================================================================== +--- linux-2.6.33.orig/include/linux/Kbuild ++++ linux-2.6.33/include/linux/Kbuild +@@ -385,3 +385,5 @@ unifdef-y += xfrm.h + objhdr-y += version.h + header-y += wimax.h + header-y += wimax/ ++header-y += ipc_module.h ++ +Index: linux-2.6.33/drivers/gpio/gpiolib.c +=================================================================== +--- linux-2.6.33.orig/drivers/gpio/gpiolib.c ++++ linux-2.6.33/drivers/gpio/gpiolib.c +@@ -228,11 +228,14 @@ static ssize_t gpio_direction_show(struc + + if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; +- else +- status = sprintf(buf, "%s\n", +- test_bit(FLAG_IS_OUT, &desc->flags) +- ? "out" : "in"); +- ++ else { ++ status = sprintf(buf, ++ "%s\n", ++ gpio_get_direction( (desc - gpio_desc) ) == ++ DIRECTION_OUT ? ++ "out" : ++ "in"); ++ } + mutex_unlock(&sysfs_lock); + return status; + } +@@ -1507,6 +1510,29 @@ void gpio_set_value_cansleep(unsigned gp + } + EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); + ++enum gpio_direction gpio_get_direction(unsigned gpio) ++{ ++ struct gpio_chip *chip; ++ struct gpio_desc *desc = &gpio_desc[gpio]; ++ ++ chip = gpio_to_chip(gpio); ++ might_sleep_if(extra_checks && chip->can_sleep); ++ ++ if (chip->get_direction) { ++ if (chip->get_direction(chip, gpio - chip->base) == ++ DIRECTION_IN) { ++ clear_bit(FLAG_IS_OUT, &desc->flags); ++ return DIRECTION_IN; ++ } else { ++ set_bit(FLAG_IS_OUT, &desc->flags); ++ return DIRECTION_OUT; ++ } ++ } ++ return test_bit(FLAG_IS_OUT, &desc->flags) ? ++ DIRECTION_OUT : ++ DIRECTION_IN; ++} ++EXPORT_SYMBOL_GPL(gpio_get_direction); + + #ifdef CONFIG_DEBUG_FS + +Index: linux-2.6.33/drivers/gpio/langwell_gpio.c +=================================================================== +--- linux-2.6.33.orig/drivers/gpio/langwell_gpio.c ++++ linux-2.6.33/drivers/gpio/langwell_gpio.c +@@ -107,6 +107,19 @@ static int lnw_gpio_direction_output(str + return 0; + } + ++static enum gpio_direction lnw_gpio_get_direction(struct gpio_chip *chip, ++ unsigned offset) ++{ ++ struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); ++ u8 reg = offset / 32; ++ void __iomem *gpdr; ++ ++ gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]); ++ if (readl(gpdr) & BIT(offset % 32)) ++ return DIRECTION_OUT; ++ return DIRECTION_IN; ++} ++ + static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) + { + struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); +@@ -240,6 +253,7 @@ static int __devinit lnw_gpio_probe(stru + lnw->chip.label = dev_name(&pdev->dev); + lnw->chip.direction_input = lnw_gpio_direction_input; + lnw->chip.direction_output = lnw_gpio_direction_output; ++ lnw->chip.get_direction = lnw_gpio_get_direction; + lnw->chip.get = lnw_gpio_get; + lnw->chip.set = lnw_gpio_set; + lnw->chip.to_irq = lnw_gpio_to_irq; +Index: linux-2.6.33/drivers/gpio/langwell_pmic_gpio.c +=================================================================== +--- linux-2.6.33.orig/drivers/gpio/langwell_pmic_gpio.c ++++ linux-2.6.33/drivers/gpio/langwell_pmic_gpio.c +@@ -165,15 +165,33 @@ static int pmic_gpio_direction_output(st + return rc; + } + +-static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) ++static enum gpio_direction pmic_gpio_get_direction(struct gpio_chip *chip, ++ unsigned offset) + { +- /* we only have 8 GPIO can use as input */ + if (offset > 8) { +- printk(KERN_ERR +- "%s: only pin 0-7 support input\n", __func__); +- return -1; ++ /* GPOWSs and GPOs are always outputs */ ++ return DIRECTION_OUT; + } +- return ipc_read_char(GPIO0 + offset) & GPIO_DIN; ++ if (ipc_read_char(GPIO0 + offset) & GPIO_DIR) ++ return DIRECTION_IN; ++ return DIRECTION_OUT; ++} ++ ++static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ if (offset < 8) { ++ /* GPIOSW: Get state according to direction */ ++ if (pmic_gpio_get_direction( chip, offset ) == DIRECTION_IN) ++ return (ipc_read_char(GPIO0 + offset) & GPIO_DIN); ++ return (ipc_read_char(GPIO0 + offset) & GPIO_DOU); ++ } else if (offset < 16) { ++ /* GPOSW */ ++ return (ipc_read_char(GPOSWCTL0 + offset - 8) & GPOSW_DOU); ++ } else if (offset < 24) { ++ /* GPO */ ++ return (ipc_read_char(GPO) & (1 << (offset - 16))); ++ } ++ return 0; + } + + static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +@@ -284,6 +302,7 @@ static int __devinit pmic_gpio_probe(str + pg->chip.label = "langwell_pmic"; + pg->chip.direction_input = pmic_gpio_direction_input; + pg->chip.direction_output = pmic_gpio_direction_output; ++ pg->chip.get_direction = pmic_gpio_get_direction; + pg->chip.get = pmic_gpio_get; + pg->chip.set = pmic_gpio_set; + pg->chip.to_irq = pmic_gpio_to_irq; +Index: linux-2.6.33/drivers/gpio/pca953x.c +=================================================================== +--- linux-2.6.33.orig/drivers/gpio/pca953x.c ++++ linux-2.6.33/drivers/gpio/pca953x.c +@@ -144,6 +144,24 @@ static int pca953x_gpio_direction_output + return 0; + } + ++static enum gpio_direction pca953x_gpio_get_direction(struct gpio_chip *gc, ++ unsigned off) ++{ ++ struct pca953x_chip *chip; ++ uint16_t reg_val; ++ int ret; ++ ++ chip = container_of(gc, struct pca953x_chip, gpio_chip); ++ ++ ret = pca953x_read_reg(chip, PCA953X_DIRECTION, ®_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 |