From: Prajwal Mohan Date: Tue, 27 Apr 2010 11:23:00 -0700 Subject: [PATCH] Aava specific patches This driver is from aava Signed-off-by: Prajwal Mohan 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 #include + + #include +#include +#include + 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 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 @@ -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 + * + * 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 + +#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 #include #include +/*jhuot start*/ +#include +/*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 #include #include +/*jhuot, added for MAX3107 data*/ +#include + #include #include @@ -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 + * and max3110.c + * by Feng Tang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 #include @@ -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