diff options
14 files changed, 3691 insertions, 1 deletions
@@ -103,6 +103,10 @@ tty/tty-release-btm-while-sleeping-in-block_til_ready.patch tty/8250-fix-set_ldisc-operation.patch tty/tty-avoid-recursive-btm-in-pty_close.patch +tty/serial-max3107-introduce-a-max3107-driver.patch +tty/serial-max3107-abstract-out-the-platform-specific-bits.patch +tty/tty_io-remove-casts-from-void.patch + ################################### # USB stuff for after 2.6.35 is out @@ -170,7 +174,17 @@ usb/usb-drivers-usb-makefile-conditionally-descend-to-early.patch usb/usb-xhci-trivial-use-array_size.patch usb/usb-ehci-fix-null-pointer-dererence-in-hcds-that-use-hcd_local_mem.patch usb/usb-musb-tusb6010-fix-compile-error-with-n8x0_defconfig.patch - +usb/usb-gadget-compilation-issue-missing-task_interruptible.patch +usb/usb-gadget-storage_common-comments-updated.patch +usb/usb-serial-io_ti-don-t-return-0-if-writing-the-download-record-failed.patch +usb/usb-core-hcd-pci-use-for_each_pci_dev.patch +usb/usb-musb-use-correct-register-widths-in-register-dumps.patch +usb/usb-musb-fix-compilation-warning-in-host-only-mode.patch +usb/usb-ulpi-fix-compilation-warning.patch +usb/usb-ehci_omap-fix-device-detect-issue-with-modules.patch +usb/usb-musb-kill-board-specific-pinmux-from-driver-file.patch +usb/usb-musb-do-not-override-dma-mode-in-channel-program.patch # staging stuff is now in the staging-next tree on git.kernel.org + diff --git a/tty/serial-max3107-abstract-out-the-platform-specific-bits.patch b/tty/serial-max3107-abstract-out-the-platform-specific-bits.patch new file mode 100644 index 00000000000000..1bdce1ea0c6422 --- /dev/null +++ b/tty/serial-max3107-abstract-out-the-platform-specific-bits.patch @@ -0,0 +1,1158 @@ +From alan@linux.intel.com Thu Jul 8 11:28:08 2010 +From: Alan Cox <alan@linux.intel.com> +Date: Wed, 30 Jun 2010 17:58:38 +0100 +Subject: serial: max3107: Abstract out the platform specific bits +To: greg@kroah.com, linux-serial@vger.kernel.org +Message-ID: <20100630165831.8720.9189.stgit@localhost.localdomain> + + +At the moment there is only one platform type supported and there is is +hard wired, but with these changes the infrastructure is now there for +anyone else to provide methods for their hardware. + +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/Kconfig | 21 +- + drivers/serial/Makefile | 1 + drivers/serial/max3107-aava.c | 344 ++++++++++++++++++++++++++++++++++ + drivers/serial/max3107.c | 413 ++++++++---------------------------------- + drivers/serial/max3107.h | 85 ++++++++ + include/linux/serial_core.h | 4 + 6 files changed, 531 insertions(+), 337 deletions(-) + +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -550,20 +550,29 @@ config SERIAL_S5PV210 + help + Serial port support for Samsung's S5P Family of SoC's + ++ ++config SERIAL_MAX3100 ++ tristate "MAX3100 support" ++ depends on SPI ++ select SERIAL_CORE ++ help ++ MAX3100 chip support ++ + config SERIAL_MAX3107 + tristate "MAX3107 support" +- depends on SPI && GPIOLIB ++ depends on SPI + select SERIAL_CORE +- default y + help + MAX3107 chip support + +-config SERIAL_MAX3100 +- tristate "MAX3100 support" +- depends on SPI ++config SERIAL_MAX3107_AAVA ++ tristate "MAX3107 AAVA platform support" ++ depends on X86_MRST && SERIAL_MAX3107 && GPIOLIB + select SERIAL_CORE + help +- MAX3100 chip support ++ Support for the MAX3107 chip configuration found on the AAVA ++ platform. Includes the extra initialisation and GPIO support ++ neded for this device. + + config SERIAL_DZ + bool "DECstation DZ serial driver" +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -47,6 +47,7 @@ obj-$(CONFIG_SERIAL_S3C6400) += s3c6400. + obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o + obj-$(CONFIG_SERIAL_MAX3100) += max3100.o + obj-$(CONFIG_SERIAL_MAX3107) += max3107.o ++obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o + obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o + obj-$(CONFIG_SERIAL_MUX) += mux.o + obj-$(CONFIG_SERIAL_68328) += 68328serial.o +--- /dev/null ++++ b/drivers/serial/max3107-aava.c +@@ -0,0 +1,344 @@ ++/* ++ * max3107.c - spi uart protocol driver for Maxim 3107 ++ * Based on max3100.c ++ * by Christian Pellegrin <chripell@evolware.org> ++ * and max3110.c ++ * by Feng Tang <feng.tang@intel.com> ++ * ++ * Copyright (C) Aavamobile 2009 ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ */ ++ ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/serial_core.h> ++#include <linux/serial.h> ++#include <linux/spi/spi.h> ++#include <linux/freezer.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/sfi.h> ++#include <asm/mrst.h> ++#include "max3107.h" ++ ++/* 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 */ ++ ++ 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 GPIO 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 GPIO 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 */ ++ ++ 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 gpio 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 conf data w 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 */ ++ ++ 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 GPIO data r 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 */ ++ ++ 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 GPIO data w failed\n"); ++} ++ ++/* GPIO chip data */ ++static struct gpio_chip max3107_gpio_chip = { ++ .owner = THIS_MODULE, ++ .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, ++}; ++ ++/** ++ * max3107_aava_reset - reset on AAVA systems ++ * @spi: The SPI device we are probing ++ * ++ * Reset the device ready for probing. ++ */ ++ ++static int max3107_aava_reset(struct spi_device *spi) ++{ ++ /* Reset the chip */ ++ if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { ++ pr_err("Requesting RESET GPIO failed\n"); ++ return -EIO; ++ } ++ if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { ++ pr_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)) { ++ pr_err("Setting RESET GPIO to 1 failed\n"); ++ gpio_free(MAX3107_RESET_GPIO); ++ return -EIO; ++ } ++ gpio_free(MAX3107_RESET_GPIO); ++ msleep(MAX3107_WAKEUP_DELAY); ++ return 0; ++} ++ ++static int max3107_aava_configure(struct max3107_port *s) ++{ ++ int retval; ++ ++ /* Initialize GPIO chip data */ ++ s->chip = max3107_gpio_chip; ++ s->chip.label = s->spi->modalias; ++ s->chip.dev = &s->spi->dev; ++ ++ /* Add GPIO chip */ ++ retval = gpiochip_add(&s->chip); ++ if (retval) { ++ dev_err(&s->spi->dev, "Adding GPIO chip failed\n"); ++ return retval; ++ } ++ ++ /* Temporary fix for EV2 boot problems, set modem reset to 0 */ ++ max3107_gpio_direction_out(&s->chip, 3, 0); ++ return 0; ++} ++ ++#if 0 ++/* This will get enabled once we have the board stuff merged for this ++ specific case */ ++ ++static const struct baud_table brg13_ext[] = { ++ { 300, MAX3107_BRG13_B300 }, ++ { 600, MAX3107_BRG13_B600 }, ++ { 1200, MAX3107_BRG13_B1200 }, ++ { 2400, MAX3107_BRG13_B2400 }, ++ { 4800, MAX3107_BRG13_B4800 }, ++ { 9600, MAX3107_BRG13_B9600 }, ++ { 19200, MAX3107_BRG13_B19200 }, ++ { 57600, MAX3107_BRG13_B57600 }, ++ { 115200, MAX3107_BRG13_B115200 }, ++ { 230400, MAX3107_BRG13_B230400 }, ++ { 460800, MAX3107_BRG13_B460800 }, ++ { 921600, MAX3107_BRG13_B921600 }, ++ { 0, 0 } ++}; ++ ++static void max3107_aava_init(struct max3107_port *s) ++{ ++ /*override for AAVA SC specific*/ ++ if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { ++ if (get_koski_build_id() <= KOSKI_EV2) ++ if (s->ext_clk) { ++ s->brg_cfg = MAX3107_BRG13_B9600; ++ s->baud_tbl = (struct baud_table *)brg13_ext; ++ } ++ } ++} ++#endif ++ ++static int __devexit max3107_aava_remove(struct spi_device *spi) ++{ ++ struct max3107_port *s = dev_get_drvdata(&spi->dev); ++ ++ /* Remove GPIO chip */ ++ if (gpiochip_remove(&s->chip)) ++ dev_warn(&spi->dev, "Removing GPIO chip failed\n"); ++ ++ /* Then do the default remove */ ++ return max3107_remove(spi); ++} ++ ++/* Platform data */ ++static struct max3107_plat aava_plat_data = { ++ .loopback = 0, ++ .ext_clk = 1, ++/* .init = max3107_aava_init, */ ++ .configure = max3107_aava_configure, ++ .hw_suspend = max3107_hw_susp, ++ .polled_mode = 0, ++ .poll_time = 0, ++}; ++ ++ ++static int __devinit max3107_probe_aava(struct spi_device *spi) ++{ ++ int err = max3107_aava_reset(spi); ++ if (err < 0) ++ return err; ++ return max3107_probe(spi, &aava_plat_data); ++} ++ ++/* Spi driver data */ ++static struct spi_driver max3107_driver = { ++ .driver = { ++ .name = "aava-max3107", ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ }, ++ .probe = max3107_probe_aava, ++ .remove = __devexit_p(max3107_aava_remove), ++ .suspend = max3107_suspend, ++ .resume = max3107_resume, ++}; ++ ++/* Driver init function */ ++static int __init max3107_init(void) ++{ ++ return spi_register_driver(&max3107_driver); ++} ++ ++/* Driver exit function */ ++static void __exit max3107_exit(void) ++{ ++ spi_unregister_driver(&max3107_driver); ++} ++ ++module_init(max3107_init); ++module_exit(max3107_exit); ++ ++MODULE_DESCRIPTION("MAX3107 driver"); ++MODULE_AUTHOR("Aavamobile"); ++MODULE_ALIAS("aava-max3107-spi"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/serial/max3107.c ++++ b/drivers/serial/max3107.c +@@ -31,98 +31,12 @@ + #include <linux/device.h> + #include <linux/serial_core.h> + #include <linux/serial.h> ++#include <linux/gpio.h> + #include <linux/spi/spi.h> + #include <linux/freezer.h> +-#include <linux/platform_device.h> +-#include <linux/gpio.h> +-#include <linux/sfi.h> +-#include <asm/mrst.h> + #include "max3107.h" + +-struct baud_table { +- int baud; +- u32 new_brg; +-}; +- +-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 */ +- +- u16 irqen_reg; /* Current IRQ enable register value */ +- /* Shared data */ +- 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 +- */ +- struct baud_table *baud_tbl; +- int handle_irq; /* Indicates that IRQ should be handled */ +- +- /* Rx buffer and str*/ +- u16 *rxbuf; +- u8 *rxstr; +- /* Tx buffer*/ +- u16 *txbuf; +-}; +- +-/* 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; +-}; +- +-static struct baud_table brg13_ext[] = { +- { 300, MAX3107_BRG13_B300 }, +- { 600, MAX3107_BRG13_B600 }, +- { 1200, MAX3107_BRG13_B1200 }, +- { 2400, MAX3107_BRG13_B2400 }, +- { 4800, MAX3107_BRG13_B4800 }, +- { 9600, MAX3107_BRG13_B9600 }, +- { 19200, MAX3107_BRG13_B19200 }, +- { 57600, MAX3107_BRG13_B57600 }, +- { 115200, MAX3107_BRG13_B115200 }, +- { 230400, MAX3107_BRG13_B230400 }, +- { 460800, MAX3107_BRG13_B460800 }, +- { 921600, MAX3107_BRG13_B921600 }, +- { 0, 0 } +-}; +- +-static struct baud_table brg26_ext[] = { ++static const struct baud_table brg26_ext[] = { + { 300, MAX3107_BRG26_B300 }, + { 600, MAX3107_BRG26_B600 }, + { 1200, MAX3107_BRG26_B1200 }, +@@ -138,7 +52,7 @@ static struct baud_table brg26_ext[] = { + { 0, 0 } + }; + +-static struct baud_table brg13_int[] = { ++static const struct baud_table brg13_int[] = { + { 300, MAX3107_BRG13_IB300 }, + { 600, MAX3107_BRG13_IB600 }, + { 1200, MAX3107_BRG13_IB1200 }, +@@ -157,7 +71,7 @@ static struct baud_table brg13_int[] = { + static u32 get_new_brg(int baud, struct max3107_port *s) + { + int i; +- struct baud_table *baud_tbl = s->baud_tbl; ++ const struct baud_table *baud_tbl = s->baud_tbl; + + for (i = 0; i < 13; i++) { + if (baud == baud_tbl[i].baud) +@@ -168,7 +82,7 @@ static u32 get_new_brg(int baud, struct + } + + /* Perform SPI transfer for write/read of device register(s) */ +-static int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len) ++int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len) + { + struct spi_message spi_msg; + struct spi_transfer spi_xfer; +@@ -213,6 +127,7 @@ static int max3107_rw(struct max3107_por + #endif + return 0; + } ++EXPORT_SYMBOL_GPL(max3107_rw); + + /* Puts received data to circular buffer */ + static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data, +@@ -611,16 +526,10 @@ static void max3107_register_init(struct + s->brg_cfg = MAX3107_BRG13_IB9600; + s->baud_tbl = (struct baud_table *)brg13_int; + } +-#if 0 +- /*override for AAVA SC specific*/ +- if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { +- if (get_koski_build_id() <= KOSKI_EV2) +- if (s->ext_clk) { +- s->brg_cfg = MAX3107_BRG13_B9600; +- s->baud_tbl = (struct baud_table *)brg13_ext; +- } +- } +-#endif ++ ++ if (s->pdata->init) ++ s->pdata->init(s); ++ + buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG) + | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK); + buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG) +@@ -734,7 +643,7 @@ static irqreturn_t max3107_irq(int irqno + * used but that would mess the GPIOs + * + */ +-static void max3107_hw_susp(struct max3107_port *s, int suspend) ++void max3107_hw_susp(struct max3107_port *s, int suspend) + { + pr_debug("enter, suspend %d\n", suspend); + +@@ -752,6 +661,7 @@ static void max3107_hw_susp(struct max31 + max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP); + } + } ++EXPORT_SYMBOL_GPL(max3107_hw_susp); + + /* Modem status IRQ enabling */ + static void max3107_enable_ms(struct uart_port *port) +@@ -899,10 +809,8 @@ static void max3107_shutdown(struct uart + { + struct max3107_port *s = container_of(port, struct max3107_port, port); + +- if (s->suspended) { +- /* Resume HW */ +- max3107_hw_susp(s, 0); +- } ++ if (s->suspended && s->pdata->hw_suspend) ++ s->pdata->hw_suspend(s, 0); + + /* Free the interrupt */ + free_irq(s->spi->irq, s); +@@ -915,7 +823,8 @@ static void max3107_shutdown(struct uart + } + + /* Suspend HW */ +- max3107_hw_susp(s, 1); ++ if (s->pdata->hw_suspend) ++ s->pdata->hw_suspend(s, 1); + } + + /* Port startup function */ +@@ -941,7 +850,8 @@ static int max3107_startup(struct uart_p + } + + /* Resume HW */ +- max3107_hw_susp(s, 0); ++ if (s->pdata->hw_suspend) ++ s->pdata->hw_suspend(s, 0); + + /* Init registers */ + max3107_register_init(s); +@@ -973,16 +883,14 @@ static int max3107_request_port(struct u + 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 series */ +- s->port.type = PORT_MAX3100; ++ s->port.type = PORT_MAX3107; + } + + /* 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) ++ if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107) + return 0; + + return -EINVAL; +@@ -1000,157 +908,6 @@ static void max3107_break_ctl(struct uar + /* We don't support break control, do nothing */ + } + +-/* 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 */ +- +- 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 GPIO 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 GPIO 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 */ +- +- 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 gpio 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 conf data w 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 */ +- +- 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 GPIO data r 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 */ +- +- 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 GPIO data w failed\n"); +-} +- +-/* Platform data */ +-static struct max3107_plat max3107_plat_data = { +- .loopback = 0, +- .ext_clk = 1, +- .max3107_hw_suspend = &max3107_hw_susp, +- .polled_mode = 0, +- .poll_time = 0, +-}; + + /* Port functions */ + static struct uart_ops max3107_ops = { +@@ -1180,52 +937,48 @@ static struct uart_driver max3107_uart_d + .nr = 1, + }; + +-/* GPIO chip data */ +-static struct gpio_chip max3107_gpio_chip = { +- .owner = THIS_MODULE, +- .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, ++static int driver_registered = 0; ++ ++ ++ ++/* 'Generic' platform data */ ++static struct max3107_plat generic_plat_data = { ++ .loopback = 0, ++ .ext_clk = 1, ++ .hw_suspend = max3107_hw_susp, ++ .polled_mode = 0, ++ .poll_time = 0, + }; +-/* Device probe function */ +-static int __devinit max3107_probe(struct spi_device *spi) ++ ++ ++/*******************************************************************/ ++ ++/** ++ * max3107_probe - SPI bus probe entry point ++ * @spi: the spi device ++ * ++ * SPI wants us to probe this device and if appropriate claim it. ++ * Perform any platform specific requirements and then initialise ++ * the device. ++ */ ++ ++int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) + { + struct max3107_port *s; +- struct max3107_plat *pdata = &max3107_plat_data; + u16 buf[2]; /* Buffer for SPI transfers */ + int retval; + + pr_info("enter max3107 probe\n"); + +- /* Reset the chip */ +- if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { +- pr_err("Requesting RESET GPIO failed\n"); +- return -EIO; +- } +- if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { +- pr_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)) { +- pr_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) { + pr_err("Allocating port structure failed\n"); + return -ENOMEM; + } ++ ++ s->pdata = pdata; ++ + /* SPI Rx buffer + * +2 for RX FIFO interrupt + * disabling and RX level query +@@ -1298,10 +1051,13 @@ static int __devinit max3107_probe(struc + } + + /* Register UART driver */ +- retval = uart_register_driver(&max3107_uart_driver); +- if (retval) { +- dev_err(&s->spi->dev, "Registering UART driver failed\n"); +- return retval; ++ if (!driver_registered) { ++ retval = uart_register_driver(&max3107_uart_driver); ++ if (retval) { ++ dev_err(&s->spi->dev, "Registering UART driver failed\n"); ++ return retval; ++ } ++ driver_registered = 1; + } + + /* Initialize UART port data */ +@@ -1312,8 +1068,7 @@ static int __devinit max3107_probe(struc + 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 in the same series */ +- s->port.type = PORT_MAX3100; ++ s->port.type = PORT_MAX3107; + + /* Add UART port */ + retval = uart_add_one_port(&max3107_uart_driver, &s->port); +@@ -1322,44 +1077,31 @@ static int __devinit max3107_probe(struc + 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; ++ if (pdata->configure) { ++ retval = pdata->configure(s); ++ if (retval < 0) ++ return retval; + } + +- /* Temporary fix for EV2 boot problems, set modem reset to 0 */ +- max3107_gpio_direction_out(&s->chip, 3, 0); +- + /* Go to suspend mode */ +- max3107_hw_susp(s, 1); ++ if (pdata->hw_suspend) ++ pdata->hw_suspend(s, 1); + + return 0; + } ++EXPORT_SYMBOL_GPL(max3107_probe); + + /* Driver remove function */ +-static int __devexit max3107_remove(struct spi_device *spi) ++int max3107_remove(struct spi_device *spi) + { + struct max3107_port *s = dev_get_drvdata(&spi->dev); + + pr_info("enter max3107 remove\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 TxRx buffer */ + kfree(s->rxbuf); +@@ -1371,9 +1113,10 @@ static int __devexit max3107_remove(stru + + return 0; + } ++EXPORT_SYMBOL_GPL(max3107_remove); + + /* Driver suspend function */ +-static int max3107_suspend(struct spi_device *spi, pm_message_t state) ++int max3107_suspend(struct spi_device *spi, pm_message_t state) + { + #ifdef CONFIG_PM + struct max3107_port *s = dev_get_drvdata(&spi->dev); +@@ -1384,13 +1127,15 @@ static int max3107_suspend(struct spi_de + uart_suspend_port(&max3107_uart_driver, &s->port); + + /* Go to suspend mode */ +- max3107_hw_susp(s, 1); ++ if (s->pdata->hw_suspend) ++ s->pdata->hw_suspend(s, 1); + #endif /* CONFIG_PM */ + return 0; + } ++EXPORT_SYMBOL_GPL(max3107_suspend); + + /* Driver resume function */ +-static int max3107_resume(struct spi_device *spi) ++int max3107_resume(struct spi_device *spi) + { + #ifdef CONFIG_PM + struct max3107_port *s = dev_get_drvdata(&spi->dev); +@@ -1398,13 +1143,20 @@ static int max3107_resume(struct spi_dev + pr_debug("enter resume\n"); + + /* Resume from suspend */ +- max3107_hw_susp(s, 0); ++ if (s->pdata->hw_suspend) ++ s->pdata->hw_suspend(s, 0); + + /* Resume UART port */ + uart_resume_port(&max3107_uart_driver, &s->port); + #endif /* CONFIG_PM */ + return 0; + } ++EXPORT_SYMBOL_GPL(max3107_resume); ++ ++static int max3107_probe_generic(struct spi_device *spi) ++{ ++ return max3107_probe(spi, &generic_plat_data); ++} + + /* Spi driver data */ + static struct spi_driver max3107_driver = { +@@ -1413,7 +1165,7 @@ static struct spi_driver max3107_driver + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, +- .probe = max3107_probe, ++ .probe = max3107_probe_generic, + .remove = __devexit_p(max3107_remove), + .suspend = max3107_suspend, + .resume = max3107_resume, +@@ -1430,6 +1182,9 @@ static int __init max3107_init(void) + static void __exit max3107_exit(void) + { + pr_info("enter max3107 exit\n"); ++ /* Unregister UART driver */ ++ if (driver_registered) ++ uart_unregister_driver(&max3107_uart_driver); + spi_unregister_driver(&max3107_driver); + } + +@@ -1438,5 +1193,5 @@ module_exit(max3107_exit); + + MODULE_DESCRIPTION("MAX3107 driver"); + MODULE_AUTHOR("Aavamobile"); +-MODULE_ALIAS("max3107-spi-uart"); +-MODULE_LICENSE("GPLv2"); ++MODULE_ALIAS("max3107-spi"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/serial/max3107.h ++++ b/drivers/serial/max3107.h +@@ -10,8 +10,8 @@ + * (at your option) any later version. + */ + +-#ifndef _LINUX_SERIAL_MAX3107_H +-#define _LINUX_SERIAL_MAX3107_H ++#ifndef _MAX3107_H ++#define _MAX3107_H + + /* Serial error status definitions */ + #define MAX3107_PARITY_ERROR 1 +@@ -355,4 +355,85 @@ + #define MAX3107_BRG13_IB460800 (0x000000 | 0x00) + #define MAX3107_BRG13_IB921600 (0x000000 | 0x00) + ++ ++struct baud_table { ++ int baud; ++ u32 new_brg; ++}; ++ ++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 */ ++ ++ u16 irqen_reg; /* Current IRQ enable register value */ ++ /* Shared data */ ++ 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 ++ */ ++ struct baud_table *baud_tbl; ++ int handle_irq; /* Indicates that IRQ should be handled */ ++ ++ /* Rx buffer and str*/ ++ u16 *rxbuf; ++ u8 *rxstr; ++ /* Tx buffer*/ ++ u16 *txbuf; ++ ++ struct max3107_plat *pdata; /* Platform data */ ++}; ++ ++/* Platform data structure */ ++struct max3107_plat { ++ /* Loopback mode enable */ ++ int loopback; ++ /* External clock enable */ ++ int ext_clk; ++ /* Called during the register initialisation */ ++ void (*init)(struct max3107_port *s); ++ /* Called when the port is found and configured */ ++ int (*configure)(struct max3107_port *s); ++ /* HW suspend function */ ++ void (*hw_suspend) (struct max3107_port *s, int suspend); ++ /* Polling mode enable */ ++ int polled_mode; ++ /* Polling period if polling mode enabled */ ++ int poll_time; ++}; ++ ++extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len); ++extern void max3107_hw_susp(struct max3107_port *s, int suspend); ++extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata); ++extern int max3107_remove(struct spi_device *spi); ++extern int max3107_suspend(struct spi_device *spi, pm_message_t state); ++extern int max3107_resume(struct spi_device *spi); ++ + #endif /* _LINUX_SERIAL_MAX3107_H */ +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -186,6 +186,10 @@ + #define PORT_ALTERA_JTAGUART 91 + #define PORT_ALTERA_UART 92 + ++/* MAX3107 */ ++#define PORT_MAX3107 94 ++ ++ + #ifdef __KERNEL__ + + #include <linux/compiler.h> diff --git a/tty/serial-max3107-introduce-a-max3107-driver.patch b/tty/serial-max3107-introduce-a-max3107-driver.patch new file mode 100644 index 00000000000000..56b648f6d3850f --- /dev/null +++ b/tty/serial-max3107-introduce-a-max3107-driver.patch @@ -0,0 +1,1860 @@ +From alan@linux.intel.com Thu Jul 8 11:27:42 2010 +From: jianwei.yang <jianwei.yang@intel.com> +Date: Wed, 30 Jun 2010 17:57:12 +0100 +Subject: serial: max3107: introduce a max3107 driver +To: greg@kroah.com, linux-serial@vger.kernel.org +Message-ID: <20100630165707.8519.16480.stgit@localhost.localdomain> + + +From: jianwei.yang <jianwei.yang@intel.com> + +This device is used by some of the Intel MID platforms. It's not similar +enough to the MAX3100 to use the same driver. + +At this point the driver is specific to the platform and not generalised. +We will fix that later. + +Signed-off-by: jianwei.yang <jianwei.yang@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/Kconfig | 8 + drivers/serial/Makefile | 1 + drivers/serial/max3107.c | 1442 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/serial/max3107.h | 358 +++++++++++ + 4 files changed, 1809 insertions(+) + +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -550,6 +550,14 @@ config SERIAL_S5PV210 + help + Serial port support for Samsung's S5P Family of SoC's + ++config SERIAL_MAX3107 ++ tristate "MAX3107 support" ++ depends on SPI && GPIOLIB ++ select SERIAL_CORE ++ default y ++ help ++ MAX3107 chip support ++ + config SERIAL_MAX3100 + tristate "MAX3100 support" + depends on SPI +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0. + obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o + obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.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 +--- /dev/null ++++ b/drivers/serial/max3107.c +@@ -0,0 +1,1442 @@ ++/* ++ * max3107.c - spi uart protocol driver for Maxim 3107 ++ * Based on max3100.c ++ * by Christian Pellegrin <chripell@evolware.org> ++ * and max3110.c ++ * by Feng Tang <feng.tang@intel.com> ++ * ++ * Copyright (C) Aavamobile 2009 ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * ++ */ ++ ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/serial_core.h> ++#include <linux/serial.h> ++#include <linux/spi/spi.h> ++#include <linux/freezer.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/sfi.h> ++#include <asm/mrst.h> ++#include "max3107.h" ++ ++struct baud_table { ++ int baud; ++ u32 new_brg; ++}; ++ ++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 */ ++ ++ u16 irqen_reg; /* Current IRQ enable register value */ ++ /* Shared data */ ++ 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 ++ */ ++ struct baud_table *baud_tbl; ++ int handle_irq; /* Indicates that IRQ should be handled */ ++ ++ /* Rx buffer and str*/ ++ u16 *rxbuf; ++ u8 *rxstr; ++ /* Tx buffer*/ ++ u16 *txbuf; ++}; ++ ++/* 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; ++}; ++ ++static struct baud_table brg13_ext[] = { ++ { 300, MAX3107_BRG13_B300 }, ++ { 600, MAX3107_BRG13_B600 }, ++ { 1200, MAX3107_BRG13_B1200 }, ++ { 2400, MAX3107_BRG13_B2400 }, ++ { 4800, MAX3107_BRG13_B4800 }, ++ { 9600, MAX3107_BRG13_B9600 }, ++ { 19200, MAX3107_BRG13_B19200 }, ++ { 57600, MAX3107_BRG13_B57600 }, ++ { 115200, MAX3107_BRG13_B115200 }, ++ { 230400, MAX3107_BRG13_B230400 }, ++ { 460800, MAX3107_BRG13_B460800 }, ++ { 921600, MAX3107_BRG13_B921600 }, ++ { 0, 0 } ++}; ++ ++static struct baud_table brg26_ext[] = { ++ { 300, MAX3107_BRG26_B300 }, ++ { 600, MAX3107_BRG26_B600 }, ++ { 1200, MAX3107_BRG26_B1200 }, ++ { 2400, MAX3107_BRG26_B2400 }, ++ { 4800, MAX3107_BRG26_B4800 }, ++ { 9600, MAX3107_BRG26_B9600 }, ++ { 19200, MAX3107_BRG26_B19200 }, ++ { 57600, MAX3107_BRG26_B57600 }, ++ { 115200, MAX3107_BRG26_B115200 }, ++ { 230400, MAX3107_BRG26_B230400 }, ++ { 460800, MAX3107_BRG26_B460800 }, ++ { 921600, MAX3107_BRG26_B921600 }, ++ { 0, 0 } ++}; ++ ++static struct baud_table brg13_int[] = { ++ { 300, MAX3107_BRG13_IB300 }, ++ { 600, MAX3107_BRG13_IB600 }, ++ { 1200, MAX3107_BRG13_IB1200 }, ++ { 2400, MAX3107_BRG13_IB2400 }, ++ { 4800, MAX3107_BRG13_IB4800 }, ++ { 9600, MAX3107_BRG13_IB9600 }, ++ { 19200, MAX3107_BRG13_IB19200 }, ++ { 57600, MAX3107_BRG13_IB57600 }, ++ { 115200, MAX3107_BRG13_IB115200 }, ++ { 230400, MAX3107_BRG13_IB230400 }, ++ { 460800, MAX3107_BRG13_IB460800 }, ++ { 921600, MAX3107_BRG13_IB921600 }, ++ { 0, 0 } ++}; ++ ++static u32 get_new_brg(int baud, struct max3107_port *s) ++{ ++ int i; ++ struct baud_table *baud_tbl = s->baud_tbl; ++ ++ for (i = 0; i < 13; i++) { ++ if (baud == baud_tbl[i].baud) ++ return baud_tbl[i].new_brg; ++ } ++ ++ return 0; ++} ++ ++/* 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; ++ ++ /* 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; ++ pr_info("tx len %d:\n", spi_xfer.len); ++ for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) ++ pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]); ++ pr_info("\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; ++ pr_info("rx len %d:\n", spi_xfer.len); ++ for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) ++ pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]); ++ pr_info("\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; ++ ++ if (!port->state) ++ return; ++ ++ tty = port->state->port.tty; ++ if (!tty) ++ 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; ++ u8 *valid_str; ++ ++ 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; ++ } ++ if ((s->rxbuf == 0) || (s->rxstr == 0)) { ++ dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n"); ++ return; ++ } ++ buf = s->rxbuf; ++ valid_str = s->rxstr; ++ while (rxlvl) { ++ pr_debug("rxlvl %d\n", rxlvl); ++ /* Clear buffer */ ++ memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2)); ++ len = 0; ++ if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) { ++ /* First disable RX FIFO interrupt */ ++ pr_debug("Disabling RX INT\n"); ++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); ++ s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT; ++ buf[0] |= s->irqen_reg; ++ 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 h 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 */ ++ pr_debug("Enabling RX INT\n"); ++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); ++ s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT; ++ buf[0] |= s->irqen_reg; ++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) ++ dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n"); ++ } ++ ++ /* Push the received data to receivers */ ++ if (s->port.state->port.tty) ++ 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; ++ unsigned long flags; ++ int len; /* SPI transfer buffer length */ ++ u16 *buf; ++ ++ 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; ++ ++ if (!s->txbuf) { ++ dev_warn(&s->spi->dev, "Txbuf isn't ready\n"); ++ return; ++ } ++ buf = s->txbuf; ++ /* 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; ++ ++ pr_debug("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 */ ++ pr_debug("Disabling TE INT\n"); ++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); ++ s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT; ++ buf[i] |= s->irqen_reg; ++ i++; ++ len++; ++ } ++ /* Add data to send */ ++ spin_lock_irqsave(&s->port.lock, flags); ++ 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); ++ } ++ spin_unlock_irqrestore(&s->port.lock, flags); ++ if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) { ++ /* Enable TX empty interrupt */ ++ pr_debug("Enabling TE INT\n"); ++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); ++ s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT; ++ buf[i] |= s->irqen_reg; ++ i++; ++ len++; ++ } ++ if (!s->tx_enabled) { ++ /* Enable TX */ ++ pr_debug("Enable TX\n"); ++ buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); ++ spin_lock_irqsave(&s->data_lock, flags); ++ s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT; ++ buf[i] |= s->mode1_reg; ++ spin_unlock_irqrestore(&s->data_lock, flags); ++ 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 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; ++ unsigned long flags; ++ ++ /* 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 INTR handling failed\n"); ++ return 0; ++ } ++ ++ irq_status = (u8)buf[0]; ++ pr_debug("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 ++ */ ++ pr_debug("RX TO INT\n"); ++ } ++ ++ if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) { ++ /* Tx empty interrupt, ++ * disable TX and set tx_fifo_empty flag ++ */ ++ pr_debug("TE INT, disabling TX\n"); ++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); ++ spin_lock_irqsave(&s->data_lock, flags); ++ s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT; ++ buf[0] |= s->mode1_reg; ++ spin_unlock_irqrestore(&s->data_lock, flags); ++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) ++ dev_err(&s->spi->dev, "SPI transfer TX dis 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 ++ */ ++ pr_debug("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); ++ else ++ dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n"); ++} ++ ++/* 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 */ ++ unsigned long flags; ++ ++ /* 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 RX lev failed\n"); ++ rxlvl = 0; ++ } else { ++ rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK); ++ } ++ ++ do { ++ pr_debug("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_irqsave(&s->data_lock, flags); ++ if (s->mode1_commit) { ++ pr_debug("mode1_commit\n"); ++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); ++ buf[len++] |= s->mode1_reg; ++ s->mode1_commit = 0; ++ } ++ if (s->lcr_commit) { ++ pr_debug("lcr_commit\n"); ++ buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG); ++ buf[len++] |= s->lcr_reg; ++ s->lcr_commit = 0; ++ } ++ if (s->brg_commit) { ++ pr_debug("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_irqrestore(&s->data_lock, flags); ++ ++ if (len > 0) { ++ if (max3107_rw(s, (u8 *)buf, NULL, len * 2)) ++ dev_err(&s->spi->dev, ++ "SPI transfer 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 */ ++ unsigned long flags; ++ pr_debug("enter, mode %d\n", mode); ++ ++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); ++ spin_lock_irqsave(&s->data_lock, flags); ++ 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_irqrestore(&s->data_lock, flags); ++ dev_warn(&s->spi->dev, "invalid sleep mode\n"); ++ return; ++ } ++ buf[0] |= s->mode1_reg; ++ spin_unlock_irqrestore(&s->data_lock, flags); ++ ++ if (max3107_rw(s, (u8 *)buf, NULL, 2)) ++ dev_err(&s->spi->dev, "SPI transfer 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) ++{ ++ u16 buf[11]; /* Buffer for SPI transfers */ ++ ++ /* 1. Configure baud rate, 9600 as default */ ++ s->baud = 9600; ++ /* the below is default*/ ++ if (s->ext_clk) { ++ s->brg_cfg = MAX3107_BRG26_B9600; ++ s->baud_tbl = (struct baud_table *)brg26_ext; ++ } else { ++ s->brg_cfg = MAX3107_BRG13_IB9600; ++ s->baud_tbl = (struct baud_table *)brg13_int; ++ } ++#if 0 ++ /*override for AAVA SC specific*/ ++ if (mrst_platform_id() == MRST_PLATFORM_AAVA_SC) { ++ if (get_koski_build_id() <= KOSKI_EV2) ++ if (s->ext_clk) { ++ s->brg_cfg = MAX3107_BRG13_B9600; ++ s->baud_tbl = (struct baud_table *)brg13_ext; ++ } ++ } ++#endif ++ buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG) ++ | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK); ++ buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG) ++ | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK); ++ buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG) ++ | ((s->brg_cfg) & 0xff); ++ ++ /* 2. Configure LCR register, 8N1 mode by default */ ++ s->lcr_reg = MAX3107_LCR_WORD_LEN_8; ++ buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG) ++ | 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[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG) ++ | s->mode1_reg; ++ ++ /* 4. Configure MODE 2 register */ ++ buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); ++ if (s->loopback) { ++ /* Enable loopback */ ++ buf[5] |= MAX3107_MODE2_LOOPBACK_BIT; ++ } ++ /* Reset FIFOs */ ++ buf[5] |= MAX3107_MODE2_FIFORST_BIT; ++ s->tx_fifo_empty = 1; ++ ++ /* 5. Configure FIFO trigger level register */ ++ buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG); ++ /* RX FIFO trigger for 16 words, TX FIFO trigger not used */ ++ buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0)); ++ ++ /* 6. Configure flow control levels */ ++ buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG); ++ /* Flow control halt level 96, resume level 48 */ ++ buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96)); ++ ++ /* 7. Configure flow control */ ++ buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG); ++ /* Enable auto CTS and auto RTS flow control */ ++ buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT); ++ ++ /* 8. Configure RX timeout register */ ++ buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG); ++ /* Timeout after 48 character intervals */ ++ buf[9] |= 0x0030; ++ ++ /* 9. Configure LSR interrupt enable register */ ++ buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG); ++ /* Enable RX timeout interrupt */ ++ buf[10] |= MAX3107_LSR_RXTO_BIT; ++ ++ /* Perform SPI transfer */ ++ if (max3107_rw(s, (u8 *)buf, NULL, 22)) ++ dev_err(&s->spi->dev, "SPI transfer for init failed\n"); ++ ++ /* 10. Clear IRQ status register by reading it */ ++ buf[0] = 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[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG) ++ | s->irqen_reg; ++ ++ /* 12. Clear FIFO reset that was set in step 6 */ ++ buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); ++ if (s->loopback) { ++ /* Keep loopback enabled */ ++ buf[2] |= MAX3107_MODE2_LOOPBACK_BIT; ++ } ++ ++ /* Perform SPI transfer */ ++ if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6)) ++ 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) ++{ ++ pr_debug("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); ++ ++ /* 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); ++ ++ pr_debug("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); ++ unsigned long flags; ++ ++ /* Set RX disabled in MODE 1 register */ ++ spin_lock_irqsave(&s->data_lock, flags); ++ s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT; ++ s->mode1_commit = 1; ++ spin_unlock_irqrestore(&s->data_lock, flags); ++ /* 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; ++ unsigned long flags; ++ ++ if (!port->state) ++ return; ++ ++ tty = port->state->port.tty; ++ if (!tty) ++ 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); ++ ++ spin_lock_irqsave(&s->data_lock, flags); ++ new_brg = get_new_brg(baud, s); ++ /* if can't find the corrent config, use previous */ ++ if (!new_brg) { ++ baud = s->baud; ++ new_brg = s->brg_cfg; ++ } ++ spin_unlock_irqrestore(&s->data_lock, flags); ++ 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_irqsave(&s->data_lock, flags); ++ 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_irqrestore(&s->data_lock, flags); ++ ++ /* 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); ++ ++ 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); ++ ++ /* 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 series */ ++ 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 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 */ ++ ++ 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 GPIO 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 GPIO 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 */ ++ ++ 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 gpio 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 conf data w 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 */ ++ ++ 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 GPIO data r 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 */ ++ ++ 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 GPIO data w failed\n"); ++} ++ ++/* Platform data */ ++static struct max3107_plat max3107_plat_data = { ++ .loopback = 0, ++ .ext_clk = 1, ++ .max3107_hw_suspend = &max3107_hw_susp, ++ .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", ++ .nr = 1, ++}; ++ ++/* GPIO chip data */ ++static struct gpio_chip max3107_gpio_chip = { ++ .owner = THIS_MODULE, ++ .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; ++ ++ pr_info("enter max3107 probe\n"); ++ ++ /* Reset the chip */ ++ if (gpio_request(MAX3107_RESET_GPIO, "max3107")) { ++ pr_err("Requesting RESET GPIO failed\n"); ++ return -EIO; ++ } ++ if (gpio_direction_output(MAX3107_RESET_GPIO, 0)) { ++ pr_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)) { ++ pr_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) { ++ pr_err("Allocating port structure failed\n"); ++ return -ENOMEM; ++ } ++ /* SPI Rx buffer ++ * +2 for RX FIFO interrupt ++ * disabling and RX level query ++ */ ++ s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL); ++ if (!s->rxbuf) { ++ pr_err("Allocating RX buffer failed\n"); ++ return -ENOMEM; ++ } ++ s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL); ++ if (!s->rxstr) { ++ pr_err("Allocating RX buffer failed\n"); ++ return -ENOMEM; ++ } ++ /* SPI Tx buffer ++ * SPI transfer buffer ++ * +3 for TX FIFO empty ++ * interrupt disabling and ++ * enabling and TX enabling ++ */ ++ s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL); ++ if (!s->txbuf) { ++ pr_err("Allocating TX buffer 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 ON */ ++ 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 in the same series */ ++ 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; ++ } ++ ++ /* Temporary fix for EV2 boot problems, set modem reset to 0 */ ++ max3107_gpio_direction_out(&s->chip, 3, 0); ++ ++ /* 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); ++ ++ pr_info("enter max3107 remove\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 TxRx buffer */ ++ kfree(s->rxbuf); ++ kfree(s->rxstr); ++ kfree(s->txbuf); ++ ++ /* 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); ++ ++ pr_debug("enter suspend\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); ++ ++ pr_debug("enter resume\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) ++{ ++ pr_info("enter max3107 init\n"); ++ return spi_register_driver(&max3107_driver); ++} ++ ++/* Driver exit function */ ++static void __exit max3107_exit(void) ++{ ++ pr_info("enter max3107 exit\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"); +--- /dev/null ++++ b/drivers/serial/max3107.h +@@ -0,0 +1,358 @@ ++/* ++ * 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 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) ++ ++/* 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 13MHz */ ++#define MAX3107_BRG13_B300 (0x0A9400 | 0x05) ++#define MAX3107_BRG13_B600 (0x054A00 | 0x03) ++#define MAX3107_BRG13_B1200 (0x02A500 | 0x01) ++#define MAX3107_BRG13_B2400 (0x015200 | 0x09) ++#define MAX3107_BRG13_B4800 (0x00A900 | 0x04) ++#define MAX3107_BRG13_B9600 (0x005400 | 0x0A) ++#define MAX3107_BRG13_B19200 (0x002A00 | 0x05) ++#define MAX3107_BRG13_B38400 (0x001500 | 0x03) ++#define MAX3107_BRG13_B57600 (0x000E00 | 0x02) ++#define MAX3107_BRG13_B115200 (0x000700 | 0x01) ++#define MAX3107_BRG13_B230400 (0x000300 | 0x08) ++#define MAX3107_BRG13_B460800 (0x000100 | 0x0c) ++#define MAX3107_BRG13_B921600 (0x000100 | 0x1c) ++ ++/* Baud rate generator configuration values for external clock 26MHz */ ++#define MAX3107_BRG26_B300 (0x152800 | 0x0A) ++#define MAX3107_BRG26_B600 (0x0A9400 | 0x05) ++#define MAX3107_BRG26_B1200 (0x054A00 | 0x03) ++#define MAX3107_BRG26_B2400 (0x02A500 | 0x01) ++#define MAX3107_BRG26_B4800 (0x015200 | 0x09) ++#define MAX3107_BRG26_B9600 (0x00A900 | 0x04) ++#define MAX3107_BRG26_B19200 (0x005400 | 0x0A) ++#define MAX3107_BRG26_B38400 (0x002A00 | 0x05) ++#define MAX3107_BRG26_B57600 (0x001C00 | 0x03) ++#define MAX3107_BRG26_B115200 (0x000E00 | 0x02) ++#define MAX3107_BRG26_B230400 (0x000700 | 0x01) ++#define MAX3107_BRG26_B460800 (0x000300 | 0x08) ++#define MAX3107_BRG26_B921600 (0x000100 | 0x0C) ++ ++/* Baud rate generator configuration values for internal clock */ ++#define MAX3107_BRG13_IB300 (0x008000 | 0x00) ++#define MAX3107_BRG13_IB600 (0x004000 | 0x00) ++#define MAX3107_BRG13_IB1200 (0x002000 | 0x00) ++#define MAX3107_BRG13_IB2400 (0x001000 | 0x00) ++#define MAX3107_BRG13_IB4800 (0x000800 | 0x00) ++#define MAX3107_BRG13_IB9600 (0x000400 | 0x00) ++#define MAX3107_BRG13_IB19200 (0x000200 | 0x00) ++#define MAX3107_BRG13_IB38400 (0x000100 | 0x00) ++#define MAX3107_BRG13_IB57600 (0x000000 | 0x0B) ++#define MAX3107_BRG13_IB115200 (0x000000 | 0x05) ++#define MAX3107_BRG13_IB230400 (0x000000 | 0x03) ++#define MAX3107_BRG13_IB460800 (0x000000 | 0x00) ++#define MAX3107_BRG13_IB921600 (0x000000 | 0x00) ++ ++#endif /* _LINUX_SERIAL_MAX3107_H */ diff --git a/tty/tty_io-remove-casts-from-void.patch b/tty/tty_io-remove-casts-from-void.patch new file mode 100644 index 00000000000000..2fcdfdca6d2581 --- /dev/null +++ b/tty/tty_io-remove-casts-from-void.patch @@ -0,0 +1,73 @@ +From segooon@gmail.com Thu Jul 8 11:39:12 2010 +From: Kulikov Vasiliy <segooon@gmail.com> +Date: Tue, 29 Jun 2010 14:15:09 +0400 +Subject: tty_io: remove casts from void* +Cc: Greg Kroah-Hartman <gregkh@suse.de>, Alan Cox <alan@linux.intel.com>, "Eric W. Biederman" <ebiederm@xmission.com>, Dave Young <hidave.darkstar@gmail.com>, Jiri Kosina <jkosina@suse.cz>, linux-kernel@vger.kernel.org +Message-ID: <1277806510-30840-1-git-send-email-segooon@gmail.com> + + +Remove unnesessary casts from void*. + +Signed-off-by: Kulikov Vasiliy <segooon@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/char/tty_io.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/char/tty_io.c ++++ b/drivers/char/tty_io.c +@@ -893,7 +893,7 @@ static ssize_t tty_read(struct file *fil + struct inode *inode; + struct tty_ldisc *ld; + +- tty = (struct tty_struct *)file->private_data; ++ tty = file->private_data; + inode = file->f_path.dentry->d_inode; + if (tty_paranoia_check(tty, inode, "tty_read")) + return -EIO; +@@ -1070,7 +1070,7 @@ static ssize_t tty_write(struct file *fi + ssize_t ret; + struct tty_ldisc *ld; + +- tty = (struct tty_struct *)file->private_data; ++ tty = file->private_data; + if (tty_paranoia_check(tty, inode, "tty_write")) + return -EIO; + if (!tty || !tty->ops->write || +@@ -1513,7 +1513,7 @@ int tty_release(struct inode *inode, str + int idx; + char buf[64]; + +- tty = (struct tty_struct *)filp->private_data; ++ tty = filp->private_data; + if (tty_paranoia_check(tty, inode, "tty_release_dev")) + return 0; + +@@ -1920,7 +1920,7 @@ static unsigned int tty_poll(struct file + struct tty_ldisc *ld; + int ret = 0; + +- tty = (struct tty_struct *)filp->private_data; ++ tty = filp->private_data; + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) + return 0; + +@@ -1937,7 +1937,7 @@ static int __tty_fasync(int fd, struct f + unsigned long flags; + int retval = 0; + +- tty = (struct tty_struct *)filp->private_data; ++ tty = filp->private_data; + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) + goto out; + +@@ -2497,7 +2497,7 @@ long tty_ioctl(struct file *file, unsign + struct tty_ldisc *ld; + struct inode *inode = file->f_dentry->d_inode; + +- tty = (struct tty_struct *)file->private_data; ++ tty = file->private_data; + if (tty_paranoia_check(tty, inode, "tty_ioctl")) + return -EINVAL; + diff --git a/usb/usb-core-hcd-pci-use-for_each_pci_dev.patch b/usb/usb-core-hcd-pci-use-for_each_pci_dev.patch new file mode 100644 index 00000000000000..a7dc30a68feb09 --- /dev/null +++ b/usb/usb-core-hcd-pci-use-for_each_pci_dev.patch @@ -0,0 +1,33 @@ +From segooon@gmail.com Thu Jul 8 11:37:17 2010 +From: Kulikov Vasiliy <segooon@gmail.com> +Date: Sat, 3 Jul 2010 20:04:47 +0400 +Subject: USB: core: hcd-pci: use for_each_pci_dev() +To: Kernel Janitors <kernel-janitors@vger.kernel.org> +Cc: Greg Kroah-Hartman <gregkh@suse.de>, Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, Alexey Dobriyan <adobriyan@gmail.com>, "Rafael J. Wysocki" <rjw@sisk.pl>, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org +Message-ID: <1278173088-12051-1-git-send-email-segooon@gmail.com> + + +Use for_each_pci_dev() to simplify the code. + +Signed-off-by: Kulikov Vasiliy <segooon@gmail.com> +Acked-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/hcd-pci.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/usb/core/hcd-pci.c ++++ b/drivers/usb/core/hcd-pci.c +@@ -66,10 +66,7 @@ static void companion_common(struct pci_ + * vice versa. + */ + companion = NULL; +- for (;;) { +- companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion); +- if (!companion) +- break; ++ for_each_pci_dev(companion) { + if (companion->bus != pdev->bus || + PCI_SLOT(companion->devfn) != slot) + continue; diff --git a/usb/usb-ehci_omap-fix-device-detect-issue-with-modules.patch b/usb/usb-ehci_omap-fix-device-detect-issue-with-modules.patch new file mode 100644 index 00000000000000..17ebcb359d0ae2 --- /dev/null +++ b/usb/usb-ehci_omap-fix-device-detect-issue-with-modules.patch @@ -0,0 +1,83 @@ +From ajay.gupta@ti.com Thu Jul 8 11:40:51 2010 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Thu, 8 Jul 2010 14:03:02 +0530 +Subject: USB: ehci_omap: fix device detect issue with modules +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278577982-30046-5-git-send-email-ajay.gupta@ti.com> + + +Currently devices don't get detected automatically if the ehci +module is inserted 2nd time onward. We need to disconnect and +reconnect the device for it to get detected and enumerated. + +Resetting the USB PHY using PHY reset comamnd over ULPI fixes +this issue. Tested on OMAP3EVM. + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ehci-omap.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/usb/host/ehci-omap.c ++++ b/drivers/usb/host/ehci-omap.c +@@ -38,6 +38,7 @@ + #include <linux/gpio.h> + #include <linux/regulator/consumer.h> + #include <linux/slab.h> ++#include <linux/usb/ulpi.h> + #include <plat/usb.h> + + /* +@@ -236,6 +237,35 @@ static void omap_usb_utmi_init(struct eh + + /*-------------------------------------------------------------------------*/ + ++static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) ++{ ++ unsigned long timeout = jiffies + msecs_to_jiffies(1000); ++ unsigned reg = 0; ++ ++ reg = ULPI_FUNC_CTRL_RESET ++ /* FUNCTION_CTRL_SET register */ ++ | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT) ++ /* Write */ ++ | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) ++ /* PORTn */ ++ | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) ++ /* start ULPI access*/ ++ | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); ++ ++ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, reg); ++ ++ /* Wait for ULPI access completion */ ++ while ((ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) ++ & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { ++ cpu_relax(); ++ ++ if (time_after(jiffies, timeout)) { ++ dev_dbg(omap->dev, "phy reset operation timed out\n"); ++ break; ++ } ++ } ++} ++ + /* omap_start_ehc + * - Start the TI USBHOST controller + */ +@@ -425,6 +455,12 @@ static int omap_start_ehc(struct ehci_hc + gpio_set_value(omap->reset_gpio_port[1], 1); + } + ++ /* Soft reset the PHY using PHY reset command over ULPI */ ++ if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ++ omap_ehci_soft_phy_reset(omap, 0); ++ if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ++ omap_ehci_soft_phy_reset(omap, 1); ++ + return 0; + + err_sys_status: diff --git a/usb/usb-gadget-compilation-issue-missing-task_interruptible.patch b/usb/usb-gadget-compilation-issue-missing-task_interruptible.patch new file mode 100644 index 00000000000000..9642be9f5ac8a9 --- /dev/null +++ b/usb/usb-gadget-compilation-issue-missing-task_interruptible.patch @@ -0,0 +1,44 @@ +From stephane.duverger@gmail.com Thu Jul 8 11:23:40 2010 +From: stephane duverger <stephane.duverger@gmail.com> +Date: Tue, 29 Jun 2010 16:57:25 +0200 +Subject: USB: gadget: compilation issue: missing TASK_INTERRUPTIBLE +To: Greg KH <greg@kroah.com> +Cc: dbrownell@users.sourceforge.net, linux-usb@vger.kernel.org +Message-ID: <20100629165725.24e64a2b@riot.ssi.corp> + + +Here is the patch for the following issue: + +drivers/usb/gadget/u_serial.c: In function ‘gs_start_tx’: +drivers/usb/gadget/u_serial.c:369: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function) +drivers/usb/gadget/u_serial.c:369: error: (Each undeclared identifier is reported only once +drivers/usb/gadget/u_serial.c:369: error: for each function it appears in.) +drivers/usb/gadget/u_serial.c: In function ‘gs_rx_push’: +drivers/usb/gadget/u_serial.c:546: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function) +drivers/usb/gadget/u_serial.c: In function ‘gs_close’: +drivers/usb/gadget/u_serial.c:857: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function) +drivers/usb/gadget/u_serial.c:857: error: implicit declaration of function ‘signal_pending’ +drivers/usb/gadget/u_serial.c:857: error: implicit declaration of function ‘schedule_timeout’ +drivers/usb/gadget/u_serial.c: In function ‘gserial_cleanup’: +drivers/usb/gadget/u_serial.c:1190: error: ‘TASK_UNINTERRUPTIBLE’ undeclared (first use in this function) +drivers/usb/gadget/u_serial.c:1190: error: implicit declaration of function ‘schedule’ +drivers/usb/gadget/u_serial.c: In function ‘gserial_disconnect’: +drivers/usb/gadget/u_serial.c:1311: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function) + +Signed-off-by: Stephane Duverger <stephane.duverger@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/u_serial.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/gadget/u_serial.c ++++ b/drivers/usb/gadget/u_serial.c +@@ -18,6 +18,7 @@ + /* #define VERBOSE_DEBUG */ + + #include <linux/kernel.h> ++#include <linux/sched.h> + #include <linux/interrupt.h> + #include <linux/device.h> + #include <linux/delay.h> diff --git a/usb/usb-gadget-storage_common-comments-updated.patch b/usb/usb-gadget-storage_common-comments-updated.patch new file mode 100644 index 00000000000000..7b0740432d7427 --- /dev/null +++ b/usb/usb-gadget-storage_common-comments-updated.patch @@ -0,0 +1,159 @@ +From m.nazarewicz@samsung.com Thu Jul 8 11:30:03 2010 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Mon, 05 Jul 2010 16:38:04 +0200 +Subject: USB: gadget: storage_common: comments updated +To: linux-usb@vger.kernel.org +Cc: Sergei Shtylyov <sshtylyov@mvista.com>, Greg KH <greg@kroah.com>, linux-kernel@vger.kernel.org +Message-ID: <dd71cb106d8ded3a1d204102ffbe67f089fff923.1278324780.git.m.nazarewicz@samsung.com> + + +Updated comment to describe why printing macros are needed even +thought they are copied form the composite.h. Also, made multiline +comments follow the coding standard. + +Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/storage_common.c | 69 +++++++++++++++++++++++++----------- + 1 file changed, 48 insertions(+), 21 deletions(-) + +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -57,10 +57,12 @@ + #include <asm/unaligned.h> + + +-/* Thanks to NetChip Technologies for donating this product ID. ++/* ++ * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! +- * Instead: allocate your own, using normal USB-IF procedures. */ ++ * Instead: allocate your own, using normal USB-IF procedures. ++ */ + #define FSG_VENDOR_ID 0x0525 /* NetChip */ + #define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + +@@ -84,14 +86,27 @@ + #define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) + #define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) + +-/* Keep those macros in sync with thos in +- * include/linux/ubs/composite.h or else GCC will complain. If they ++/* ++ * Keep those macros in sync with those in ++ * include/linux/usb/composite.h or else GCC will complain. If they + * are identical (the same names of arguments, white spaces in the + * same places) GCC will allow redefinition otherwise (even if some +- * white space is removed or added) warning will be issued. No +- * checking if those symbols is defined is performed because warning +- * is desired when those macros were defined by someone else to mean +- * something else. */ ++ * white space is removed or added) warning will be issued. ++ * ++ * Those macros are needed here because File Storage Gadget does not ++ * include the composite.h header. For composite gadgets those macros ++ * are redundant since composite.h is included any way. ++ * ++ * One could check whether those macros are already defined (which ++ * would indicate composite.h had been included) or not (which would ++ * indicate we were in FSG) but this is not done because a warning is ++ * desired if definitions here differ from the ones in composite.h. ++ * ++ * We want the definitions to match and be the same in File Storage ++ * Gadget as well as Mass Storage Function (and so composite gadgets ++ * using MSF). If someone changes them in composite.h it will produce ++ * a warning in this file when building MSF. ++ */ + #define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) + #define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) + #define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) +@@ -313,9 +328,11 @@ struct fsg_buffhd { + enum fsg_buffer_state state; + struct fsg_buffhd *next; + +- /* The NetChip 2280 is faster, and handles some protocol faults ++ /* ++ * The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. +- * So we will record the intended request length here. */ ++ * So we will record the intended request length here. ++ */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; +@@ -395,8 +412,10 @@ fsg_intf_desc = { + .iInterface = FSG_STRING_INTERFACE, + }; + +-/* Three full-speed endpoint descriptors: bulk-in, bulk-out, +- * and interrupt-in. */ ++/* ++ * Three full-speed endpoint descriptors: bulk-in, bulk-out, and ++ * interrupt-in. ++ */ + + static struct usb_endpoint_descriptor + fsg_fs_bulk_in_desc = { +@@ -459,7 +478,7 @@ static struct usb_descriptor_header *fsg + * + * That means alternate endpoint descriptors (bigger packets) + * and a "device qualifier" ... plus more construction options +- * for the config descriptor. ++ * for the configuration descriptor. + */ + static struct usb_endpoint_descriptor + fsg_hs_bulk_in_desc = { +@@ -547,8 +566,10 @@ static struct usb_gadget_strings fsg_str + + /*-------------------------------------------------------------------------*/ + +-/* If the next two routines are called while the gadget is registered, +- * the caller must own fsg->filesem for writing. */ ++/* ++ * If the next two routines are called while the gadget is registered, ++ * the caller must own fsg->filesem for writing. ++ */ + + static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) + { +@@ -587,8 +608,10 @@ static int fsg_lun_open(struct fsg_lun * + goto out; + } + +- /* If we can't read the file, it's no good. +- * If we can't write the file, use it read-only. */ ++ /* ++ * If we can't read the file, it's no good. ++ * If we can't write the file, use it read-only. ++ */ + if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { + LINFO(curlun, "file not readable: %s\n", filename); + goto out; +@@ -646,8 +669,10 @@ static void fsg_lun_close(struct fsg_lun + + /*-------------------------------------------------------------------------*/ + +-/* Sync the file data, don't bother with the metadata. +- * This code was copied from fs/buffer.c:sys_fdatasync(). */ ++/* ++ * Sync the file data, don't bother with the metadata. ++ * This code was copied from fs/buffer.c:sys_fdatasync(). ++ */ + static int fsg_lun_fsync_sub(struct fsg_lun *curlun) + { + struct file *filp = curlun->filp; +@@ -728,8 +753,10 @@ static ssize_t fsg_store_ro(struct devic + if (sscanf(buf, "%d", &i) != 1) + return -EINVAL; + +- /* Allow the write-enable status to change only while the backing file +- * is closed. */ ++ /* ++ * Allow the write-enable status to change only while the ++ * backing file is closed. ++ */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); diff --git a/usb/usb-musb-do-not-override-dma-mode-in-channel-program.patch b/usb/usb-musb-do-not-override-dma-mode-in-channel-program.patch new file mode 100644 index 00000000000000..3da3fdbbe3866b --- /dev/null +++ b/usb/usb-musb-do-not-override-dma-mode-in-channel-program.patch @@ -0,0 +1,39 @@ +From ajay.gupta@ti.com Thu Jul 8 11:41:23 2010 +From: Anand Gadiyar <gadiyar@ti.com> +Date: Thu, 8 Jul 2010 16:34:55 +0530 +Subject: USB: musb: do not override DMA mode in channel program +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Anand Gadiyar <gadiyar@ti.com>, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278587095-16978-3-git-send-email-ajay.gupta@ti.com> + + +From: Anand Gadiyar <gadiyar@ti.com> + +There is no reason for the DMA channel program to override the +DMA mode passed down by its caller. Use the passed parameter +directly, and let the caller handle the decision on which mode +is to be used. + +Signed-off-by: Anand Gadiyar <gadiyar@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musbhsdma.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/usb/musb/musbhsdma.c ++++ b/drivers/usb/musb/musbhsdma.c +@@ -173,10 +173,7 @@ static int dma_channel_program(struct dm + musb_channel->max_packet_sz = packet_sz; + channel->status = MUSB_DMA_STATUS_BUSY; + +- if ((mode == 1) && (len >= packet_sz)) +- configure_channel(channel, packet_sz, 1, dma_addr, len); +- else +- configure_channel(channel, packet_sz, 0, dma_addr, len); ++ configure_channel(channel, packet_sz, mode, dma_addr, len); + + return true; + } diff --git a/usb/usb-musb-fix-compilation-warning-in-host-only-mode.patch b/usb/usb-musb-fix-compilation-warning-in-host-only-mode.patch new file mode 100644 index 00000000000000..c8852ebce1f389 --- /dev/null +++ b/usb/usb-musb-fix-compilation-warning-in-host-only-mode.patch @@ -0,0 +1,45 @@ +From ajay.gupta@ti.com Thu Jul 8 11:40:30 2010 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Thu, 8 Jul 2010 14:03:00 +0530 +Subject: USB: musb: fix compilation warning in host only mode +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278577982-30046-3-git-send-email-ajay.gupta@ti.com> + + +Fixes below compilation warning when host only configuration is +selected. +drivers/usb/musb/musb_core.c: In function 'musb_stage0_irq': +drivers/usb/musb/musb_core.c:711: warning: unused variable 'mbase' + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_core.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -704,7 +704,6 @@ static irqreturn_t musb_stage0_irq(struc + #ifdef CONFIG_USB_MUSB_HDRC_HCD + if (int_usb & MUSB_INTR_CONNECT) { + struct usb_hcd *hcd = musb_to_hcd(musb); +- void __iomem *mbase = musb->mregs; + + handled = IRQ_HANDLED; + musb->is_active = 1; +@@ -717,9 +716,9 @@ static irqreturn_t musb_stage0_irq(struc + if (is_peripheral_active(musb)) { + /* REVISIT HNP; just force disconnect */ + } +- musb_writew(mbase, MUSB_INTRTXE, musb->epmask); +- musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe); +- musb_writeb(mbase, MUSB_INTRUSBE, 0xf7); ++ musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); ++ musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); ++ musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); + #endif + musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED + |USB_PORT_STAT_HIGH_SPEED diff --git a/usb/usb-musb-kill-board-specific-pinmux-from-driver-file.patch b/usb/usb-musb-kill-board-specific-pinmux-from-driver-file.patch new file mode 100644 index 00000000000000..17a0d08f23a597 --- /dev/null +++ b/usb/usb-musb-kill-board-specific-pinmux-from-driver-file.patch @@ -0,0 +1,48 @@ +From ajay.gupta@ti.com Thu Jul 8 11:41:07 2010 +From: Anand Gadiyar <gadiyar@ti.com> +Date: Thu, 8 Jul 2010 16:34:54 +0530 +Subject: USB: musb: Kill board specific pinmux from driver file +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Anand Gadiyar <gadiyar@ti.com>, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278587095-16978-2-git-send-email-ajay.gupta@ti.com> + + +From: Anand Gadiyar <gadiyar@ti.com> + +This pin-muxing is best done in the board files. The driver should +not do this explicitly. + +Also, this code causes a warning to be thrown when OMAP2430 and OMAP3/4 +support are enabled in the same kernel. + +Signed-off-by: Anand Gadiyar <gadiyar@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/omap2430.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/drivers/usb/musb/omap2430.c ++++ b/drivers/usb/musb/omap2430.c +@@ -32,8 +32,6 @@ + #include <linux/clk.h> + #include <linux/io.h> + +-#include <plat/mux.h> +- + #include "musb_core.h" + #include "omap2430.h" + +@@ -194,10 +192,6 @@ int __init musb_platform_init(struct mus + u32 l; + struct omap_musb_board_data *data = board_data; + +-#if defined(CONFIG_ARCH_OMAP2430) +- omap_cfg_reg(AE5_2430_USB0HS_STP); +-#endif +- + /* We require some kind of external transceiver, hooked + * up through ULPI. TWL4030-family PMICs include one, + * which needs a driver, drivers aren't always needed. diff --git a/usb/usb-musb-use-correct-register-widths-in-register-dumps.patch b/usb/usb-musb-use-correct-register-widths-in-register-dumps.patch new file mode 100644 index 00000000000000..02e487f9f4454a --- /dev/null +++ b/usb/usb-musb-use-correct-register-widths-in-register-dumps.patch @@ -0,0 +1,72 @@ +From ajay.gupta@ti.com Thu Jul 8 11:40:11 2010 +From: Anand Gadiyar <gadiyar@ti.com> +Date: Thu, 8 Jul 2010 14:02:59 +0530 +Subject: USB: musb: use correct register widths in register dumps +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Anand Gadiyar <gadiyar@ti.com>, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278577982-30046-2-git-send-email-ajay.gupta@ti.com> + +From: Anand Gadiyar <gadiyar@ti.com> + +DMA_ADDR and DMA_COUNT are 32-bit registers, not 16-bit. + +Marking them as 16-bit in the table causes only the lower +16-bits to be dumped and this is misleading. + +Signed-off-by: Anand Gadiyar <gadiyar@ti.com> +Acked-by: Felipe Balbi <felipe.balbi@nokia.com> +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/musb_debugfs.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +--- a/drivers/usb/musb/musb_debugfs.c ++++ b/drivers/usb/musb/musb_debugfs.c +@@ -92,29 +92,29 @@ static const struct musb_register_map mu + { "LS_EOF1", 0x7E, 8 }, + { "SOFT_RST", 0x7F, 8 }, + { "DMA_CNTLch0", 0x204, 16 }, +- { "DMA_ADDRch0", 0x208, 16 }, +- { "DMA_COUNTch0", 0x20C, 16 }, ++ { "DMA_ADDRch0", 0x208, 32 }, ++ { "DMA_COUNTch0", 0x20C, 32 }, + { "DMA_CNTLch1", 0x214, 16 }, +- { "DMA_ADDRch1", 0x218, 16 }, +- { "DMA_COUNTch1", 0x21C, 16 }, ++ { "DMA_ADDRch1", 0x218, 32 }, ++ { "DMA_COUNTch1", 0x21C, 32 }, + { "DMA_CNTLch2", 0x224, 16 }, +- { "DMA_ADDRch2", 0x228, 16 }, +- { "DMA_COUNTch2", 0x22C, 16 }, ++ { "DMA_ADDRch2", 0x228, 32 }, ++ { "DMA_COUNTch2", 0x22C, 32 }, + { "DMA_CNTLch3", 0x234, 16 }, +- { "DMA_ADDRch3", 0x238, 16 }, +- { "DMA_COUNTch3", 0x23C, 16 }, ++ { "DMA_ADDRch3", 0x238, 32 }, ++ { "DMA_COUNTch3", 0x23C, 32 }, + { "DMA_CNTLch4", 0x244, 16 }, +- { "DMA_ADDRch4", 0x248, 16 }, +- { "DMA_COUNTch4", 0x24C, 16 }, ++ { "DMA_ADDRch4", 0x248, 32 }, ++ { "DMA_COUNTch4", 0x24C, 32 }, + { "DMA_CNTLch5", 0x254, 16 }, +- { "DMA_ADDRch5", 0x258, 16 }, +- { "DMA_COUNTch5", 0x25C, 16 }, ++ { "DMA_ADDRch5", 0x258, 32 }, ++ { "DMA_COUNTch5", 0x25C, 32 }, + { "DMA_CNTLch6", 0x264, 16 }, +- { "DMA_ADDRch6", 0x268, 16 }, +- { "DMA_COUNTch6", 0x26C, 16 }, ++ { "DMA_ADDRch6", 0x268, 32 }, ++ { "DMA_COUNTch6", 0x26C, 32 }, + { "DMA_CNTLch7", 0x274, 16 }, +- { "DMA_ADDRch7", 0x278, 16 }, +- { "DMA_COUNTch7", 0x27C, 16 }, ++ { "DMA_ADDRch7", 0x278, 32 }, ++ { "DMA_COUNTch7", 0x27C, 32 }, + { } /* Terminating Entry */ + }; + diff --git a/usb/usb-serial-io_ti-don-t-return-0-if-writing-the-download-record-failed.patch b/usb/usb-serial-io_ti-don-t-return-0-if-writing-the-download-record-failed.patch new file mode 100644 index 00000000000000..8e3bf339ddbb82 --- /dev/null +++ b/usb/usb-serial-io_ti-don-t-return-0-if-writing-the-download-record-failed.patch @@ -0,0 +1,28 @@ +From roel.kluin@gmail.com Thu Jul 8 11:35:42 2010 +From: Roel Kluin <roel.kluin@gmail.com> +Date: Fri, 02 Jul 2010 00:36:43 +0200 +Subject: USB: serial: io_ti: Don't return 0 if writing the download record failed +To: Greg Kroah-Hartman <gregkh@suse.de>, linux-usb@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>, LKML <linux-kernel@vger.kernel.org> +Message-ID: <4C2D187B.4020109@gmail.com> + + +If the write download record failed we shouldn't return 0. + +Signed-off-by: Roel Kluin <roel.kluin@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/io_ti.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -1321,7 +1321,7 @@ static int download_fw(struct edgeport_s + kfree(header); + kfree(rom_desc); + kfree(ti_manuf_desc); +- return status; ++ return -EINVAL; + } + + kfree(vheader); diff --git a/usb/usb-ulpi-fix-compilation-warning.patch b/usb/usb-ulpi-fix-compilation-warning.patch new file mode 100644 index 00000000000000..7cc79693b3c6bb --- /dev/null +++ b/usb/usb-ulpi-fix-compilation-warning.patch @@ -0,0 +1,34 @@ +From ajay.gupta@ti.com Thu Jul 8 11:40:41 2010 +From: Ajay Kumar Gupta <ajay.gupta@ti.com> +Date: Thu, 8 Jul 2010 14:03:01 +0530 +Subject: USB: ulpi: fix compilation warning +To: linux-usb@vger.kernel.org +Cc: linux-omap@vger.kernel.org, felipe.balbi@nokia.com, gregkh@suse.de, Ajay Kumar Gupta <ajay.gupta@ti.com> +Message-ID: <1278577982-30046-4-git-send-email-ajay.gupta@ti.com> + + +Fixes below compilation warning from ulpi.h + +include/linux/usb/ulpi.h:145: + warning: 'struct otg_io_access_ops' declared inside parameter list +include/linux/usb/ulpi.h:145: + warning: its scope is only this definition or declaration, + which is probably not what you want + +Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + include/linux/usb/ulpi.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/usb/ulpi.h ++++ b/include/linux/usb/ulpi.h +@@ -11,6 +11,7 @@ + #ifndef __LINUX_USB_ULPI_H + #define __LINUX_USB_ULPI_H + ++#include <linux/usb/otg.h> + /*-------------------------------------------------------------------------*/ + + /* |
