Re: [PATCH] usb:serial: Add Fintek F81532/534 driver
Hi, Ji-Ze Hong (Peter Hong) 於 2016/5/31 上午 09:33 寫道: This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Sorry, I forgot to change the mail title for "PATCH V9". I'll resend a patch with title "PATCH V9". Thanks -- With Best Regards, Peter Hung
Re: [PATCH] usb:serial: Add Fintek F81532/534 driver
Hi, Ji-Ze Hong (Peter Hong) 於 2016/5/31 上午 09:33 寫道: This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Sorry, I forgot to change the mail title for "PATCH V9". I'll resend a patch with title "PATCH V9". Thanks -- With Best Regards, Peter Hung
Re: [PATCH V4 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Andy, Andy Shevchenko 於 2016/2/23 下午 07:05 寫道: On Tue, 2016-02-23 at 14:30 +0800, Peter Hung wrote: +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 SERIAL_8250_PCI ? In my opinion, 8250_pci & f81504_core are independently drivers. So I'll set the default to SERIAL_8250. +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* Find every port to check is multi-function port */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio mode. +* So we'll not configure it as serial port. +*/ + return true; Perhaps if (fintek_gpio_mapping[i] == idx && (gpio_en & BIT(i))) return true; Your code is more simple and readable. I'll change it for V5 Thanks for your advices. -- With Best Regards, Peter Hung
Re: [PATCH V4 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Andy, Andy Shevchenko 於 2016/2/23 下午 07:05 寫道: On Tue, 2016-02-23 at 14:30 +0800, Peter Hung wrote: +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 SERIAL_8250_PCI ? In my opinion, 8250_pci & f81504_core are independently drivers. So I'll set the default to SERIAL_8250. +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* Find every port to check is multi-function port */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio mode. +* So we'll not configure it as serial port. +*/ + return true; Perhaps if (fintek_gpio_mapping[i] == idx && (gpio_en & BIT(i))) return true; Your code is more simple and readable. I'll change it for V5 Thanks for your advices. -- With Best Regards, Peter Hung
[PATCH V4 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c and add it to blacklist 8250_pci.c will still handle the device when patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Changelog: V4: 1. Fix the comment style 2. Fix the warning (.owner = THIS_MODULE) reported by kbuild bot with f81504_core.c & 8250_f81504.c 3. Remove unused Kconfig option (RATIONAL) with 8250_f81504.c 4. Remove unused variable (quot/rem) with f81504_check_baudrate() in 8250_f81504.c V3: 1. Refactoring gpio-f81504.c with new API (Suggested by Linus Walleij). 2. Fix wrong kfree in gpio-f81504.c (Suggested by Andy Shevchenko). 3. Get PCI resource by pci_resource_start() instead of getting PCI resource from BAR of PCI configuration space (Suggested by Alan). V2: 1. Split F81504/508/512 from 8250_pci.c to MFD, It'll add 3 new files 1. drivers/mfd/f81504-core.c 2. drivers/gpio/gpio-f81504.c 3. drivers/tty/serial/8250/8250_f81504.c V1: 1. Split F81504/508/512 from 8250_pci.c to 8250_fintek_pci.c. Alan & Andy recommend me to rewrite as MFD architecture. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 241 drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 335 ++ drivers/tty/serial/8250/8250_f81504.c | 250 + drivers/tty/serial/8250/8250_pci.c| 206 + drivers/tty/serial/8250/Kconfig | 10 + drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 919 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
[PATCH V4 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c and add it to blacklist 8250_pci.c will still handle the device when patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Changelog: V4: 1. Fix the comment style 2. Fix the warning (.owner = THIS_MODULE) reported by kbuild bot with f81504_core.c & 8250_f81504.c 3. Remove unused Kconfig option (RATIONAL) with 8250_f81504.c 4. Remove unused variable (quot/rem) with f81504_check_baudrate() in 8250_f81504.c V3: 1. Refactoring gpio-f81504.c with new API (Suggested by Linus Walleij). 2. Fix wrong kfree in gpio-f81504.c (Suggested by Andy Shevchenko). 3. Get PCI resource by pci_resource_start() instead of getting PCI resource from BAR of PCI configuration space (Suggested by Alan). V2: 1. Split F81504/508/512 from 8250_pci.c to MFD, It'll add 3 new files 1. drivers/mfd/f81504-core.c 2. drivers/gpio/gpio-f81504.c 3. drivers/tty/serial/8250/8250_f81504.c V1: 1. Split F81504/508/512 from 8250_pci.c to 8250_fintek_pci.c. Alan & Andy recommend me to rewrite as MFD architecture. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 241 drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 335 ++ drivers/tty/serial/8250/8250_f81504.c | 250 + drivers/tty/serial/8250/8250_pci.c| 206 + drivers/tty/serial/8250/Kconfig | 10 + drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 919 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
[PATCH V4 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_f81504.c | 250 ++ drivers/tty/serial/8250/Kconfig | 10 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 261 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..2b6c3d3 --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18_46_MHZ, + F81504_CLKSEL_14_77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must larger than desire baud rate */ + if (baud > baudrate_table[index]) + continue; + + /* Find divisible clock source */ + if (!(baudrate_table[index] % baud)) { + if (idx) + *idx = index; + return 0; + } + } + + return -EINVAL; +} + +static void f81504_set_termios(struct uart_port *port, + struct kterm
[PATCH V4 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 241 + 3 files changed, 252 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2b80903..c9e1cf8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -912,6 +912,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c759190..f277089 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..25a535c --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct f81504_gpio_chip *gc = gpiochip_get_data(chip); + struct platform_device *pdev = to_platform_device(chip->parent); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + u8 tmp; + + mutex_lock(>locker); + + /* Set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * +F81504_GPIO_SET_OFFSET + +F81504_GPIO_OUT_EN_OFFSET, ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + + F81504_GPIO_OUT_EN_OFFSET, tmp & ~BIT(offset)); + + mutex_unlock(>locker); + return 0; +} + +sta
[PATCH V4 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support and Andy recommend me to add these this in blacklist to avoid probed by 8250_pci.c Suggested-by: Paul Gortmaker <paul.gortma...@windriver.com> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_pci.c | 206 + 1 file changed, 5 insertions(+), 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e71ec78..24a669c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,156 +1532,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i <
[PATCH V4 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_f81504.c | 250 ++ drivers/tty/serial/8250/Kconfig | 10 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 261 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..2b6c3d3 --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18_46_MHZ, + F81504_CLKSEL_14_77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must larger than desire baud rate */ + if (baud > baudrate_table[index]) + continue; + + /* Find divisible clock source */ + if (!(baudrate_table[index] % baud)) { + if (idx) + *idx = index; + return 0; + } + } + + return -EINVAL; +} + +static void f81504_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct platform_device *pdev = container_of(port->dev, + st
[PATCH V4 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 241 + 3 files changed, 252 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2b80903..c9e1cf8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -912,6 +912,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c759190..f277089 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..25a535c --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct f81504_gpio_chip *gc = gpiochip_get_data(chip); + struct platform_device *pdev = to_platform_device(chip->parent); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + u8 tmp; + + mutex_lock(>locker); + + /* Set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * +F81504_GPIO_SET_OFFSET + +F81504_GPIO_OUT_EN_OFFSET, ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + + F81504_GPIO_OUT_EN_OFFSET, tmp & ~BIT(offset)); + + mutex_unlock(>locker); + return 0; +} + +static int f81504_gpio_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ +
[PATCH V4 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support and Andy recommend me to add these this in blacklist to avoid probed by 8250_pci.c Suggested-by: Paul Gortmaker Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 206 + 1 file changed, 5 insertions(+), 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e71ec78..24a669c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,156 +1532,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i < max_port; ++i) { - /* UART0 configuration offset start from 0x40 */ - config_base
[PATCH V4 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/mfd/Kconfig| 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 335 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 401 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aa21dc5..775761f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -345,6 +345,18 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 +help + This driver provides the F81504/508/512 UART & GPIO platform + devices. You should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial port support. + This driver needs to be built into the kernel to use early + console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eaa6465d..8e581ad 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..c192250 --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,335 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* Find every port to check is multi-function port */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio mode. +* So we'll not configure it as serial port. +*/ + return true; + } + + return false; +} + +static int f81504_port_init(struct pci_dev *pdev) +{ + struct f81504_pci_private *priv = pci_get_drvdata(pdev); + unsigned int i; + u32 gpio_addr; + u8 gpio_en, f0h_data, f3h_data; + u32 max_port, iobase; + u32 bar_data[3]; + u16 tmp; + u8 config_base; + + /* Init GPIO IO Address */ + gpio_addr = pci_resource_start(pdev, 2); + + /* +* Write GPIO IO Address LSB/MSB to corresponding register. Due to we +* can't write once with pci_write_config_word() on x86 platform, we'll +* write it with pci_write_conf
[PATCH V4 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/mfd/Kconfig| 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 335 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 401 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aa21dc5..775761f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -345,6 +345,18 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 +help + This driver provides the F81504/508/512 UART & GPIO platform + devices. You should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial port support. + This driver needs to be built into the kernel to use early + console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eaa6465d..8e581ad 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..c192250 --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,335 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* Find every port to check is multi-function port */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio mode. +* So we'll not configure it as serial port. +*/ + return true; + } + + return false; +} + +static int f81504_port_init(struct pci_dev *pdev) +{ + struct f81504_pci_private *priv = pci_get_drvdata(pdev); + unsigned int i; + u32 gpio_addr; + u8 gpio_en, f0h_data, f3h_data; + u32 max_port, iobase; + u32 bar_data[3]; + u16 tmp; + u8 config_base; + + /* Init GPIO IO Address */ + gpio_addr = pci_resource_start(pdev, 2); + + /* +* Write GPIO IO Address LSB/MSB to corresponding register. Due to we +* can't write once with pci_write_config_word() on x86 platform, we'll +* write it with pci_write_config_byte(). +*/ + pci_write_config_byte(pdev, F81504_GPIO_IO_LSB_REG, gpio_addr &
Re: [PATCH V3 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Linus, Linus Walleij 於 2016/2/16 下午 11:22 寫道: On Tue, Feb 16, 2016 at 7:55 AM, Peter Hung <hpe...@gmail.com> wrote: Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> Acked-by: Linus Walleij <linus.wall...@linaro.org> It's fine with me if this is queued in MFD, serial or whatever tree, or we can wait until the MFD parts are in and take it for the next merge window. Thanks for your review, but Andy give me some advice for 8250_f81504.c. So I'll send V4 when I rewrite it. -- With Best Regards, Peter Hung
Re: [PATCH V3 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Linus, Linus Walleij 於 2016/2/16 下午 11:22 寫道: On Tue, Feb 16, 2016 at 7:55 AM, Peter Hung wrote: Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung Acked-by: Linus Walleij It's fine with me if this is queued in MFD, serial or whatever tree, or we can wait until the MFD parts are in and take it for the next merge window. Thanks for your review, but Andy give me some advice for 8250_f81504.c. So I'll send V4 when I rewrite it. -- With Best Regards, Peter Hung
Re: [PATCH V3 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
Hi Andy, Andy Shevchenko 於 2016/2/16 下午 05:11 寫道: On Tue, 2016-02-16 at 14:55 +0800, Peter Hung wrote: +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; I suggest to replace DOT by _. ok +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; private_data is a type of void *, therefore no need to have an explicit casting. ok +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) Post-increment is also okay. { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); So, how quot is used and is it possible to set, for example, baud rate as 100 or 576000? The IC don't support B100 due to no 16MHz clock source. The quot & rem is only use for compare, and it's must be not 0 when the code run to calculate DIV_ROUND_CLOSEST. So quot is a redundancy here. This function will find the suitable clock source for future use. We'll pass suitable baud rate * 16 to port->uartclk for serial8250_do_set_termios() to do advance divider operations. I'll rewrite this section with remove quot and direct check the "baudrate_table[index] % baud" divisible. + u8 tmp, *offset = (u8 *) port->private_data; Same for provate_data as above. ok + /* +* direct use 1.8432MHz when baudrate smaller then or +* equal 115200bps Check your style of comments in a _whole_ your series. ok + /* +* If it can't found suitable clock source but had old +* accpetable baudrate, we'll use it Typo: acceptable. Baudrate -> baud rate. ok + port.port.private_data = data; /* save current idx */ Not sure you need to allocate memory for that at all, or maybe use a struct with one member (for now). We just pass the index of PCI configuration space currently. So I just set a allocated u8 memory to private data. We'll maintain current method. +static SIMPLE_DEV_PM_OPS(f81504_serial_pm_ops, f81504_serial_suspend, + f81504_serial_resume); + +static struct platform_driver f81504_serial_driver = { + .driver = { + .name = F81504_SERIAL_NAME, + .owner = THIS_MODULE, You perhaps don't need this. Check the rest of the modules. ok +config SERIAL_8250_F81504 +tristate "Fintek F81504/508/512 16550 PCIE device support" if EXPERT +depends on SERIAL_8250 && MFD_FINTEK_F81504_CORE +default SERIAL_8250 +select RATIONAL It seems RATIONAL API is not used here. This driver hadn't use RATIONAL API. I'll remove it. Thanks for your advice. -- With Best Regards, Peter Hung
Re: [PATCH V3 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
Hi Andy, Andy Shevchenko 於 2016/2/16 下午 05:11 寫道: On Tue, 2016-02-16 at 14:55 +0800, Peter Hung wrote: +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; I suggest to replace DOT by _. ok +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; private_data is a type of void *, therefore no need to have an explicit casting. ok +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) Post-increment is also okay. { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); So, how quot is used and is it possible to set, for example, baud rate as 100 or 576000? The IC don't support B100 due to no 16MHz clock source. The quot & rem is only use for compare, and it's must be not 0 when the code run to calculate DIV_ROUND_CLOSEST. So quot is a redundancy here. This function will find the suitable clock source for future use. We'll pass suitable baud rate * 16 to port->uartclk for serial8250_do_set_termios() to do advance divider operations. I'll rewrite this section with remove quot and direct check the "baudrate_table[index] % baud" divisible. + u8 tmp, *offset = (u8 *) port->private_data; Same for provate_data as above. ok + /* +* direct use 1.8432MHz when baudrate smaller then or +* equal 115200bps Check your style of comments in a _whole_ your series. ok + /* +* If it can't found suitable clock source but had old +* accpetable baudrate, we'll use it Typo: acceptable. Baudrate -> baud rate. ok + port.port.private_data = data; /* save current idx */ Not sure you need to allocate memory for that at all, or maybe use a struct with one member (for now). We just pass the index of PCI configuration space currently. So I just set a allocated u8 memory to private data. We'll maintain current method. +static SIMPLE_DEV_PM_OPS(f81504_serial_pm_ops, f81504_serial_suspend, + f81504_serial_resume); + +static struct platform_driver f81504_serial_driver = { + .driver = { + .name = F81504_SERIAL_NAME, + .owner = THIS_MODULE, You perhaps don't need this. Check the rest of the modules. ok +config SERIAL_8250_F81504 +tristate "Fintek F81504/508/512 16550 PCIE device support" if EXPERT +depends on SERIAL_8250 && MFD_FINTEK_F81504_CORE +default SERIAL_8250 +select RATIONAL It seems RATIONAL API is not used here. This driver hadn't use RATIONAL API. I'll remove it. Thanks for your advice. -- With Best Regards, Peter Hung
Re: [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Linus, Linus Walleij 於 2016/2/10 下午 05:08 寫道: On Thu, Jan 28, 2016 at 10:20 AM, Peter Hung <hpe...@gmail.com> wrote: +#include +#include Drivers should just #include ok. +static struct f81504_gpio_chip *gpio_to_f81504_chip(struct gpio_chip *chip) +{ + return container_of(chip, struct f81504_gpio_chip, chip); +} Avoid this construction in new code. Use gpiochip_get_data(chip) everywhere that gpio_to_f81504_chip() is used and register the gpiochip with gpiochip_add_data() and the code will be simpler. See any other driver in drivers/gpio for examples, I converted them all. ok. I'll re-write this section. + + if (tmp & BIT(offset)) + return GPIOF_DIR_OUT; + + return GPIOF_DIR_IN; +} Do not use GPIOF* flags in driver code, these are for the consumer API. Just return 0/1. ok + status = gpiochip_add(>chip); As mentioned, use gpiochip_add_data(>chip, gc); ok. +static struct platform_driver f81504_gpio_driver = { + .driver = { + .name = F81504_GPIO_NAME, + .owner = THIS_MODULE, I saw coccinelle was already complaining about this. Looking forward to v3! I had sent V3 today to resolve the issue above. Thanks for your advices. -- With Best Regards, Peter Hung
Re: [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Linus, Linus Walleij 於 2016/2/10 下午 05:08 寫道: On Thu, Jan 28, 2016 at 10:20 AM, Peter Hung wrote: +#include +#include Drivers should just #include ok. +static struct f81504_gpio_chip *gpio_to_f81504_chip(struct gpio_chip *chip) +{ + return container_of(chip, struct f81504_gpio_chip, chip); +} Avoid this construction in new code. Use gpiochip_get_data(chip) everywhere that gpio_to_f81504_chip() is used and register the gpiochip with gpiochip_add_data() and the code will be simpler. See any other driver in drivers/gpio for examples, I converted them all. ok. I'll re-write this section. + + if (tmp & BIT(offset)) + return GPIOF_DIR_OUT; + + return GPIOF_DIR_IN; +} Do not use GPIOF* flags in driver code, these are for the consumer API. Just return 0/1. ok + status = gpiochip_add(>chip); As mentioned, use gpiochip_add_data(>chip, gc); ok. +static struct platform_driver f81504_gpio_driver = { + .driver = { + .name = F81504_GPIO_NAME, + .owner = THIS_MODULE, I saw coccinelle was already complaining about this. Looking forward to v3! I had sent V3 today to resolve the issue above. Thanks for your advices. -- With Best Regards, Peter Hung
[PATCH V3 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 241 + 3 files changed, 252 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2b80903..c9e1cf8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -912,6 +912,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c759190..f277089 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..ef42e4f --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct f81504_gpio_chip *gc = gpiochip_get_data(chip); + struct platform_device *pdev = to_platform_device(chip->parent); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + u8 tmp; + + mutex_lock(>locker); + + /* set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * +F81504_GPIO_SET_OFFSET + +F81504_GPIO_OUT_EN_OFFSET, ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + + F81504_GPIO_OUT_EN_OFFSET, tmp & ~BIT(offset)); + + mutex_unlock(>locker); + return 0; +} + +sta
[PATCH V3 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 241 + 3 files changed, 252 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2b80903..c9e1cf8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -912,6 +912,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c759190..f277089 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..ef42e4f --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct f81504_gpio_chip *gc = gpiochip_get_data(chip); + struct platform_device *pdev = to_platform_device(chip->parent); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + u8 tmp; + + mutex_lock(>locker); + + /* set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * +F81504_GPIO_SET_OFFSET + +F81504_GPIO_OUT_EN_OFFSET, ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + + F81504_GPIO_OUT_EN_OFFSET, tmp & ~BIT(offset)); + + mutex_unlock(>locker); + return 0; +} + +static int f81504_gpio_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ +
[PATCH V3 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/mfd/Kconfig| 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 336 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 402 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aa21dc5..775761f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -345,6 +345,18 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 +help + This driver provides the F81504/508/512 UART & GPIO platform + devices. You should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial port support. + This driver needs to be built into the kernel to use early + console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eaa6465d..8e581ad 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..12a5f7f --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,336 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* find every port to check is multi-function port? */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio +* mode. So we'll not configure it as serial port. +*/ + return true; + } + + return false; +} + +static int f81504_port_init(struct pci_dev *pdev) +{ + struct f81504_pci_private *priv = pci_get_drvdata(pdev); + unsigned int i; + u32 gpio_addr; + u8 gpio_en, f0h_data, f3h_data; + u32 max_port, iobase; + u32 bar_data[3]; + u16 tmp; + u8 config_base; + + /* Init GPIO IO Address */ + gpio_addr = pci_resource_start(pdev, 2); + + /* +* Write GPIO IO Address LSB/MSB to corresponding register. Due to we +* can't write once with pci_write_config_word() on x86 platform, we'll +* write it with pci_write_conf
[PATCH V3 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/mfd/Kconfig| 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 336 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 402 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aa21dc5..775761f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -345,6 +345,18 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default SERIAL_8250 +help + This driver provides the F81504/508/512 UART & GPIO platform + devices. You should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial port support. + This driver needs to be built into the kernel to use early + console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5eaa6465d..8e581ad 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..12a5f7f --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,336 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static bool f81504_is_gpio(unsigned int idx, u8 gpio_en) +{ + unsigned int i; + + /* find every port to check is multi-function port? */ + for (i = 0; i < ARRAY_SIZE(fintek_gpio_mapping); i++) { + if (fintek_gpio_mapping[i] != idx || !(gpio_en & BIT(i))) + continue; + + /* +* This port is multi-function and enabled as gpio +* mode. So we'll not configure it as serial port. +*/ + return true; + } + + return false; +} + +static int f81504_port_init(struct pci_dev *pdev) +{ + struct f81504_pci_private *priv = pci_get_drvdata(pdev); + unsigned int i; + u32 gpio_addr; + u8 gpio_en, f0h_data, f3h_data; + u32 max_port, iobase; + u32 bar_data[3]; + u16 tmp; + u8 config_base; + + /* Init GPIO IO Address */ + gpio_addr = pci_resource_start(pdev, 2); + + /* +* Write GPIO IO Address LSB/MSB to corresponding register. Due to we +* can't write once with pci_write_config_word() on x86 platform, we'll +* write it with pci_write_config_byte(). +*/ + pci_write_config_byte(pdev, F81504_GPIO_IO_LSB_REG, gpio_addr &
[PATCH V3 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 266 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..747af87 --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); + /* find divisible clock source */ + rem = baudrate_table[index] % baud; + + if (quot && !rem) { + if (idx) + *idx = index; + return 0; + } + } + +
[PATCH V3 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 266 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..747af87 --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); + /* find divisible clock source */ + rem = baudrate_table[index] % baud; + + if (quot && !rem) { + if (idx) + *idx = index; + return 0; + } + } + + return -EINVAL; +} + +static void f81504_set_termios(struct uart_port *port, + struct ktermios *termi
[PATCH V3 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support and Andy recommend me to add these this in blacklist to avoid probed by 8250_pci.c Suggested-by: Paul Gortmaker <paul.gortma...@windriver.com> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_pci.c | 206 + 1 file changed, 5 insertions(+), 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e71ec78..24a669c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,156 +1532,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i <
[PATCH V3 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support and Andy recommend me to add these this in blacklist to avoid probed by 8250_pci.c Suggested-by: Paul Gortmaker Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 206 + 1 file changed, 5 insertions(+), 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e71ec78..24a669c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,156 +1532,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i < max_port; ++i) { - /* UART0 configuration offset start from 0x40 */ - config_base
[PATCH V3 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c and add it to blacklist It can be workable when applied patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Changelog: V3: 1. Refactoring gpio-f81504.c with new API (Suggested by Linus Walleij). 2. Fix wrong kfree in gpio-f81504.c (Suggested by Andy Shevchenko). 3. Get PCI resource by pci_resource_start() instead of getting PCI resource from BAR of PCI configuration space (Suggested by Alan). V2: 1. Split F81504/508/512 from 8250_pci.c to MFD, It'll add 3 new files 1. drivers/mfd/f81504-core.c 2. drivers/gpio/gpio-f81504.c 3. drivers/tty/serial/8250/8250_f81504.c V1: 1. Split F81504/508/512 from 8250_pci.c to 8250_fintek_pci.c. Alan & Andy recommend me to rewrite as MFD architecture. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 241 drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 336 ++ drivers/tty/serial/8250/8250_f81504.c | 254 + drivers/tty/serial/8250/8250_pci.c| 206 + drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 925 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
[PATCH V3 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c and add it to blacklist It can be workable when applied patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Changelog: V3: 1. Refactoring gpio-f81504.c with new API (Suggested by Linus Walleij). 2. Fix wrong kfree in gpio-f81504.c (Suggested by Andy Shevchenko). 3. Get PCI resource by pci_resource_start() instead of getting PCI resource from BAR of PCI configuration space (Suggested by Alan). V2: 1. Split F81504/508/512 from 8250_pci.c to MFD, It'll add 3 new files 1. drivers/mfd/f81504-core.c 2. drivers/gpio/gpio-f81504.c 3. drivers/tty/serial/8250/8250_f81504.c V1: 1. Split F81504/508/512 from 8250_pci.c to 8250_fintek_pci.c. Alan & Andy recommend me to rewrite as MFD architecture. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 241 drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 336 ++ drivers/tty/serial/8250/8250_f81504.c | 254 + drivers/tty/serial/8250/8250_pci.c| 206 + drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 925 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
Re: [PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Hi Andy, Andy Shevchenko 於 2016/1/29 下午 08:40 寫道: On Fri, 2016-01-29 at 16:20 +0800, Peter Hung wrote: Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:04 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: - /* Fintek PCI serial cards */ - { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, - { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, - { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, Shouldn't you blacklist them in 8250_pci? You are referring to add blacklist instead of remove F81504/508/512 code? No. or add blacklist and remove code? This one. ok Check what lspci tells you about your device. I'm pretty sure that it has Serial Class, which would trigger enumeration in 8250_pci.c if it comes first. I had add log with 8250_pci.c. It really trigger once by 8250_pci.c, but will failed with serial_pci_guess_board(). So It can be handled by f81504-core.c. I should add pid/vid to blacklist and comments it'll be handled by f81504-core.c Thanks -- With Best Regards, Peter Hung
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Andy, Andy Shevchenko 於 2016/1/29 下午 09:41 寫道: On Fri, 2016-01-29 at 13:50 +0800, Peter Hung wrote: Andy Shevchenko 於 2016/1/28 下午 07:55 寫道: I would suggest to rearrange definition block here (and in the rest of the functions in entire series) to somehow follow the following pattern 1) assignments go first, especially container_of() based ones; 2) group variables by meaning and put longer lines upper; 3) return value variable, if exists, goes last. Besides that choose types carefully. If there is known limit for counters, no need to define wider type than needed. Use proper types for corresponding values. I'll try to rearrange the definition blocks. For the counter issue, some senior recommend me to change count from int to size_t for performance. Wow, how come? On which arch? Also mark this as (1) to refer below. In this case, should I use u8 to replace i & j ? It should be less than 12 & 6. At least you tell compiler that it may use any suitable type. In any case the last decision is by compiler if you don't do any tricks. So, I suggest to use non-fixed width type like (unsigned) int and leave everything else on compiler. Sorry for my misunderstanding, not for performance. The senior just recommend me to replace all size/count variables to size_t. https://lkml.org/lkml/2016/1/3/193 size_t in x86 is unsigned int, x86_64 is unsigned long, It maybe good for prefetch or match register size I guess. I'll make the size_t of series patches to unsigned int. + pci_write_config_byte(dev, F81504_GPIO_IO_LSB_REG, gpio_addr & 0xff); + pci_write_config_byte(dev, F81504_GPIO_IO_MSB_REG, (gpio_addr >> 8) & + 0xff); Could it be written at once as a word? I tested with writing a word to "F81504_GPIO_IO_LSB_REG", but it'll failed, so I'll remain it. Please, add a comment line above. ok + if (priv) { + /* Reinit from resume(), read the previous value from priv */ + gpio_en = priv->gpio_en; I would suggest to move this line down to follow same pattern in else branch. I'm talking here to make simple rearrangement like if () { … gpio_en = … } else { … gpio_en = … } Thus the gpio_en assignment goes last in both branches. ok + + pci_write_config_byte(dev, config_base + 0x06, dev- irq); + + /* +* Force init to RS232 / Share Mode, recovery previous mode +* will done in F81504 8250 platform driver resume() Period at the end of sentences in multi-line comments. Sorry, what this mean for ? I cant use multi-line comments in the end ?? Sentences are started with capital letters and end with period '.' character, like this one. ok. + if (status) { + dev_warn(>dev, "%s: add device failed: %d\n", + __func__, status); Indent _ under &. Some senior recommend me to do at least 2-tabs to do indent when code cross multi-line. So I'll use to 2-tabs from "dev" to do indent. How should I do with indent ?? It seems no consensus, but Lindent will do indent like your comments. I would suggest to use what is used in most recent drivers and modules. I don't remember that 2 tabs fact is somehow reflected in CodingStyle. Maybe your seniour was talkin about multi-line function definition? ok, I'll indent multi-line statement as your comment and multi-line function with 2 tabs. + f81504_gpio_cell.pdata_size = sizeof(i); Static. The problem here is badly chosen type of i. Like I mentioned at the top of review… I'll try to rewrite it with pass a structure. It seems more make sense. That's correct on one side, on the other I'm not sure you got my comment. size_t is arch-dependent type, sizeof() is not the same everywhere. I'll change it to pass unsigned int. + pci_read_config_byte(dev, F81504_GPIO_IO_MSB_REG, ); + priv->gpio_ioaddr = tmp << 8; + pci_read_config_byte(dev, F81504_GPIO_IO_LSB_REG, ); + priv->gpio_ioaddr |= tmp; One read as word? It can't read as word. The "F81504_GPIO_IO_LSB_REG" is 0xf1, It seems can't be read word/dword from a odd address. I'll remain it. Put comment about that. ok So, if you have default y for this and 8250_pci, which one will be loaded? I had tested on x86, It'll handle by 8250_pci.c when this & 8250_pci.c all built-in mode. Yeah. here is the problem. When you introduce that you have to be sure that no-one will try to build kernel with both included right now. Paul had recommend me to reduce the impact of code change. I'll remove all F81504/508/512 code in 8250_pci.c until the series patches had applied. The device will handle with 8250_pci.c before applide patch no4, and handle with f81504_code.c when applied patch no4. This maybe reduce the bisect misleading. BTW, due
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Andy, Andy Shevchenko 於 2016/1/29 下午 09:41 寫道: On Fri, 2016-01-29 at 13:50 +0800, Peter Hung wrote: Andy Shevchenko 於 2016/1/28 下午 07:55 寫道: I would suggest to rearrange definition block here (and in the rest of the functions in entire series) to somehow follow the following pattern 1) assignments go first, especially container_of() based ones; 2) group variables by meaning and put longer lines upper; 3) return value variable, if exists, goes last. Besides that choose types carefully. If there is known limit for counters, no need to define wider type than needed. Use proper types for corresponding values. I'll try to rearrange the definition blocks. For the counter issue, some senior recommend me to change count from int to size_t for performance. Wow, how come? On which arch? Also mark this as (1) to refer below. In this case, should I use u8 to replace i & j ? It should be less than 12 & 6. At least you tell compiler that it may use any suitable type. In any case the last decision is by compiler if you don't do any tricks. So, I suggest to use non-fixed width type like (unsigned) int and leave everything else on compiler. Sorry for my misunderstanding, not for performance. The senior just recommend me to replace all size/count variables to size_t. https://lkml.org/lkml/2016/1/3/193 size_t in x86 is unsigned int, x86_64 is unsigned long, It maybe good for prefetch or match register size I guess. I'll make the size_t of series patches to unsigned int. + pci_write_config_byte(dev, F81504_GPIO_IO_LSB_REG, gpio_addr & 0xff); + pci_write_config_byte(dev, F81504_GPIO_IO_MSB_REG, (gpio_addr >> 8) & + 0xff); Could it be written at once as a word? I tested with writing a word to "F81504_GPIO_IO_LSB_REG", but it'll failed, so I'll remain it. Please, add a comment line above. ok + if (priv) { + /* Reinit from resume(), read the previous value from priv */ + gpio_en = priv->gpio_en; I would suggest to move this line down to follow same pattern in else branch. I'm talking here to make simple rearrangement like if () { … gpio_en = … } else { … gpio_en = … } Thus the gpio_en assignment goes last in both branches. ok + + pci_write_config_byte(dev, config_base + 0x06, dev- irq); + + /* +* Force init to RS232 / Share Mode, recovery previous mode +* will done in F81504 8250 platform driver resume() Period at the end of sentences in multi-line comments. Sorry, what this mean for ? I cant use multi-line comments in the end ?? Sentences are started with capital letters and end with period '.' character, like this one. ok. + if (status) { + dev_warn(>dev, "%s: add device failed: %d\n", + __func__, status); Indent _ under &. Some senior recommend me to do at least 2-tabs to do indent when code cross multi-line. So I'll use to 2-tabs from "dev" to do indent. How should I do with indent ?? It seems no consensus, but Lindent will do indent like your comments. I would suggest to use what is used in most recent drivers and modules. I don't remember that 2 tabs fact is somehow reflected in CodingStyle. Maybe your seniour was talkin about multi-line function definition? ok, I'll indent multi-line statement as your comment and multi-line function with 2 tabs. + f81504_gpio_cell.pdata_size = sizeof(i); Static. The problem here is badly chosen type of i. Like I mentioned at the top of review… I'll try to rewrite it with pass a structure. It seems more make sense. That's correct on one side, on the other I'm not sure you got my comment. size_t is arch-dependent type, sizeof() is not the same everywhere. I'll change it to pass unsigned int. + pci_read_config_byte(dev, F81504_GPIO_IO_MSB_REG, ); + priv->gpio_ioaddr = tmp << 8; + pci_read_config_byte(dev, F81504_GPIO_IO_LSB_REG, ); + priv->gpio_ioaddr |= tmp; One read as word? It can't read as word. The "F81504_GPIO_IO_LSB_REG" is 0xf1, It seems can't be read word/dword from a odd address. I'll remain it. Put comment about that. ok So, if you have default y for this and 8250_pci, which one will be loaded? I had tested on x86, It'll handle by 8250_pci.c when this & 8250_pci.c all built-in mode. Yeah. here is the problem. When you introduce that you have to be sure that no-one will try to build kernel with both included right now. Paul had recommend me to reduce the impact of code change. I'll remove all F81504/508/512 code in 8250_pci.c until the series patches had applied. The device will handle with 8250_pci.c before applide patch no4, and handle with f81504_code.c when applied patch no4. This maybe reduce the bisect misleading. BTW, due
Re: [PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Hi Andy, Andy Shevchenko 於 2016/1/29 下午 08:40 寫道: On Fri, 2016-01-29 at 16:20 +0800, Peter Hung wrote: Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:04 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: - /* Fintek PCI serial cards */ - { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, - { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, - { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, Shouldn't you blacklist them in 8250_pci? You are referring to add blacklist instead of remove F81504/508/512 code? No. or add blacklist and remove code? This one. ok Check what lspci tells you about your device. I'm pretty sure that it has Serial Class, which would trigger enumeration in 8250_pci.c if it comes first. I had add log with 8250_pci.c. It really trigger once by 8250_pci.c, but will failed with serial_pci_guess_board(). So It can be handled by f81504-core.c. I should add pid/vid to blacklist and comments it'll be handled by f81504-core.c Thanks -- With Best Regards, Peter Hung
Re: [PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:04 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: - /* Fintek PCI serial cards */ - { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, - { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, - { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, Shouldn't you blacklist them in 8250_pci? You are referring to add blacklist instead of remove F81504/508/512 code? or add blacklist and remove code? -- With Best Regards, Peter Hung
Re: [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:03 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: + /* set output data */ + tmp = inb(priv->gpio_ioaddr + gc->idx); ioread8 is a bit better since it automatically works with IO space and MMIO. But if you are certain you will always have the address in IO space, you can disregard this comment. I had only tested on x86 environment currently. We'll try to get an ARM platform with PCIE to test it. We'll remain it until getting new board. +static int f81504_gpio_probe(struct platform_device *pdev) +{ + int status; + struct f81504_gpio_chip *gc; + void *data = dev_get_platdata(>dev); + u8 gpio_idx = *(u8 *)data; + char *name; + + if (gpio_idx >= ARRAY_SIZE(fintek_gpio_mapping)) { + dev_err(>dev, "%s: gpio_idx:%d out of range.\n", + __func__, gpio_idx); + return -ENODEV; + } + + gc = devm_kzalloc(>dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + kfree(data); What the heck? Sorry for the big mistake, I'd confused for dev_get_platdata() & platform_set_drvdata(). I'll rewrite this and check 8250_f81504.c too. + status = gpiochip_add(>chip); + if (status) { + dev_err(>dev, "%s: gpiochip_add failed: %d\n", __func__, + status); + return -ENOMEM; You ignored the status. + } + + return 0; Perhaps just return gpiochip_add(); ? Just return gpiochip_add() seems good. Thanks your advices -- With Best Regards, Peter Hung
Re: [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:03 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: + /* set output data */ + tmp = inb(priv->gpio_ioaddr + gc->idx); ioread8 is a bit better since it automatically works with IO space and MMIO. But if you are certain you will always have the address in IO space, you can disregard this comment. I had only tested on x86 environment currently. We'll try to get an ARM platform with PCIE to test it. We'll remain it until getting new board. +static int f81504_gpio_probe(struct platform_device *pdev) +{ + int status; + struct f81504_gpio_chip *gc; + void *data = dev_get_platdata(>dev); + u8 gpio_idx = *(u8 *)data; + char *name; + + if (gpio_idx >= ARRAY_SIZE(fintek_gpio_mapping)) { + dev_err(>dev, "%s: gpio_idx:%d out of range.\n", + __func__, gpio_idx); + return -ENODEV; + } + + gc = devm_kzalloc(>dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + kfree(data); What the heck? Sorry for the big mistake, I'd confused for dev_get_platdata() & platform_set_drvdata(). I'll rewrite this and check 8250_f81504.c too. + status = gpiochip_add(>chip); + if (status) { + dev_err(>dev, "%s: gpiochip_add failed: %d\n", __func__, + status); + return -ENOMEM; You ignored the status. + } + + return 0; Perhaps just return gpiochip_add(); ? Just return gpiochip_add() seems good. Thanks your advices -- With Best Regards, Peter Hung
Re: [PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Hi Andy, Andy Shevchenko 於 2016/1/28 下午 08:04 寫道: On Thu, 2016-01-28 at 17:20 +0800, Peter Hung wrote: - /* Fintek PCI serial cards */ - { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, - { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, - { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, Shouldn't you blacklist them in 8250_pci? You are referring to add blacklist instead of remove F81504/508/512 code? or add blacklist and remove code? -- With Best Regards, Peter Hung
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
hes into 3 independent patch and based on their maintainer git repository? +static struct pci_driver f81504_driver = { + .name = F81504_DRIVER_NAME, + .probe = f81504_probe, + .remove = f81504_remove, + .driver = { + .pm = _pm_ops, + .owner = THIS_MODULE, kbuild already complained about. ok diff --git a/include/linux/mfd/f81504.h b/include/linux/mfd/f81504.h new file mode 100644 index 000..13bd0ae --- /dev/null +++ b/include/linux/mfd/f81504.h @@ -0,0 +1,52 @@ +#ifndef __F81504_H__ __MFD_F… ok Thanks for your advices -- With Best Regards, Peter Hung
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Alan, One Thousand Gnomes 於 2016/1/28 下午 06:04 寫道: + Please bulit-in kernel if you need early console support. This driver needs to be built into the kernel to use early console support. ok + switch (dev->device) { + case FINTEK_F81504: /* 4 ports */ + /* F81504 max 2 sets of GPIO, others are max 6 sets*/ + gpio_en &= 0x03; + case FINTEK_F81508: /* 8 ports */ + max_port = dev->device & 0xff; If that is meant to fall through from F81504 into F81508 it's worth commenting, otherwise someone reviewing the code can't always be sure it was intentional. ok, I'll add comments to describe this. + /* Get the UART IO address dispatch from the BIOS */ + pci_read_config_dword(dev, 0x24, _data[0]); + pci_read_config_dword(dev, 0x20, _data[1]); + pci_read_config_dword(dev, 0x1c, _data[2]); Take these from the pci device itself. On some non PC platforms the values in the pci bar may be remapped by bridges and not give you the true answer. pci_resource_start(dev, barnumber) Thanks for point this out, I'll rewrite here with pci_resource_start(). -- With Best Regards, Peter Hung
[PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support. Suggested-by: Paul Gortmaker Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 201 - 1 file changed, 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..0eeb4a3 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1527,156 +1527,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i < max_port; ++i) { - /* UART0 configuration offset start from 0x40 */ - config_base = 0x40 + 0x08 * i; - - /* Calculate Real IO Port */ - iobase = (bar_data[i / 4] & 0xffe0) + (
[PATCH V2 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 266 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..543661f --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); + /* find divisible clock source */ + rem = baudrate_table[index] % baud; + + if (quot && !rem) { + if (idx) + *idx = index; + return 0; + } + } + + return -EINVAL; +} + +static void f81504_set_termios(struct uart_port *port, + struct ktermios *termi
[PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/mfd/Kconfig| 11 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 331 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 396 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9ca66de..40503a4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -310,6 +310,17 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default y +help + This driver generate F81504/508/512 UART & GPIO platform + device. It should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial ports support. + Please bulit-in kernel if you need early console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0f230a6..f7382b3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -21,6 +21,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..9059171 --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,331 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_DRIVER_NAME "f81504_core" +#define F81504_DEV_DESC"Fintek F81504/508/512 PCIE-to-UART core" +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static int f81504_port_init(struct pci_dev *dev) +{ + size_t i, j; + u32 max_port, iobase, gpio_addr; + u32 bar_data[3]; + u16 tmp; + u8 config_base, gpio_en, f0h_data, f3h_data; + bool is_gpio; + struct f81504_pci_private *priv = pci_get_drvdata(dev); + + /* Init GPIO IO Address */ + pci_read_config_dword(dev, 0x18, _addr); + gpio_addr &= 0xffe0; + pci_write_config_byte(dev, F81504_GPIO_IO_LSB_REG, gpio_addr & 0xff); + pci_write_config_byte(dev, F81504_GPIO_IO_MSB_REG, (gpio_addr >> 8) & + 0xff); + + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +* bit2: UART8 pin out for UART8 / GPIO2 +* bit3: UART9 pin out for UART9 /
[PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes Suggested-by: Andy Shevchenko Signed-off-by: Peter Hung --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 257 + 3 files changed, 268 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b18bea0..633a65f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -900,6 +900,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 986dbd8..06fb240 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..817b926 --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static struct f81504_gpio_chip *gpio_to_f81504_chip(struct gpio_chip *chip) +{ + return container_of(chip, struct f81504_gpio_chip, chip); +} + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + u8 tmp; + struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip); + struct platform_device *pdev = to_platform_device(chip->dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + mutex_lock(>locker); + + /* set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET, + ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET, + tmp & ~BIT(offset)); + + mutex_unlock(>locker); + retu
[PATCH V2 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c It can be workable when applied patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 257 ++ drivers/mfd/Kconfig | 11 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 331 ++ drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/8250_pci.c| 201 - drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 930 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
[PATCH V2 0/4] Transform Fintek PCIE driver from 8250 to MFD
The Fintek F81504/508/512 is a multi-function PCIE devices. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function It had implemented in 8250_pci.c with basic serial port function. We want to complete it. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 So we'll do this with following patches. 1. Add MFD core driver. 2. Add GPIOLIB driver. 3. Add serial port driver. 4. Remove old driver in 8250_pci.c It can be workable when applied patches 1~3. After apply patch 4, the device will control by F81504 MFD core driver. Peter Hung (4): mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support serial: 8250_pci: Remove Fintek F81504/508/512 UART driver drivers/gpio/Kconfig | 10 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c| 257 ++ drivers/mfd/Kconfig | 11 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 331 ++ drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/8250_pci.c| 201 - drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + include/linux/mfd/f81504.h| 52 ++ 11 files changed, 930 insertions(+), 201 deletions(-) create mode 100644 drivers/gpio/gpio-f81504.c create mode 100644 drivers/mfd/f81504-core.c create mode 100644 drivers/tty/serial/8250/8250_f81504.c create mode 100644 include/linux/mfd/f81504.h -- 1.9.1
[PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
This driver is GPIOLIB driver for F81504/508/512, it'll handle the GPIOLIB operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function GPIO register: PCI Configuration space: F0h: bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve F1h: IO address (LSB) F2h: IO address (MSB) F8h + 8 * set: Direction control (bitwise) bitx: 0 - Input mode bitx: 1 - Output mode F9h + 8 * set: Drive ability control (bitwise) bitx: 0 - Open drain (default) bitx: 1 - Push Pull In this driver, we only implements open drain mode. IO space: (IO base + 0~5): GPIO-0x~5x in/out value (bitwise) Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-f81504.c | 257 + 3 files changed, 268 insertions(+) create mode 100644 drivers/gpio/gpio-f81504.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b18bea0..633a65f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -900,6 +900,16 @@ config GPIO_WM8994 Say yes here to access the GPIO signals of WM8994 audio hub CODECs from Wolfson Microelectronics. +config GPIO_F81504 +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support" +depends on MFD_FINTEK_F81504_CORE +select MFD_CORE +help + Say yes here to support the GPIO functionality of Fintek + F81504/508/512 PCIE-to-UART/GPIO. + + If unsure, say N. + endmenu menu "PCI GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 986dbd8..06fb240 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_GPIO_VX855)+= gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_F81504) += gpio-f81504.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB)+= gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c new file mode 100644 index 000..817b926 --- /dev/null +++ b/drivers/gpio/gpio-f81504.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2016 Fintek Corporation + * Based on gpio-mpc8xxx.c + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include +#include +#include +#include + +struct f81504_gpio_chip { + struct gpio_chip chip; + struct mutex locker; + u8 idx; + u8 save_out_en; + u8 save_drive_en; + u8 save_value; +}; + +static struct f81504_gpio_chip *gpio_to_f81504_chip(struct gpio_chip *chip) +{ + return container_of(chip, struct f81504_gpio_chip, chip); +} + +static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + u8 tmp; + struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip); + struct platform_device *pdev = to_platform_device(chip->dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + mutex_lock(>locker); + + /* set input mode */ + pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET, + ); + pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx * + F81504_GPIO_SET_OFFSET + F81504_GP
[PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
The Fintek F81504/508/512 had implemented the basic serial port function in 8250_pci.c. We try to implement high baudrate & GPIOLIB with a spilt file 8250_f81504.c, but it seems too complex to add GPIOLIB. Alan & Andy recommend us to rewrite and spilt our driver with MFD architecture. https://lkml.org/lkml/2016/1/19/288 This driver is core driver for F81504/508/512, it'll handle the generation of UART/GPIO platform device and initialize PCIE configuration space when probe()/resume(). IC function list: F81504: Max 2x8 GPIOs and max 4 serial ports port2/3 are multi-function F81508: Max 6x8 GPIOs and max 8 serial ports port2/3 are multi-function, port8/9/10/11 are gpio only F81512: Max 6x8 GPIOs and max 12 serial ports port2/3/8/9/10/11 are multi-function H/W provider could changes the PCI configure space F0/F3h values in EEPROM or ASL code to change mode. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/mfd/Kconfig| 11 ++ drivers/mfd/Makefile | 2 + drivers/mfd/f81504-core.c | 331 + include/linux/mfd/f81504.h | 52 +++ 4 files changed, 396 insertions(+) create mode 100644 drivers/mfd/f81504-core.c create mode 100644 include/linux/mfd/f81504.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9ca66de..40503a4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -310,6 +310,17 @@ config HTC_I2CPLD This device provides input and output GPIOs through an I2C interface to one or more sub-chips. +config MFD_FINTEK_F81504_CORE +tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO MFD support" +depends on PCI +select MFD_CORE +default y +help + This driver generate F81504/508/512 UART & GPIO platform + device. It should enable CONFIG_GPIO_F81504 to get GPIOLIB + support and CONFIG_8250_F81504 to get serial ports support. + Please bulit-in kernel if you need early console support. + config MFD_INTEL_QUARK_I2C_GPIO tristate "Intel Quark MFD I2C GPIO" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0f230a6..f7382b3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -21,6 +21,8 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o +obj-$(CONFIG_MFD_FINTEK_F81504_CORE) += f81504-core.o + obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o diff --git a/drivers/mfd/f81504-core.c b/drivers/mfd/f81504-core.c new file mode 100644 index 000..9059171 --- /dev/null +++ b/drivers/mfd/f81504-core.c @@ -0,0 +1,331 @@ +/* + * Core operations for Fintek F81504/508/512 PCIE-to-UART/GPIO device + */ +#include +#include +#include +#include +#include +#include +#include + +#define F81504_DRIVER_NAME "f81504_core" +#define F81504_DEV_DESC"Fintek F81504/508/512 PCIE-to-UART core" +#define F81504_IO_REGION 8 + +const u8 fintek_gpio_mapping[F81504_MAX_GPIO_CNT] = { 2, 3, 8, 9, 10, 11 }; +EXPORT_SYMBOL(fintek_gpio_mapping); + +static int f81504_port_init(struct pci_dev *dev) +{ + size_t i, j; + u32 max_port, iobase, gpio_addr; + u32 bar_data[3]; + u16 tmp; + u8 config_base, gpio_en, f0h_data, f3h_data; + bool is_gpio; + struct f81504_pci_private *priv = pci_get_drvdata(dev); + + /* Init GPIO IO Address */ + pci_read_config_dword(dev, 0x18, _addr); + gpio_addr &= 0xffe0; + pci_write_config_byte(dev, F81504_GPIO_IO_LSB_REG, gpio_addr & 0xff); + pci_write_config_byte(dev, F81504_GPIO_IO_MSB_REG, (gpio_addr >> 8) & + 0xff); + + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +
[PATCH V2 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support
This driver is 8250 driver for F81504/508/512, it'll handle the serial port operation of this device. This module will depend on MFD_FINTEK_F81504_CORE. The serial ports support from 50bps to 1.5Mbps with Linux baudrate define excluding 1.0Mbps due to not support 16MHz clock source. PCI Configuration Space Registers, set:0~11(Max): 40h + 8 * set: bit7~6: Clock source selector 00: 1.8432MHz 01: 18.432MHz 10: 24MHz 11: 14.769MHz bit0: UART enable 41h + 8 * set: bit5~4: RX trigger multiple 00: 1x * trigger level 01: 2x * trigger level 10: 4x * trigger level 11: 8x * trigger level bit1~0: FIFO Size 11: 128Bytes 44h + 8 * set: UART IO address (LSB) 45h + 8 * set: UART IO address (MSB) 47h + 8 * set: bit5: RTS invert (bit4 must enable) bit4: RTS auto direction enable 0: RTS control by MCR 1: RTS driven high when TX, otherwise low Suggested-by: One Thousand Gnomes <gno...@lxorguk.ukuu.org.uk> Suggested-by: Andy Shevchenko <andriy.shevche...@linux.intel.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_f81504.c | 254 ++ drivers/tty/serial/8250/Kconfig | 11 ++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 266 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_f81504.c diff --git a/drivers/tty/serial/8250/8250_f81504.c b/drivers/tty/serial/8250/8250_f81504.c new file mode 100644 index 000..543661f --- /dev/null +++ b/drivers/tty/serial/8250/8250_f81504.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include + +#include "8250.h" + +static u32 baudrate_table[] = { 150, 1152000, 921600 }; +static u8 clock_table[] = { F81504_CLKSEL_24_MHZ, F81504_CLKSEL_18DOT46_MHZ, + F81504_CLKSEL_14DOT77_MHZ }; + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int f81504_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct platform_device *pdev = container_of(port->dev, + struct platform_device, dev); + struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent); + + pci_read_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + ); + + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= F81504_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~F81504_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= F81504_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(F81504_RTS_CONTROL_BY_HW | F81504_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, F81504_UART_START_ADDR + + F81504_UART_OFFSET * *index + F81504_UART_MODE_OFFSET, + setting); + + if (rs485 != >rs485) + port->rs485 = *rs485; + + return 0; +} + +static int f81504_check_baudrate(u32 baud, size_t *idx) +{ + size_t index; + u32 quot, rem; + + for (index = 0; index < ARRAY_SIZE(baudrate_table); ++index) { + /* Clock source must largeer than desire baudrate */ + if (baud > baudrate_table[index]) + continue; + + quot = DIV_ROUND_CLOSEST(baudrate_table[index], baud); + /* find divisible clock source */ + rem = baudrate_table[index] % baud; + + if (quot && !rem) { + if (idx) + *idx = index; + return 0; + } + } + +
[PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver
Remove Fintek F81504/508/512 PCIE-to-UART device driver from 8250_pci.c Paul recommed us do less code deletion to avoid confusing problem when bisect. https://lkml.org/lkml/2016/1/18/646 But this patch is sent after with following patch. 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support We must remove F81504/508/512 support in 8250_pci.c and migrate to f81504-core/8250_f81504 to enable MFD support. Suggested-by: Paul Gortmaker <paul.gortma...@windriver.com> Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_pci.c | 201 - 1 file changed, 201 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..0eeb4a3 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1527,156 +1527,6 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } -/* RTS will control by MCR if this bit is 0 */ -#define FINTEK_RTS_CONTROL_BY_HW BIT(4) -/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ -#define FINTEK_RTS_INVERT BIT(5) - -/* We should do proper H/W transceiver setting before change to RS485 mode */ -static int pci_fintek_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) -{ - u8 setting; - u8 *index = (u8 *) port->private_data; - struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, - dev); - - pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - - if (!rs485) - rs485 = >rs485; - else if (rs485->flags & SER_RS485_ENABLED) - memset(rs485->padding, 0, sizeof(rs485->padding)); - else - memset(rs485, 0, sizeof(*rs485)); - - /* F81504/508/512 not support RTS delay before or after send */ - rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; - - if (rs485->flags & SER_RS485_ENABLED) { - /* Enable RTS H/W control mode */ - setting |= FINTEK_RTS_CONTROL_BY_HW; - - if (rs485->flags & SER_RS485_RTS_ON_SEND) { - /* RTS driving high on TX */ - setting &= ~FINTEK_RTS_INVERT; - } else { - /* RTS driving low on TX */ - setting |= FINTEK_RTS_INVERT; - } - - rs485->delay_rts_after_send = 0; - rs485->delay_rts_before_send = 0; - } else { - /* Disable RTS H/W control mode */ - setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); - } - - pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - - if (rs485 != >rs485) - port->rs485 = *rs485; - - return 0; -} - -static int pci_fintek_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - u8 *data; - u8 config_base; - u16 iobase; - - config_base = 0x40 + 0x08 * idx; - - /* Get the io address from configuration space */ - pci_read_config_word(pdev, config_base + 4, ); - - dev_dbg(>dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); - - port->port.iotype = UPIO_PORT; - port->port.iobase = iobase; - port->port.rs485_config = pci_fintek_rs485_config; - - data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* preserve index in PCI configuration space */ - *data = idx; - port->port.private_data = data; - - return 0; -} - -static int pci_fintek_init(struct pci_dev *dev) -{ - unsigned long iobase; - u32 max_port, i; - u32 bar_data[3]; - u8 config_base; - struct serial_private *priv = pci_get_drvdata(dev); - struct uart_8250_port *port; - - switch (dev->device) { - case 0x1104: /* 4 ports */ - case 0x1108: /* 8 ports */ - max_port = dev->device & 0xff; - break; - case 0x1112: /* 12 ports */ - max_port = 12; - break; - default: - return -EINVAL; - } - - /* Get the io address dispatch from the BIOS */ - pci_read_config_dword(dev, 0x24, _data[0]); - pci_read_config_dword(dev, 0x20, _data[1]); - pci_read_config_dword(dev, 0x1c, _data[2]); - - for (i = 0; i < max_port; ++i) { - /* UART0 configuration offset start from 0x40 */ - config_base = 0x40 + 0x08 * i; - - /* Calculate Real IO P
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
Hi Alan, One Thousand Gnomes 於 2016/1/28 下午 06:04 寫道: + Please bulit-in kernel if you need early console support. This driver needs to be built into the kernel to use early console support. ok + switch (dev->device) { + case FINTEK_F81504: /* 4 ports */ + /* F81504 max 2 sets of GPIO, others are max 6 sets*/ + gpio_en &= 0x03; + case FINTEK_F81508: /* 8 ports */ + max_port = dev->device & 0xff; If that is meant to fall through from F81504 into F81508 it's worth commenting, otherwise someone reviewing the code can't always be sure it was intentional. ok, I'll add comments to describe this. + /* Get the UART IO address dispatch from the BIOS */ + pci_read_config_dword(dev, 0x24, _data[0]); + pci_read_config_dword(dev, 0x20, _data[1]); + pci_read_config_dword(dev, 0x1c, _data[2]); Take these from the pci device itself. On some non PC platforms the values in the pci bar may be remapped by bridges and not give you the true answer. pci_resource_start(dev, barnumber) Thanks for point this out, I'll rewrite here with pci_resource_start(). -- With Best Regards, Peter Hung
Re: [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support
hes into 3 independent patch and based on their maintainer git repository? +static struct pci_driver f81504_driver = { + .name = F81504_DRIVER_NAME, + .probe = f81504_probe, + .remove = f81504_remove, + .driver = { + .pm = _pm_ops, + .owner = THIS_MODULE, kbuild already complained about. ok diff --git a/include/linux/mfd/f81504.h b/include/linux/mfd/f81504.h new file mode 100644 index 000..13bd0ae --- /dev/null +++ b/include/linux/mfd/f81504.h @@ -0,0 +1,52 @@ +#ifndef __F81504_H__ __MFD_F… ok Thanks for your advices -- With Best Regards, Peter Hung
[PATCH V8 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. F81532 spec: https://drive.google.com/file/d/0B8vRwwYO7aMFOTRRMmhWQVNvajQ/view?usp=sharing F81534 spec: https://drive.google.com/file/d/0B8vRwwYO7aMFV29pQWJqbVBNc00/view?usp=sharing F81438 transceiver spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459082/FINTEK/F81438.html Features: 1. F81532 is 1-to-2 & F81534 is 1-to-4 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can do auto-direction control by user-space tool. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). It's also controlled by user-space tool. 5. User-space tool will save the configuration in internal storage and the IC will read it when power on or driver loaded. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get user-space tool to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung --- Changelog: v8 1. Remove driver mode GPIOLIB & RS485 control support, the driver will only load GPIO/UART Mode when driver attach() & port_probe(). 2. Add more documents for 3 generation IC with f81534_calc_num_ports(). 3. Simplify the GPIO register structure "f81534_pin_control". 4. Change all counter type from int to size_t. 5. Change some failed message with failed: "status code" and remove all exclamation mark in messages. 6. Change all save blocks to block0 due to the driver is only used 1 block (block0) to save data. 7. Change read MSR in open() instead of port_probe(). 8. use GFP_ATOMIC kmalloc mode in write(). 9. Maintain old style with 1 read URBs and 4 write URBs like mxuports.c I had tested with submit 4 read URBs, but it'll make some port freeze when doing BurnInTest Port test. v7 1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block. Due to F81532/534 could run without gpiolib, we implements f81534_prepare_gpio()/f81534_release_gpio() always success without CONFIG_GPIOLIB. 2. Fix crash when receiving MSR change on driver load/unload. It's cause by f81534_process_read_urb() get read URB callback data, but port private data is not init complete or released. We solve with 2 modifications. 1. add null pointer check with f81534_process_read_urb(). We'll skip this report when port_priv = NULL. 2. when "one" port f81534_port_remove() is called, kill the port-0 read URB before kfree port_priv. v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. 5. Add device vendor id with 0x2c42 v5 1. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 2. Some function modifier add with static (Thanks for Paul Bolle) 3. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg
[PATCH V8 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. F81532 spec: https://drive.google.com/file/d/0B8vRwwYO7aMFOTRRMmhWQVNvajQ/view?usp=sharing F81534 spec: https://drive.google.com/file/d/0B8vRwwYO7aMFV29pQWJqbVBNc00/view?usp=sharing F81438 transceiver spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459082/FINTEK/F81438.html Features: 1. F81532 is 1-to-2 & F81534 is 1-to-4 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can do auto-direction control by user-space tool. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). It's also controlled by user-space tool. 5. User-space tool will save the configuration in internal storage and the IC will read it when power on or driver loaded. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get user-space tool to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- Changelog: v8 1. Remove driver mode GPIOLIB & RS485 control support, the driver will only load GPIO/UART Mode when driver attach() & port_probe(). 2. Add more documents for 3 generation IC with f81534_calc_num_ports(). 3. Simplify the GPIO register structure "f81534_pin_control". 4. Change all counter type from int to size_t. 5. Change some failed message with failed: "status code" and remove all exclamation mark in messages. 6. Change all save blocks to block0 due to the driver is only used 1 block (block0) to save data. 7. Change read MSR in open() instead of port_probe(). 8. use GFP_ATOMIC kmalloc mode in write(). 9. Maintain old style with 1 read URBs and 4 write URBs like mxuports.c I had tested with submit 4 read URBs, but it'll make some port freeze when doing BurnInTest Port test. v7 1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block. Due to F81532/534 could run without gpiolib, we implements f81534_prepare_gpio()/f81534_release_gpio() always success without CONFIG_GPIOLIB. 2. Fix crash when receiving MSR change on driver load/unload. It's cause by f81534_process_read_urb() get read URB callback data, but port private data is not init complete or released. We solve with 2 modifications. 1. add null pointer check with f81534_process_read_urb(). We'll skip this report when port_priv = NULL. 2. when "one" port f81534_port_remove() is called, kill the port-0 read URB before kfree port_priv. v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. 5. Add device vendor id with 0x2c42 v5 1. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 2. Some function modifier add with static (Thanks for Paul Bolle) 3. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2
Re: [PATCH V2 1/1] gpio-f7188x: Add F81866 GPIO supports
Hi Simon, Simon Guinot 於 2016/1/22 下午 04:58 寫道: On Fri, Jan 22, 2016 at 03:23:33PM +0800, Peter Hung wrote: Acked-by: Simon Guinot Thanks, Should I resend patch V3 to add Acked-by? -- With Best Regards, Peter Hung
Re: [PATCH V2 1/1] gpio-f7188x: Add F81866 GPIO supports
Hi Simon, Simon Guinot 於 2016/1/22 下午 04:58 寫道: On Fri, Jan 22, 2016 at 03:23:33PM +0800, Peter Hung wrote: Acked-by: Simon Guinot <simon.gui...@sequanux.org> Thanks, Should I resend patch V3 to add Acked-by? -- With Best Regards, Peter Hung
[PATCH V2 1/1] gpio-f7188x: Add F81866 GPIO supports
Add F81866 GPIO supports Fintek F81866 is a SuperIO. It contains HWMON/GPIO/Serial Ports. and it has totally 72(9x8 sets) gpio pins. Here is the PDF spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459085/FINTEK/F81866AD-I.html The control method is the same with F7188x, but we should care the address of GPIO8x. GPIO address is below: GPIO0x based: 0xf0 GPIO1x based: 0xe0 GPIO2x based: 0xd0 GPIO3x based: 0xc0 GPIO4x based: 0xb0 GPIO5x based: 0xa0 GPIO6x based: 0x90 GPIO7x based: 0x80 GPIO8x based: 0x88 <-- not 0x70. Signed-off-by: Peter Hung --- drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-f7188x.c | 27 --- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cb212eb..c1ad573 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -513,10 +513,10 @@ config GPIO_104_IDI_48 via the idi_48_irq module parameter. config GPIO_F7188X - tristate "F71869, F71869A, F71882FG and F71889F GPIO support" + tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support" help This option enables support for GPIOs found on Fintek Super-I/O - chips F71869, F71869A, F71882FG and F71889F. + chips F71869, F71869A, F71882FG, F71889F and F81866. To compile this driver as a module, choose M here: the module will be called f7188x-gpio. diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index d62fd6b..0417798 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -1,5 +1,5 @@ /* - * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882 and F71889 + * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866 * * Copyright (C) 2010-2013 LaCie * @@ -36,14 +36,16 @@ #define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */ #define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ #define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ +#define SIO_F81866_ID 0x1010 /* F81866 chipset ID */ -enum chips { f71869, f71869a, f71882fg, f71889f }; +enum chips { f71869, f71869a, f71882fg, f71889f, f81866 }; static const char * const f7188x_names[] = { "f71869", "f71869a", "f71882fg", "f71889f", + "f81866", }; struct f7188x_sio { @@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = { F7188X_GPIO_BANK(70, 8, 0x80), }; +static struct f7188x_gpio_bank f81866_gpio_bank[] = { + F7188X_GPIO_BANK(0, 8, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 8, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), + F7188X_GPIO_BANK(80, 8, 0x88), +}; + static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { int err; @@ -318,6 +332,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev) data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); data->bank = f71889_gpio_bank; break; + case f81866: + data->nr_bank = ARRAY_SIZE(f81866_gpio_bank); + data->bank = f81866_gpio_bank; + break; default: return -ENODEV; } @@ -395,6 +413,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F71889_ID: sio->type = f71889f; break; + case SIO_F81866_ID: + sio->type = f81866; + break; default: pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); goto err; @@ -485,6 +506,6 @@ static void __exit f7188x_gpio_exit(void) } module_exit(f7188x_gpio_exit); -MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG and F71889F"); +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866"); MODULE_AUTHOR("Simon Guinot "); MODULE_LICENSE("GPL"); -- 1.9.1
[PATCH V2 0/1] gpio-f7188x: Add F81866 GPIO supports
Fintek F81866 is a SuperIO. It contains HWMON/GPIO/Serial Ports. and it has totally 72(9x8 sets) gpio pins. Here is the PDF spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459085/FINTEK/F81866AD-I.html The control method is the same with F7188x, but we should care the address of GPIO8x. GPIO address is below: GPIO0x based: 0xf0 GPIO1x based: 0xe0 GPIO2x based: 0xd0 GPIO3x based: 0xc0 GPIO4x based: 0xb0 GPIO5x based: 0xa0 GPIO6x based: 0x90 GPIO7x based: 0x80 GPIO8x based: 0x88 <-- not 0x70. Change Log: V2: 1. V1 contains 2 patches, first is add F81866 and second is a filter to find enabled GPIO. But Simon say some mainboard maybe configure the SuperIO with wrong setting. So the V2 patch only implements F81866 GPIO control method the same with F7188x. Peter Hung (1): gpio-f7188x: Add F81866 GPIO supports drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-f7188x.c | 27 --- 2 files changed, 26 insertions(+), 5 deletions(-) -- Change Log: V2 1.9.1
[PATCH V2 1/1] gpio-f7188x: Add F81866 GPIO supports
Add F81866 GPIO supports Fintek F81866 is a SuperIO. It contains HWMON/GPIO/Serial Ports. and it has totally 72(9x8 sets) gpio pins. Here is the PDF spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459085/FINTEK/F81866AD-I.html The control method is the same with F7188x, but we should care the address of GPIO8x. GPIO address is below: GPIO0x based: 0xf0 GPIO1x based: 0xe0 GPIO2x based: 0xd0 GPIO3x based: 0xc0 GPIO4x based: 0xb0 GPIO5x based: 0xa0 GPIO6x based: 0x90 GPIO7x based: 0x80 GPIO8x based: 0x88 <-- not 0x70. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-f7188x.c | 27 --- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cb212eb..c1ad573 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -513,10 +513,10 @@ config GPIO_104_IDI_48 via the idi_48_irq module parameter. config GPIO_F7188X - tristate "F71869, F71869A, F71882FG and F71889F GPIO support" + tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support" help This option enables support for GPIOs found on Fintek Super-I/O - chips F71869, F71869A, F71882FG and F71889F. + chips F71869, F71869A, F71882FG, F71889F and F81866. To compile this driver as a module, choose M here: the module will be called f7188x-gpio. diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index d62fd6b..0417798 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -1,5 +1,5 @@ /* - * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882 and F71889 + * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866 * * Copyright (C) 2010-2013 LaCie * @@ -36,14 +36,16 @@ #define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */ #define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ #define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ +#define SIO_F81866_ID 0x1010 /* F81866 chipset ID */ -enum chips { f71869, f71869a, f71882fg, f71889f }; +enum chips { f71869, f71869a, f71882fg, f71889f, f81866 }; static const char * const f7188x_names[] = { "f71869", "f71869a", "f71882fg", "f71889f", + "f81866", }; struct f7188x_sio { @@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = { F7188X_GPIO_BANK(70, 8, 0x80), }; +static struct f7188x_gpio_bank f81866_gpio_bank[] = { + F7188X_GPIO_BANK(0, 8, 0xF0), + F7188X_GPIO_BANK(10, 8, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 8, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), + F7188X_GPIO_BANK(80, 8, 0x88), +}; + static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { int err; @@ -318,6 +332,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev) data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); data->bank = f71889_gpio_bank; break; + case f81866: + data->nr_bank = ARRAY_SIZE(f81866_gpio_bank); + data->bank = f81866_gpio_bank; + break; default: return -ENODEV; } @@ -395,6 +413,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F71889_ID: sio->type = f71889f; break; + case SIO_F81866_ID: + sio->type = f81866; + break; default: pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid); goto err; @@ -485,6 +506,6 @@ static void __exit f7188x_gpio_exit(void) } module_exit(f7188x_gpio_exit); -MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG and F71889F"); +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866"); MODULE_AUTHOR("Simon Guinot <simon.gui...@sequanux.org>"); MODULE_LICENSE("GPL"); -- 1.9.1
[PATCH V2 0/1] gpio-f7188x: Add F81866 GPIO supports
Fintek F81866 is a SuperIO. It contains HWMON/GPIO/Serial Ports. and it has totally 72(9x8 sets) gpio pins. Here is the PDF spec: http://www.alldatasheet.com/datasheet-pdf/pdf/459085/FINTEK/F81866AD-I.html The control method is the same with F7188x, but we should care the address of GPIO8x. GPIO address is below: GPIO0x based: 0xf0 GPIO1x based: 0xe0 GPIO2x based: 0xd0 GPIO3x based: 0xc0 GPIO4x based: 0xb0 GPIO5x based: 0xa0 GPIO6x based: 0x90 GPIO7x based: 0x80 GPIO8x based: 0x88 <-- not 0x70. Change Log: V2: 1. V1 contains 2 patches, first is add F81866 and second is a filter to find enabled GPIO. But Simon say some mainboard maybe configure the SuperIO with wrong setting. So the V2 patch only implements F81866 GPIO control method the same with F7188x. Peter Hung (1): gpio-f7188x: Add F81866 GPIO supports drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-f7188x.c | 27 --- 2 files changed, 26 insertions(+), 5 deletions(-) -- Change Log: V2 1.9.1
Re: [PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Hi Greg, Andy Shevchenko 於 2015/12/13 上午 09:08 寫道: First of all, maybe you can consider to split this part of the driver to separate one? (Like we did for 8250_mid.c). It seems 8250_pci is too bloated. But it's just an idea, maybe for future. Did you have reviewed this patch? Please skip this patch if not reviewed. The F81504/508/512 is multi-function card. It contains Serial/GPIO functions. It maybe enlarge the scale of 8250_pci.c and make it less maintainable if we add GPIOLIB support into 8250_pci.c Could I split the F81504/508/512 driver from 8250_pci.c into a new module file and implements GPIOLIB? Thanks -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Hi Greg, Andy Shevchenko 於 2015/12/13 上午 09:08 寫道: First of all, maybe you can consider to split this part of the driver to separate one? (Like we did for 8250_mid.c). It seems 8250_pci is too bloated. But it's just an idea, maybe for future. Did you have reviewed this patch? Please skip this patch if not reviewed. The F81504/508/512 is multi-function card. It contains Serial/GPIO functions. It maybe enlarge the scale of 8250_pci.c and make it less maintainable if we add GPIOLIB support into 8250_pci.c Could I split the F81504/508/512 driver from 8250_pci.c into a new module file and implements GPIOLIB? Thanks -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Hello, Andy Shevchenko 於 2015/12/13 上午 09:08 寫道: On Tue, Dec 1, 2015 at 8:54 AM, Peter Hung wrote: First of all, maybe you can consider to split this part of the driver to separate one? (Like we did for 8250_mid.c). It seems 8250_pci is too bloated. But it's just an idea, maybe for future. It's a good idea. Our PCI-to-UART device is a multifunctional (GPIO/UART) board, I need try to split it from 8250_pci.c to implements all functions. +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; Clearly you have bit combination here Bit 1: 1 Bit 3: 1 So, mask as 0x0a shall cover this IIAC. IMO, It maybe wrong. If we checked only with 0x0a mask, the 0x06 & 0x07 will be passed. I had try with k-map to reduce from 0~11 (12~15 for don't care). The final boolean value is a + c b(bar) for a is MSB. - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ Maybe you can introduce constants for IDs. I'll make the magic numbers with #define marco. Thanks for your advices. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Hello, Andy Shevchenko 於 2015/12/13 上午 09:08 寫道: On Tue, Dec 1, 2015 at 8:54 AM, Peter Hung <hpe...@gmail.com> wrote: First of all, maybe you can consider to split this part of the driver to separate one? (Like we did for 8250_mid.c). It seems 8250_pci is too bloated. But it's just an idea, maybe for future. It's a good idea. Our PCI-to-UART device is a multifunctional (GPIO/UART) board, I need try to split it from 8250_pci.c to implements all functions. +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; Clearly you have bit combination here Bit 1: 1 Bit 3: 1 So, mask as 0x0a shall cover this IIAC. IMO, It maybe wrong. If we checked only with 0x0a mask, the 0x06 & 0x07 will be passed. I had try with k-map to reduce from 0~11 (12~15 for don't care). The final boolean value is a + c b(bar) for a is MSB. - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ Maybe you can introduce constants for IDs. I'll make the magic numbers with #define marco. Thanks for your advices. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V7 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by ioctl TIOCGRS485/TIOCSRS485 If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So it implements as gpiolib interface with output-only function. 5. It'll save the configuration in internal storage when uart/pins mode changed. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung --- Changelog: v7 1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block. Due to F81532/534 could run without gpiolib, we implements f81534_prepare_gpio()/f81534_release_gpio() always success without CONFIG_GPIOLIB. 2. Fix crash when receiving MSR change on driver load/unload. It's cause by f81534_process_read_urb() get read URB callback data, but port private data is not init complete or released. We solve with 2 modifications. 1. add null pointer check with f81534_process_read_urb(). We'll skip this report when port_priv = NULL. 2. when "one" port f81534_port_remove() is called, kill the port-0 read URB before kfree port_priv. v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. 5. Add device vendor id with 0x2c42 v5 1. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 2. Some function modifier add with static (Thanks for Paul Bolle) 3. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 2945 +++ 3 files changed, 2956 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate "USB Fintek F81532/534 Multi-Ports Serial Driver" + help + Say Y here if you want to use the Fintek F81532/534 Multi-Ports + usb to seri
[PATCH V7 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by ioctl TIOCGRS485/TIOCSRS485 If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So it implements as gpiolib interface with output-only function. 5. It'll save the configuration in internal storage when uart/pins mode changed. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- Changelog: v7 1. Make all gpiolib function with #ifdef CONFIG_GPIOLIB marco block. Due to F81532/534 could run without gpiolib, we implements f81534_prepare_gpio()/f81534_release_gpio() always success without CONFIG_GPIOLIB. 2. Fix crash when receiving MSR change on driver load/unload. It's cause by f81534_process_read_urb() get read URB callback data, but port private data is not init complete or released. We solve with 2 modifications. 1. add null pointer check with f81534_process_read_urb(). We'll skip this report when port_priv = NULL. 2. when "one" port f81534_port_remove() is called, kill the port-0 read URB before kfree port_priv. v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. 5. Add device vendor id with 0x2c42 v5 1. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 2. Some function modifier add with static (Thanks for Paul Bolle) 3. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 2945 +++ 3 files changed, 2956 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate "USB Fintek F81532/534 Multi-Ports Serial Driver" + help + Say Y here if you want to use the Fintek F8
[PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Fix real serial port count for F81504/508/512 with multi-function mode. Fintek F81504/508/512 are multi-function boards. It could be configurated via PCI configuration space register F0h/F3h with external EEPROM that programmed by customer. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve It'll use (F0h & ~F3h) & 0x3f union set to find max set of GPIOs. If a port is indicated as GPIO, it'll not report as serial port and reserve for userspace to manipulate. F81504: Max for 4 serial ports. UART2/3 is multi-function. F81508: Max for 8 serial ports. UART2/3 is multi-function. 8/9/10/11 is GPIO only F81512: Max for 12 serial ports. UART2/3/8/9/10/11 is multi-function. Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 114 +++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..8a639cb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,6 +1532,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv, /* only worked with FINTEK_RTS_CONTROL_BY_HW on */ #define FINTEK_RTS_INVERT BIT(5) +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; + /* We should do proper H/W transceiver setting before change to RS485 mode */ static int pci_fintek_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) @@ -1586,10 +1589,41 @@ static int pci_fintek_setup(struct serial_private *priv, { struct pci_dev *pdev = priv->dev; u8 *data; - u8 config_base; - u16 iobase; + u8 tmp; + u8 config_base = 0; + u16 iobase, i, max_port, count = 0; - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = pdev->device & 0xff; + break; + case 0x1112: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* find real serial port index from logic idx */ + for (i = 0; i < max_port; ++i) { + config_base = 0x40 + 0x08 * i; + + pci_read_config_byte(pdev, config_base, ); + if (!tmp) + continue; + + if (count == idx) + break; + + ++count; + } + + if (i >= max_port) { + dev_err(>dev, "%s: mapping error! i=%d, idx=%d\n", + __func__, i, idx); + return -ENODEV; + } /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, ); @@ -1604,8 +1638,8 @@ static int pci_fintek_setup(struct serial_private *priv, if (!data) return -ENOMEM; - /* preserve index in PCI configuration space */ - *data = idx; + /* preserve real index in PCI configuration space */ + *data = i; port->port.private_data = data; return 0; @@ -1614,12 +1648,40 @@ static int pci_fintek_setup(struct serial_private *priv, static int pci_fintek_init(struct pci_dev *dev) { unsigned long iobase; - u32 max_port, i; + u32 max_port, i, j; u32 bar_data[3]; u8 config_base; + u8 tmp, f0h_data, f3h_data; + bool skip_init; struct serial_private *priv = pci_get_drvdata(dev); struct uart_8250_port *port; + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +* bit2: UART8 pin out for UART8 / GPIO2 +* bit3: UART9 pin out for UART9 / GPIO3 +* bit4: UART10 pin out for UART10 / GPIO4 +* bit5: UART11 pin out for UART11 / GPIO5 +* bit6~7: Reserve +*/ + pci_read_config_byte(dev, 0xf0, _data); + pci_read_config_byte(dev, 0xf3, _data); + + /* find the max set of GPIOs */ + tmp = f0h_data | ~f3h_data; + + /* rewrite GPIO setting
[PATCH 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Fix real serial port count for F81504/508/512 with multi-function mode. Fintek F81504/508/512 are multi-function boards. It could be configurated via PCI configuration space register F0h/F3h with external EEPROM that programmed by customer. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve It'll use (F0h & ~F3h) & 0x3f union set to find max set of GPIOs. If a port is indicated as GPIO, it'll not report as serial port and reserve for userspace to manipulate. F81504: Max for 4 serial ports. UART2/3 is multi-function. F81508: Max for 8 serial ports. UART2/3 is multi-function. 8/9/10/11 is GPIO only F81512: Max for 12 serial ports. UART2/3/8/9/10/11 is multi-function. Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 114 +++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..8a639cb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,6 +1532,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv, /* only worked with FINTEK_RTS_CONTROL_BY_HW on */ #define FINTEK_RTS_INVERT BIT(5) +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; + /* We should do proper H/W transceiver setting before change to RS485 mode */ static int pci_fintek_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) @@ -1586,10 +1589,41 @@ static int pci_fintek_setup(struct serial_private *priv, { struct pci_dev *pdev = priv->dev; u8 *data; - u8 config_base; - u16 iobase; + u8 tmp; + u8 config_base = 0; + u16 iobase, i, max_port, count = 0; - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = pdev->device & 0xff; + break; + case 0x1112: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* find real serial port index from logic idx */ + for (i = 0; i < max_port; ++i) { + config_base = 0x40 + 0x08 * i; + + pci_read_config_byte(pdev, config_base, ); + if (!tmp) + continue; + + if (count == idx) + break; + + ++count; + } + + if (i >= max_port) { + dev_err(>dev, "%s: mapping error! i=%d, idx=%d\n", + __func__, i, idx); + return -ENODEV; + } /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, ); @@ -1604,8 +1638,8 @@ static int pci_fintek_setup(struct serial_private *priv, if (!data) return -ENOMEM; - /* preserve index in PCI configuration space */ - *data = idx; + /* preserve real index in PCI configuration space */ + *data = i; port->port.private_data = data; return 0; @@ -1614,12 +1648,40 @@ static int pci_fintek_setup(struct serial_private *priv, static int pci_fintek_init(struct pci_dev *dev) { unsigned long iobase; - u32 max_port, i; + u32 max_port, i, j; u32 bar_data[3]; u8 config_base; + u8 tmp, f0h_data, f3h_data; + bool skip_init; struct serial_private *priv = pci_get_drvdata(dev); struct uart_8250_port *port; + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +* bit2: UART8 pin out for UART8 / GPIO2 +* bit3: UART9 pin out for UART9 / GPIO3 +* bit4: UART10 pin out for UART10 / GPIO4 +* bit5: UART11 pin out for UART11 / GPIO5 +* bit6~7: Reserve +*/ + pci_read_config_byte(dev, 0xf0, _data); + pci_read_config_byte(dev, 0xf3, _data); + + /* find the max set of GPIOs */ + tmp = f0h_data | ~f3h_data; + + /* rewrite GPIO setting
[PATCH 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Fix real serial port count for F81504/508/512 with multi-function mode. Fintek F81504/508/512 are multi-function boards. It could be configurated via PCI configuration space register F0h/F3h with external EEPROM that programmed by customer. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve It'll use (F0h & ~F3h) & 0x3f union set to find max set of GPIOs. If a port is indicated as GPIO, it'll not report as serial port and reserve for userspace to manipulate. F81504: Max for 4 serial ports. UART2/3 is multi-function. F81508: Max for 8 serial ports. UART2/3 is multi-function. 8/9/10/11 is GPIO only F81512: Max for 12 serial ports. UART2/3/8/9/10/11 is multi-function. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_pci.c | 114 +++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..8a639cb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,6 +1532,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv, /* only worked with FINTEK_RTS_CONTROL_BY_HW on */ #define FINTEK_RTS_INVERT BIT(5) +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; + /* We should do proper H/W transceiver setting before change to RS485 mode */ static int pci_fintek_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) @@ -1586,10 +1589,41 @@ static int pci_fintek_setup(struct serial_private *priv, { struct pci_dev *pdev = priv->dev; u8 *data; - u8 config_base; - u16 iobase; + u8 tmp; + u8 config_base = 0; + u16 iobase, i, max_port, count = 0; - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = pdev->device & 0xff; + break; + case 0x1112: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* find real serial port index from logic idx */ + for (i = 0; i < max_port; ++i) { + config_base = 0x40 + 0x08 * i; + + pci_read_config_byte(pdev, config_base, ); + if (!tmp) + continue; + + if (count == idx) + break; + + ++count; + } + + if (i >= max_port) { + dev_err(>dev, "%s: mapping error! i=%d, idx=%d\n", + __func__, i, idx); + return -ENODEV; + } /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, ); @@ -1604,8 +1638,8 @@ static int pci_fintek_setup(struct serial_private *priv, if (!data) return -ENOMEM; - /* preserve index in PCI configuration space */ - *data = idx; + /* preserve real index in PCI configuration space */ + *data = i; port->port.private_data = data; return 0; @@ -1614,12 +1648,40 @@ static int pci_fintek_setup(struct serial_private *priv, static int pci_fintek_init(struct pci_dev *dev) { unsigned long iobase; - u32 max_port, i; + u32 max_port, i, j; u32 bar_data[3]; u8 config_base; + u8 tmp, f0h_data, f3h_data; + bool skip_init; struct serial_private *priv = pci_get_drvdata(dev); struct uart_8250_port *port; + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +* bit2: UART8 pin out for UART8 / GPIO2 +* bit3: UART9 pin out for UART9 / GPIO3 +* bit4: UART10 pin out for UART10 / GPIO4 +* bit5: UART11 pin out for UART11 / GPIO5 +* bit6~7: Reserve +*/ + pci_read_config_byte(dev, 0xf0, _data); + pci_read_config_byte(dev, 0xf3, _data); + + /* find the max set of GPIOs */ + tmp = f0
[PATCH RESEND 1/1] serial: 8250_pci: Fix real serial port count for F81504/508/512
Fix real serial port count for F81504/508/512 with multi-function mode. Fintek F81504/508/512 are multi-function boards. It could be configurated via PCI configuration space register F0h/F3h with external EEPROM that programmed by customer. F0h bit0~5: Enable GPIO0~5 bit6~7: Reserve F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) bit0: UART2 pin out for UART2 / GPIO0 bit1: UART3 pin out for UART3 / GPIO1 bit2: UART8 pin out for UART8 / GPIO2 bit3: UART9 pin out for UART9 / GPIO3 bit4: UART10 pin out for UART10 / GPIO4 bit5: UART11 pin out for UART11 / GPIO5 bit6~7: Reserve It'll use (F0h & ~F3h) & 0x3f union set to find max set of GPIOs. If a port is indicated as GPIO, it'll not report as serial port and reserve for userspace to manipulate. F81504: Max for 4 serial ports. UART2/3 is multi-function. F81508: Max for 8 serial ports. UART2/3 is multi-function. 8/9/10/11 is GPIO only F81512: Max for 12 serial ports. UART2/3/8/9/10/11 is multi-function. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- drivers/tty/serial/8250/8250_pci.c | 114 +++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 4097f3f..8a639cb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1532,6 +1532,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv, /* only worked with FINTEK_RTS_CONTROL_BY_HW on */ #define FINTEK_RTS_INVERT BIT(5) +/* The device is multi-function with UART & GPIO */ +static u8 fintek_gpio_mapping[] = {2, 3, 8, 9, 10, 11}; + /* We should do proper H/W transceiver setting before change to RS485 mode */ static int pci_fintek_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) @@ -1586,10 +1589,41 @@ static int pci_fintek_setup(struct serial_private *priv, { struct pci_dev *pdev = priv->dev; u8 *data; - u8 config_base; - u16 iobase; + u8 tmp; + u8 config_base = 0; + u16 iobase, i, max_port, count = 0; - config_base = 0x40 + 0x08 * idx; + switch (pdev->device) { + case 0x1104: /* 4 ports */ + case 0x1108: /* 8 ports */ + max_port = pdev->device & 0xff; + break; + case 0x1112: /* 12 ports */ + max_port = 12; + break; + default: + return -EINVAL; + } + + /* find real serial port index from logic idx */ + for (i = 0; i < max_port; ++i) { + config_base = 0x40 + 0x08 * i; + + pci_read_config_byte(pdev, config_base, ); + if (!tmp) + continue; + + if (count == idx) + break; + + ++count; + } + + if (i >= max_port) { + dev_err(>dev, "%s: mapping error! i=%d, idx=%d\n", + __func__, i, idx); + return -ENODEV; + } /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, ); @@ -1604,8 +1638,8 @@ static int pci_fintek_setup(struct serial_private *priv, if (!data) return -ENOMEM; - /* preserve index in PCI configuration space */ - *data = idx; + /* preserve real index in PCI configuration space */ + *data = i; port->port.private_data = data; return 0; @@ -1614,12 +1648,40 @@ static int pci_fintek_setup(struct serial_private *priv, static int pci_fintek_init(struct pci_dev *dev) { unsigned long iobase; - u32 max_port, i; + u32 max_port, i, j; u32 bar_data[3]; u8 config_base; + u8 tmp, f0h_data, f3h_data; + bool skip_init; struct serial_private *priv = pci_get_drvdata(dev); struct uart_8250_port *port; + /* +* The PCI board is multi-function, some serial port can converts to +* GPIO function. Customers could changes the F0/F3h values in EEPROM +* +* F0h bit0~5: Enable GPIO0~5 +* bit6~7: Reserve +* +* F3h bit0~5: Multi-Functional Flag (0:GPIO/1:UART) +* bit0: UART2 pin out for UART2 / GPIO0 +* bit1: UART3 pin out for UART3 / GPIO1 +* bit2: UART8 pin out for UART8 / GPIO2 +* bit3: UART9 pin out for UART9 / GPIO3 +* bit4: UART10 pin out for UART10 / GPIO4 +* bit5: UART11 pin out for UART11 / GPIO5 +* bit6~7: Reserve +*/ + pci_read_config_byte(dev, 0xf0, _data); + pci_read_config_byte(dev, 0xf3, _data); + + /* find the max set of GPIOs */ + tmp = f0
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Peter Hung 於 2015/11/3 上午 11:51 寫道: > This driver is for Fintek F81532/F81534 USB to Serial Ports IC. > Changelog: > v6 > 1. Re-implement the write()/resume() function. Due to this device cant be > suitable with generic write(), we'll do the submit write URB when > write()/received tx empty/set_termios()/resume() > 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & > f81534_phy_to_logic_port(). > 3. Introduced "Port Hide" function. Some customer use F81532 reference > design for HW layout, but really use F81534 IC. We'll check > F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do > port hide with port not used. It can be avoid end-user to use not > layouted port. > 4. The 4x3 output-only open-drain pins for F81532/534 is designed for > control outer devices (with our EVB for examples, the 4 sets of pins > are designed to control transceiver mode). So we decide to implement > with gpiolib interface. I need to do some improvements with senior advices, so I'll send v7 patch when I modify & re-test the code complete. Could you give me some roughly advices of this patch when you having time. Thanks for your help -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi, Oliver Neukum 於 2015/11/4 下午 04:38 寫道: On Wed, 2015-11-04 at 16:19 +0800, Peter Hung wrote: Hi Oliver Neukum 於 2015/11/3 下午 06:03 寫道: On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote: + for (i = 0; i < F81534_NUM_PORT; ++i) + atomic_set(_priv->port_active[i], 0); Should be ATOMIC_INIT() ATOMIC_INIT() seems to be used only for variable initializer, It cant be used for dynamic allocation. Should I change it to a normal boolean flag protecting with spin_lock ? No, if it doesn't work, use the current code. OK, I'll use current code. +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, Is the point of passing a pointer to msr locking? + bool is_port_open) This function is used only with URB callback function. The *msr is reported by H/W with newest MSR. The USB-Serial generic system will re-submit read URB when callback complete. So this function should run once on the same time. Yes, so why don't you pass an u8 as opposed to a pointer to an u8? I'll re-write it from u8* to u8. +static int f81534_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + unsigned long flags; + int r; + u8 msr, mcr; + + /* +* We'll avoid to direct read MSR register. The IC will read the MSR +* changed and report it f81534_process_per_serial_block() by +* F81534_TOKEN_MSR_CHANGE. +* +* When this device in heavy loading (e.g., BurnInTest Loopback Test) +* The report of MSR register will delay received a bit. It's due to +* MSR interrupt is lowest priority in 16550A. So we decide to sleep +* a little time to pass the test. +*/ + if (schedule_timeout_interruptible( + msecs_to_jiffies(F81534_DELAY_READ_MSR))) { + dev_info(>dev, "%s: breaked !!\n", __func__); + } Is the delay necessary or isn't it? If it is necessary you should do something about the signal. We add this delay due to stress test (Loop-back & 921600bps with BurnInTest). It'll receive MSR with some delay when connecting with DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to delay some time to pass the test. OK, but how do you guarantee the delay you need if you get a signal, which would abort the delay? Hmm, you are right. It seems to replace *_interruptible to *_killable and return -EINTR to guarantee not abort by normal signal. Thanks for your advices -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Andy Shevchenko 於 2015/11/3 下午 05:45 寫道: On Tue, Nov 3, 2015 at 5:51 AM, Peter Hung wrote: + *Please reference https://bitbucket.org/hpeter/fintek-general/src/ + *with f81534/tools to get set_gpio.c & set_mode.c. Please use it + *carefully. Would it be good to have this under Documentation ? I had some documents in source code. The link is the demo program to implement switch UART/PIN funcion. I'll try to add for document with the repository. +static void f81534_dtr_rts(struct usb_serial_port *port, int on); + +static int f81534_set_port_mode(struct usb_serial_port *port, + enum uart_mode eMode); + +static int f81534_save_configure_data(struct usb_serial_port *port); + +static int f81534_switch_gpio_mode(struct usb_serial_port *port, u8 mode); + +static void f81534_wakeup_all_port(struct usb_serial *serial); + +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, + bool is_port_open); + +static int f81534_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size); + +static int f81534_submit_writer(struct usb_serial_port *port, gfp_t mem_flags); Would it be possible to reshuffle code to reduce amount of forward declarations? I'll try to reduce it. + if ((size <= F81534_MAX_DATA_BLOCK) && + (read_size == (count + 1))) { No need to have internal parens. In my opinion, It makes more readable. Should I remove it? + if (baudrate <= 115200) { + value = 0x01; /* 1.846m fixed */ + divisor = f81534_calc_baud_divisor(baudrate, 115200, NULL); + port_priv->current_baud_base = 115200; + } else { + for (count = 0; count < ARRAY_SIZE(baudrate_table) ; ++count) { + baud_base = baudrate_table[count]; + divisor = f81534_calc_baud_divisor(baudrate, baud_base, + ); + if (!rem) { + dev_dbg(>dev, "%s: found clockbase %d\n", + __func__, + baudrate_table[count]); + value = clock_table[count]; + port_priv->current_baud_base = baud_base; + break; + } + } Can you calculate baud rates more precisely? Any link to datasheet where it's described? I'll try to comment it within source code. +static int f81534_ioctl_get_rs485(struct usb_serial_port *port, + struct serial_rs485 __user *arg) +{ + int status; + struct serial_rs485 data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + struct f81534_serial_private *serial_priv = + usb_get_serial_data(port->serial); One line? It's over 80 character with a tab, It cant be one line. I'll fix other issue that you mention. Thanks for your advices. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Oliver Neukum 於 2015/11/3 下午 06:03 寫道: On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote: +static int f81534_attach(struct usb_serial *serial) +{ + struct f81534_serial_private *serial_priv = NULL; + int status; + int i; + int offset; + uintptr_t setting_idx = (uintptr_t) usb_get_serial_data(serial); + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) + return -ENOMEM; + + usb_set_serial_data(serial, serial_priv); + serial_priv->setting_idx = setting_idx; + + for (i = 0; i < F81534_NUM_PORT; ++i) { + /* Disable all interrupt before submit URB */ + status = f81534_setregister(serial->dev, i, + INTERRUPT_ENABLE_REGISTER, 0x00); + if (status) { + dev_err(>dev->dev, "%s: IER disable failed\n", + __func__); + goto failed; + } + } + + for (i = 0; i < F81534_NUM_PORT; ++i) + atomic_set(_priv->port_active[i], 0); Should be ATOMIC_INIT() ATOMIC_INIT() seems to be used only for variable initializer, It cant be used for dynamic allocation. Should I change it to a normal boolean flag protecting with spin_lock ? +static int f81534_port_remove(struct usb_serial_port *port) +{ + struct f81534_port_private *port_priv; + + f81534_release_gpio(port); + port_priv = usb_get_serial_port_data(port); + kfree(port_priv); + return 0; +} + +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, Is the point of passing a pointer to msr locking? + bool is_port_open) This function is used only with URB callback function. The *msr is reported by H/W with newest MSR. The USB-Serial generic system will re-submit read URB when callback complete. So this function should run once on the same time. +static int f81534_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + unsigned long flags; + int r; + u8 msr, mcr; + + /* +* We'll avoid to direct read MSR register. The IC will read the MSR +* changed and report it f81534_process_per_serial_block() by +* F81534_TOKEN_MSR_CHANGE. +* +* When this device in heavy loading (e.g., BurnInTest Loopback Test) +* The report of MSR register will delay received a bit. It's due to +* MSR interrupt is lowest priority in 16550A. So we decide to sleep +* a little time to pass the test. +*/ + if (schedule_timeout_interruptible( + msecs_to_jiffies(F81534_DELAY_READ_MSR))) { + dev_info(>dev, "%s: breaked !!\n", __func__); + } Is the delay necessary or isn't it? If it is necessary you should do something about the signal. We add this delay due to stress test (Loop-back & 921600bps with BurnInTest). It'll receive MSR with some delay when connecting with DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to delay some time to pass the test. +static int f81534_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) +{ + unsigned char *ptr = (unsigned char *) dest; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + int port_num = port_priv->phy; + struct usb_serial *serial = port->serial; + + WARN_ON(size != serial->port[0]->bulk_out_size); + + if (size != F81534_WRITE_BUFFER_SIZE) { + WARN_ON(size != F81534_WRITE_BUFFER_SIZE); What is the sense of this? I'll remove the double-check section with next version patch. + ptr[F81534_RECEIVE_BLOCK_SIZE * 0] = 0; + ptr[F81534_RECEIVE_BLOCK_SIZE * 1] = 1; + ptr[F81534_RECEIVE_BLOCK_SIZE * 2] = 2; + ptr[F81534_RECEIVE_BLOCK_SIZE * 3] = 3; Either these ... + ptr[F81534_RECEIVE_BLOCK_SIZE * port_num + 0] = port_num; .. or that is redundant I'll remove it too. Thanks for your advice. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Peter Hung 於 2015/11/3 上午 11:51 寫道: > This driver is for Fintek F81532/F81534 USB to Serial Ports IC. > Changelog: > v6 > 1. Re-implement the write()/resume() function. Due to this device cant be > suitable with generic write(), we'll do the submit write URB when > write()/received tx empty/set_termios()/resume() > 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & > f81534_phy_to_logic_port(). > 3. Introduced "Port Hide" function. Some customer use F81532 reference > design for HW layout, but really use F81534 IC. We'll check > F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do > port hide with port not used. It can be avoid end-user to use not > layouted port. > 4. The 4x3 output-only open-drain pins for F81532/534 is designed for > control outer devices (with our EVB for examples, the 4 sets of pins > are designed to control transceiver mode). So we decide to implement > with gpiolib interface. I need to do some improvements with senior advices, so I'll send v7 patch when I modify & re-test the code complete. Could you give me some roughly advices of this patch when you having time. Thanks for your help -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi, Oliver Neukum 於 2015/11/4 下午 04:38 寫道: On Wed, 2015-11-04 at 16:19 +0800, Peter Hung wrote: Hi Oliver Neukum 於 2015/11/3 下午 06:03 寫道: On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote: + for (i = 0; i < F81534_NUM_PORT; ++i) + atomic_set(_priv->port_active[i], 0); Should be ATOMIC_INIT() ATOMIC_INIT() seems to be used only for variable initializer, It cant be used for dynamic allocation. Should I change it to a normal boolean flag protecting with spin_lock ? No, if it doesn't work, use the current code. OK, I'll use current code. +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, Is the point of passing a pointer to msr locking? + bool is_port_open) This function is used only with URB callback function. The *msr is reported by H/W with newest MSR. The USB-Serial generic system will re-submit read URB when callback complete. So this function should run once on the same time. Yes, so why don't you pass an u8 as opposed to a pointer to an u8? I'll re-write it from u8* to u8. +static int f81534_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + unsigned long flags; + int r; + u8 msr, mcr; + + /* +* We'll avoid to direct read MSR register. The IC will read the MSR +* changed and report it f81534_process_per_serial_block() by +* F81534_TOKEN_MSR_CHANGE. +* +* When this device in heavy loading (e.g., BurnInTest Loopback Test) +* The report of MSR register will delay received a bit. It's due to +* MSR interrupt is lowest priority in 16550A. So we decide to sleep +* a little time to pass the test. +*/ + if (schedule_timeout_interruptible( + msecs_to_jiffies(F81534_DELAY_READ_MSR))) { + dev_info(>dev, "%s: breaked !!\n", __func__); + } Is the delay necessary or isn't it? If it is necessary you should do something about the signal. We add this delay due to stress test (Loop-back & 921600bps with BurnInTest). It'll receive MSR with some delay when connecting with DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to delay some time to pass the test. OK, but how do you guarantee the delay you need if you get a signal, which would abort the delay? Hmm, you are right. It seems to replace *_interruptible to *_killable and return -EINTR to guarantee not abort by normal signal. Thanks for your advices -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Andy Shevchenko 於 2015/11/3 下午 05:45 寫道: On Tue, Nov 3, 2015 at 5:51 AM, Peter Hung <hpe...@gmail.com> wrote: + *Please reference https://bitbucket.org/hpeter/fintek-general/src/ + *with f81534/tools to get set_gpio.c & set_mode.c. Please use it + *carefully. Would it be good to have this under Documentation ? I had some documents in source code. The link is the demo program to implement switch UART/PIN funcion. I'll try to add for document with the repository. +static void f81534_dtr_rts(struct usb_serial_port *port, int on); + +static int f81534_set_port_mode(struct usb_serial_port *port, + enum uart_mode eMode); + +static int f81534_save_configure_data(struct usb_serial_port *port); + +static int f81534_switch_gpio_mode(struct usb_serial_port *port, u8 mode); + +static void f81534_wakeup_all_port(struct usb_serial *serial); + +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, + bool is_port_open); + +static int f81534_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size); + +static int f81534_submit_writer(struct usb_serial_port *port, gfp_t mem_flags); Would it be possible to reshuffle code to reduce amount of forward declarations? I'll try to reduce it. + if ((size <= F81534_MAX_DATA_BLOCK) && + (read_size == (count + 1))) { No need to have internal parens. In my opinion, It makes more readable. Should I remove it? + if (baudrate <= 115200) { + value = 0x01; /* 1.846m fixed */ + divisor = f81534_calc_baud_divisor(baudrate, 115200, NULL); + port_priv->current_baud_base = 115200; + } else { + for (count = 0; count < ARRAY_SIZE(baudrate_table) ; ++count) { + baud_base = baudrate_table[count]; + divisor = f81534_calc_baud_divisor(baudrate, baud_base, + ); + if (!rem) { + dev_dbg(>dev, "%s: found clockbase %d\n", + __func__, + baudrate_table[count]); + value = clock_table[count]; + port_priv->current_baud_base = baud_base; + break; + } + } Can you calculate baud rates more precisely? Any link to datasheet where it's described? I'll try to comment it within source code. +static int f81534_ioctl_get_rs485(struct usb_serial_port *port, + struct serial_rs485 __user *arg) +{ + int status; + struct serial_rs485 data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + struct f81534_serial_private *serial_priv = + usb_get_serial_data(port->serial); One line? It's over 80 character with a tab, It cant be one line. I'll fix other issue that you mention. Thanks for your advices. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
Hi Oliver Neukum 於 2015/11/3 下午 06:03 寫道: On Tue, 2015-11-03 at 11:51 +0800, Peter Hung wrote: +static int f81534_attach(struct usb_serial *serial) +{ + struct f81534_serial_private *serial_priv = NULL; + int status; + int i; + int offset; + uintptr_t setting_idx = (uintptr_t) usb_get_serial_data(serial); + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) + return -ENOMEM; + + usb_set_serial_data(serial, serial_priv); + serial_priv->setting_idx = setting_idx; + + for (i = 0; i < F81534_NUM_PORT; ++i) { + /* Disable all interrupt before submit URB */ + status = f81534_setregister(serial->dev, i, + INTERRUPT_ENABLE_REGISTER, 0x00); + if (status) { + dev_err(>dev->dev, "%s: IER disable failed\n", + __func__); + goto failed; + } + } + + for (i = 0; i < F81534_NUM_PORT; ++i) + atomic_set(_priv->port_active[i], 0); Should be ATOMIC_INIT() ATOMIC_INIT() seems to be used only for variable initializer, It cant be used for dynamic allocation. Should I change it to a normal boolean flag protecting with spin_lock ? +static int f81534_port_remove(struct usb_serial_port *port) +{ + struct f81534_port_private *port_priv; + + f81534_release_gpio(port); + port_priv = usb_get_serial_port_data(port); + kfree(port_priv); + return 0; +} + +static void f81534_compare_msr(struct usb_serial_port *port, u8 *msr, Is the point of passing a pointer to msr locking? + bool is_port_open) This function is used only with URB callback function. The *msr is reported by H/W with newest MSR. The USB-Serial generic system will re-submit read URB when callback complete. So this function should run once on the same time. +static int f81534_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + unsigned long flags; + int r; + u8 msr, mcr; + + /* +* We'll avoid to direct read MSR register. The IC will read the MSR +* changed and report it f81534_process_per_serial_block() by +* F81534_TOKEN_MSR_CHANGE. +* +* When this device in heavy loading (e.g., BurnInTest Loopback Test) +* The report of MSR register will delay received a bit. It's due to +* MSR interrupt is lowest priority in 16550A. So we decide to sleep +* a little time to pass the test. +*/ + if (schedule_timeout_interruptible( + msecs_to_jiffies(F81534_DELAY_READ_MSR))) { + dev_info(>dev, "%s: breaked !!\n", __func__); + } Is the delay necessary or isn't it? If it is necessary you should do something about the signal. We add this delay due to stress test (Loop-back & 921600bps with BurnInTest). It'll receive MSR with some delay when connecting with DTR-DSR & RTS/CTS, but the delay smaller than 10ms. So we decided to delay some time to pass the test. +static int f81534_prepare_write_buffer(struct usb_serial_port *port, + void *dest, size_t size) +{ + unsigned char *ptr = (unsigned char *) dest; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + int port_num = port_priv->phy; + struct usb_serial *serial = port->serial; + + WARN_ON(size != serial->port[0]->bulk_out_size); + + if (size != F81534_WRITE_BUFFER_SIZE) { + WARN_ON(size != F81534_WRITE_BUFFER_SIZE); What is the sense of this? I'll remove the double-check section with next version patch. + ptr[F81534_RECEIVE_BLOCK_SIZE * 0] = 0; + ptr[F81534_RECEIVE_BLOCK_SIZE * 1] = 1; + ptr[F81534_RECEIVE_BLOCK_SIZE * 2] = 2; + ptr[F81534_RECEIVE_BLOCK_SIZE * 3] = 3; Either these ... + ptr[F81534_RECEIVE_BLOCK_SIZE * port_num + 0] = port_num; .. or that is redundant I'll remove it too. Thanks for your advice. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by ioctl TIOCGRS485/TIOCSRS485 If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So it implements as gpiolib interface with output-only function. 5. It'll save the configuration in internal storage when uart/pins mode changed. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung --- Changelog: v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. v5 1. Change the configure data address F81534_CUSTOM_ADDRESS_START from 0x4000 to 0x2f00 (for MP F/W ver:AA66) 2. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 3. Some function modifier add with static (Thanks for Paul Bolle) 4. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 2991 +++ 3 files changed, 3002 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate "USB Fintek F81532/534 Multi-Ports Serial Driver" + help + Say Y here if you want to use the Fintek F81532/534 Multi-Ports + usb to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called f81534. + + config USB_SERIAL_GARMIN tristate "USB Garmin GPS driver" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 349d9df..9e43b7b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_F81232)
[PATCH V6 1/1] usb:serial: Add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by ioctl TIOCGRS485/TIOCSRS485 If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So it implements as gpiolib interface with output-only function. 5. It'll save the configuration in internal storage when uart/pins mode changed. Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c to change F81532/534 setting. Please use it carefully. Signed-off-by: Peter Hung <hpeter+linux_ker...@gmail.com> --- Changelog: v6 1. Re-implement the write()/resume() function. Due to this device cant be suitable with generic write(), we'll do the submit write URB when write()/received tx empty/set_termios()/resume() 2. Logic/Phy Port mapping rewrite in f81534_port_probe() & f81534_phy_to_logic_port(). 3. Introduced "Port Hide" function. Some customer use F81532 reference design for HW layout, but really use F81534 IC. We'll check F81534_PORT_CONF_DISABLE_PORT flag with in uart mode field to do port hide with port not used. It can be avoid end-user to use not layouted port. 4. The 4x3 output-only open-drain pins for F81532/534 is designed for control outer devices (with our EVB for examples, the 4 sets of pins are designed to control transceiver mode). So we decide to implement with gpiolib interface. v5 1. Change the configure data address F81534_CUSTOM_ADDRESS_START from 0x4000 to 0x2f00 (for MP F/W ver:AA66) 2. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 3. Some function modifier add with static (Thanks for Paul Bolle) 4. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 2991 +++ 3 files changed, 3002 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate "USB Fintek F81532/534 Multi-Ports Serial Driver" + help + Say Y here if you want to use the Fintek F81532/534 Multi-Ports + usb to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called f81534. + + config USB_SERIAL_GARMIN tristate "USB Garmin GPS driver" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 349d9df..9e43b7b 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SE
Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
Hi Johan, Johan Hovold 於 2015/9/14 下午 09:33 寫道: On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote: 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 I don't think all gpios should be exported for these ports if they have special functions that the driver could control transparently (e.g. for SER_RS485_RTS_ON_SEND). Surely, we can hide some setting with definitely setting like RS232/RS485, but the settings is only apply to our evaluation board. Some customers will use our F81532/534 with other brand transceiver IC. The pins setting maybe changed, so we decided to separate UART & pins settings and let the 3 output pins controllable for customer. Could I preserve currently UART & pins setting mode ? + current_mode &= BIT(gpio_num); + + mutex_unlock(_priv->change_mode_mutex); + f81534_wakeup_all_port(port->serial); + + return !!current_mode; +} Your gpio implementation looks wrong, but let's get back to that after you explain how these pins are used. If they are not really general purpose pins, then this isn't the right interface. The 4x3 pins is output-only mode to control transceiver, so I'm only implement the output functions and let all input functions failed. Could you give some advices to me if the gpiolib interface cant be used ? Sorry for late reply, I'm almost ready to submit v6 when clarify some questions. Thanks, -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
Hi Johan, Johan Hovold 於 2015/9/14 下午 09:33 寫道: On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote: 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 I don't think all gpios should be exported for these ports if they have special functions that the driver could control transparently (e.g. for SER_RS485_RTS_ON_SEND). Surely, we can hide some setting with definitely setting like RS232/RS485, but the settings is only apply to our evaluation board. Some customers will use our F81532/534 with other brand transceiver IC. The pins setting maybe changed, so we decided to separate UART & pins settings and let the 3 output pins controllable for customer. Could I preserve currently UART & pins setting mode ? + current_mode &= BIT(gpio_num); + + mutex_unlock(_priv->change_mode_mutex); + f81534_wakeup_all_port(port->serial); + + return !!current_mode; +} Your gpio implementation looks wrong, but let's get back to that after you explain how these pins are used. If they are not really general purpose pins, then this isn't the right interface. The 4x3 pins is output-only mode to control transceiver, so I'm only implement the output functions and let all input functions failed. Could you give some advices to me if the gpiolib interface cant be used ? Sorry for late reply, I'm almost ready to submit v6 when clarify some questions. Thanks, -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
Johan Hovold 於 2015/9/14 下午 09:33 寫道: > On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote: >> This driver is for Fintek F81532/F81534 USB to Serial Ports IC. >> > So as I mentioned above, always accept data if there's room in the fifo. > Then kick of a write urb, if TX_EMPTY is set for any of the ports and > fill the urb based on those flags as well. > I'll try to improve it with V6, but it'll need more time to do modification & verification. So V6 will release lately. Thank you for your advice. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
Johan Hovold 於 2015/9/14 下午 09:33 寫道: > On Tue, Jul 21, 2015 at 09:58:19AM +0800, Peter Hung wrote: >> This driver is for Fintek F81532/F81534 USB to Serial Ports IC. >> > So as I mentioned above, always accept data if there's room in the fifo. > Then kick of a write urb, if TX_EMPTY is set for any of the ports and > fill the urb based on those flags as well. > I'll try to improve it with V6, but it'll need more time to do modification & verification. So V6 will release lately. Thank you for your advice. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/1] serial: 8250_pci: fix mode after S3/S4 resume for F81504/508/512
Fix RS232/485 mode incorrect setting after S3/S4 resume for F81504/508/512 We had add RS232/485 RTS control with fecf27a373f5. But when it resume from S3/S4, the mode register 0x40 + 0x08 * idx + 7 will rewrite to 0x01 (RS232 mode). This patch will modify 2 sections. One is pci_fintek_init(), if it called when first init, it will write mode register with 0x01. If it called from S3/S4 resume, it's will get the relative port data and pass it to pci_fintek_rs485_config() with NULL rs485 parameter. The another modification is in pci_fintek_rs485_config(). It'll re-apply old configuration when the parameter rs485 is NULL. Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 25 + 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e12e911..68042dd 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1705,7 +1705,9 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); - if (rs485->flags & SER_RS485_ENABLED) + if (!rs485) + rs485 = >rs485; + else if (rs485->flags & SER_RS485_ENABLED) memset(rs485->padding, 0, sizeof(rs485->padding)); else memset(rs485, 0, sizeof(*rs485)); @@ -1733,7 +1735,10 @@ static int pci_fintek_rs485_config(struct uart_port *port, } pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - port->rs485 = *rs485; + + if (rs485 != >rs485) + port->rs485 = *rs485; + return 0; } @@ -1774,6 +1779,8 @@ static int pci_fintek_init(struct pci_dev *dev) u32 max_port, i; u32 bar_data[3]; u8 config_base; + struct serial_private *priv = pci_get_drvdata(dev); + struct uart_8250_port *port; switch (dev->device) { case 0x1104: /* 4 ports */ @@ -1815,8 +1822,18 @@ static int pci_fintek_init(struct pci_dev *dev) pci_write_config_byte(dev, config_base + 0x06, dev->irq); - /* force init to RS232 Mode */ - pci_write_config_byte(dev, config_base + 0x07, 0x01); + if (priv) { + /* re-apply RS232/485 mode when +* pciserial_resume_ports() +*/ + port = serial8250_get_port(priv->line[i]); + pci_fintek_rs485_config(>port, NULL); + } else { + /* First init without port data +* force init to RS232 Mode +*/ + pci_write_config_byte(dev, config_base + 0x07, 0x01); + } } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/1] serial: 8250_pci: fix mode after S3/S4 resume for F81504/508/512
Fix RS232/485 mode incorrect setting after S3/S4 resume for F81504/508/512 We had add RS232/485 RTS control with fecf27a373f5. But when it resume from S3/S4, the mode register 0x40 + 0x08 * idx + 7 will rewrite to 0x01 (RS232 mode). This patch will modify 2 sections. One is pci_fintek_init(), if it called when first init, it will write mode register with 0x01. If it called from S3/S4 resume, it's will get the relative port data and pass it to pci_fintek_rs485_config() with NULL rs485 parameter. The another modification is in pci_fintek_rs485_config(). It'll re-apply old configuration when the parameter rs485 is NULL. Signed-off-by: Peter Hung hpeter+linux_ker...@gmail.com --- drivers/tty/serial/8250/8250_pci.c | 25 + 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e12e911..68042dd 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1705,7 +1705,9 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - if (rs485-flags SER_RS485_ENABLED) + if (!rs485) + rs485 = port-rs485; + else if (rs485-flags SER_RS485_ENABLED) memset(rs485-padding, 0, sizeof(rs485-padding)); else memset(rs485, 0, sizeof(*rs485)); @@ -1733,7 +1735,10 @@ static int pci_fintek_rs485_config(struct uart_port *port, } pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - port-rs485 = *rs485; + + if (rs485 != port-rs485) + port-rs485 = *rs485; + return 0; } @@ -1774,6 +1779,8 @@ static int pci_fintek_init(struct pci_dev *dev) u32 max_port, i; u32 bar_data[3]; u8 config_base; + struct serial_private *priv = pci_get_drvdata(dev); + struct uart_8250_port *port; switch (dev-device) { case 0x1104: /* 4 ports */ @@ -1815,8 +1822,18 @@ static int pci_fintek_init(struct pci_dev *dev) pci_write_config_byte(dev, config_base + 0x06, dev-irq); - /* force init to RS232 Mode */ - pci_write_config_byte(dev, config_base + 0x07, 0x01); + if (priv) { + /* re-apply RS232/485 mode when +* pciserial_resume_ports() +*/ + port = serial8250_get_port(priv-line[i]); + pci_fintek_rs485_config(port-port, NULL); + } else { + /* First init without port data +* force init to RS232 Mode +*/ + pci_write_config_byte(dev, config_base + 0x07, 0x01); + } } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Add RS485 control for Fintek F81504/508/512 F81504/508/512 can control their RTS with H/W mode. PCI configuration space for each port is 0x40 + idx * 8 + 7. When it set with 0x01, it's configured with RS232 mode. RTS is controlled by MCR. When it set with 0x11, it's configured with RS485 mode. RTS is controlled by H/W, RTS low with idle & RX, high with TX. When it set with 0x31, it's configured with RS485 mode. RTS is controlled by H/W, RTS high with idle & RX, low with TX. We will force 0x01 on pci_fintek_setup(). Changelog: V2 1. change direct bit operation with meaningful define name. 2. due to F81504 series only support SER_RS485_ENABLED & SER_RS485_RTS_ON_SEND. We'll clean non-support area of struct serial_rs485. 3. change control method of SER_RS485_RTS_ON_SEND. In our reference circuit, the transceiver default mode needed in rx mode with RTS logic high, tx mode with RTS logic low. If user set to SER_RS485_ENABLED(default), we should set reg with 0x31. if SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND will set reg to 0x11. Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 61 ++ 1 file changed, 61 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e55f18b..5d16e14 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,11 +1685,60 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +/* RTS will control by MCR if this bit is 0 */ +#define FINTEK_RTS_CONTROL_BY_HW BIT(4) +/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ +#define FINTEK_RTS_INVERT BIT(5) + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, + dev); + + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); + + if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= FINTEK_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~FINTEK_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= FINTEK_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + port->rs485 = *rs485; + return 0; +} + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1751,15 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; + port->port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port->port.private_data = data; return 0; } @@ -1752,6 +1810,9 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase & 0xff00) >> 8)); pci_write_config_byte(dev, config_base + 0x06, dev->irq); + + /* force init to RS232 Mode */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Hi Jakub Kiciński, Jakub Kiciński 於 2015/7/25 下午 05:35 寫道: Please make sure you correct the rs485 configuration with what you can actually support. Look at 8250_lpc18xx.c as an example. In your case when the function returns it should have SER_RS485_ENABLED and one of SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND set and nothing else (or be completely zeroed if SER_RS485_ENABLED was not set). Thanks for your advice, I'll fix it and re-send patch -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Hi Jakub Kiciński, Jakub Kiciński 於 2015/7/25 下午 05:35 寫道: Please make sure you correct the rs485 configuration with what you can actually support. Look at 8250_lpc18xx.c as an example. In your case when the function returns it should have SER_RS485_ENABLED and one of SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND set and nothing else (or be completely zeroed if SER_RS485_ENABLED was not set). Thanks for your advice, I'll fix it and re-send patch -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Add RS485 control for Fintek F81504/508/512 F81504/508/512 can control their RTS with H/W mode. PCI configuration space for each port is 0x40 + idx * 8 + 7. When it set with 0x01, it's configured with RS232 mode. RTS is controlled by MCR. When it set with 0x11, it's configured with RS485 mode. RTS is controlled by H/W, RTS low with idle RX, high with TX. When it set with 0x31, it's configured with RS485 mode. RTS is controlled by H/W, RTS high with idle RX, low with TX. We will force 0x01 on pci_fintek_setup(). Changelog: V2 1. change direct bit operation with meaningful define name. 2. due to F81504 series only support SER_RS485_ENABLED SER_RS485_RTS_ON_SEND. We'll clean non-support area of struct serial_rs485. 3. change control method of SER_RS485_RTS_ON_SEND. In our reference circuit, the transceiver default mode needed in rx mode with RTS logic high, tx mode with RTS logic low. If user set to SER_RS485_ENABLED(default), we should set reg with 0x31. if SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND will set reg to 0x11. Signed-off-by: Peter Hung hpeter+linux_ker...@gmail.com --- drivers/tty/serial/8250/8250_pci.c | 61 ++ 1 file changed, 61 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e55f18b..5d16e14 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,11 +1685,60 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +/* RTS will control by MCR if this bit is 0 */ +#define FINTEK_RTS_CONTROL_BY_HW BIT(4) +/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ +#define FINTEK_RTS_INVERT BIT(5) + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port-private_data; + struct pci_dev *pci_dev = container_of(port-dev, struct pci_dev, + dev); + + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + + if (rs485-flags SER_RS485_ENABLED) + memset(rs485-padding, 0, sizeof(rs485-padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485-flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485-flags SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= FINTEK_RTS_CONTROL_BY_HW; + + if (rs485-flags SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting = ~FINTEK_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= FINTEK_RTS_INVERT; + } + + rs485-delay_rts_after_send = 0; + rs485-delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting = ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + port-rs485 = *rs485; + return 0; +} + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv-dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1751,15 @@ static int pci_fintek_setup(struct serial_private *priv, port-port.iotype = UPIO_PORT; port-port.iobase = iobase; + port-port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(pdev-dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port-port.private_data = data; return 0; } @@ -1752,6 +1810,9 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase 0xff00) 8)); pci_write_config_byte(dev, config_base + 0x06, dev-irq); + + /* force init to RS232 Mode */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Add RS485 control for Fintek F81504/508/512 F81504/508/512 can control their RTS with H/W mode. PCI configuration space for each port is 0x40 + idx * 8 + 7. When it set with 0x01, it's configured with RS232 mode. RTS is controlled by MCR. When it set with 0x11, it's configured with RS485 mode. RTS is controlled by H/W, RTS high with idle & RX, low with TX. When it set with 0x31, it's configured with RS485 mode. RTS is controlled by H/W, RTS low with idle & RX, high with TX. We will force 0x01 on pci_fintek_setup(). Signed-off-by: Peter Hung --- drivers/tty/serial/8250/8250_pci.c | 44 ++ 1 file changed, 44 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e55f18b..36280fa 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,11 +1685,43 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, + dev); + + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, ); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= BIT(4); + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting |= BIT(5); + } else { + /* RTS driving low on TX */ + setting &= ~BIT(5); + } + } else { + /* Disable RTS H/W control mode */ + setting &= ~(BIT(4) | BIT(5)); + } + + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + port->rs485 = *rs485; + return 0; +} + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1734,15 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; + port->port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(>dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port->port.private_data = data; return 0; } @@ -1752,6 +1793,9 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase & 0xff00) >> 8)); pci_write_config_byte(dev, config_base + 0x06, dev->irq); + + /* force init to RS232 Mode */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/1] serial: 8250_pci: add RS485 for F81504/508/512
Add RS485 control for Fintek F81504/508/512 F81504/508/512 can control their RTS with H/W mode. PCI configuration space for each port is 0x40 + idx * 8 + 7. When it set with 0x01, it's configured with RS232 mode. RTS is controlled by MCR. When it set with 0x11, it's configured with RS485 mode. RTS is controlled by H/W, RTS high with idle RX, low with TX. When it set with 0x31, it's configured with RS485 mode. RTS is controlled by H/W, RTS low with idle RX, high with TX. We will force 0x01 on pci_fintek_setup(). Signed-off-by: Peter Hung hpeter+linux_ker...@gmail.com --- drivers/tty/serial/8250/8250_pci.c | 44 ++ 1 file changed, 44 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e55f18b..36280fa 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,11 +1685,43 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port-private_data; + struct pci_dev *pci_dev = container_of(port-dev, struct pci_dev, + dev); + + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + + if (rs485-flags SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= BIT(4); + + if (rs485-flags SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting |= BIT(5); + } else { + /* RTS driving low on TX */ + setting = ~BIT(5); + } + } else { + /* Disable RTS H/W control mode */ + setting = ~(BIT(4) | BIT(5)); + } + + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + port-rs485 = *rs485; + return 0; +} + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv-dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1734,15 @@ static int pci_fintek_setup(struct serial_private *priv, port-port.iotype = UPIO_PORT; port-port.iobase = iobase; + port-port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(pdev-dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port-port.private_data = data; return 0; } @@ -1752,6 +1793,9 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase 0xff00) 8)); pci_write_config_byte(dev, config_base + 0x06, dev-irq); + + /* force init to RS232 Mode */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); } return max_port; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by default ioctl TIOCGRS485/TIOCSRS485 (for RS232/RS485/RS422 with transceiver) If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. There are 4x3 output-only ic pins to control transceiver mode. It's can be controlled via gpiolib. We could found the gpio number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where x is F81532/534 serial port and yyy is gpiochip number. After we found chip number, we can export 3 gpios(M2/M1/M0) per serial port by echo yyy > /sys/class/gpio/export echo yyy+1 > /sys/class/gpio/export echo yyy+2 > /sys/class/gpio/export then we can control it with echo [M0 value] > /sys/class/gpio/gpio[yyy]/value echo [M1 value] > /sys/class/gpio/gpio[yyy+1]/value echo [M2 value] > /sys/class/gpio/gpio[yyy+2]/value which M0/M1/M2 as your desired value, value is only 0 or 1. When configure complete, It's a must to free all gpio by echo yyy > /sys/class/gpio/unexport echo yyy+1 > /sys/class/gpio/unexport echo yyy+2 > /sys/class/gpio/unexport The driver will "save" gpio configure after we release all gpio of a serial port. For examples to change mode & gpio with F81532/534 Evalaution Board. F81532 EVB port0: F81437 (RS232 only) port1: F81439 (RS232/RS485/RS422 ... etc.) F81534 EVB port0/1: F81437 (RS232 only) port2/3: F81439 (RS232/RS485/RS422 ... etc.) 1. RS232 Mode (Default IC Mode) 1. Set struct serial_rs485 flags "without" SER_RS485_ENABLED (control F81532/534 RTS control) 2. Set M2/M1/M0 as 0/0/1 (control F81532/534 output pin to control transceiver mode) 2. RS485 Mode (RTS Low when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED 2. Set M2/M1/M0 as 0/1/0 3. RS485 Mode (RTS High when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and SER_RS485_RTS_ON_SEND 2. Set M2/M1/M0 as 0/1/1 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c. Please use it carefully. Changelog v5 1. Change the configure data address F81534_CUSTOM_ADDRESS_START from 0x4000 to 0x2f00 (for MP F/W ver:AA66) 2. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 3. Some function modifier add with static (Thanks for Paul Bolle) 4. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands Signed-off-by: Peter Hung --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 3279 +++ 3 files changed, 3290 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate
[PATCH V5 1/1] usb:serial add Fintek F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by default ioctl TIOCGRS485/TIOCSRS485 (for RS232/RS485/RS422 with transceiver) If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. There are 4x3 output-only ic pins to control transceiver mode. It's can be controlled via gpiolib. We could found the gpio number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where x is F81532/534 serial port and yyy is gpiochip number. After we found chip number, we can export 3 gpios(M2/M1/M0) per serial port by echo yyy /sys/class/gpio/export echo yyy+1 /sys/class/gpio/export echo yyy+2 /sys/class/gpio/export then we can control it with echo [M0 value] /sys/class/gpio/gpio[yyy]/value echo [M1 value] /sys/class/gpio/gpio[yyy+1]/value echo [M2 value] /sys/class/gpio/gpio[yyy+2]/value which M0/M1/M2 as your desired value, value is only 0 or 1. When configure complete, It's a must to free all gpio by echo yyy /sys/class/gpio/unexport echo yyy+1 /sys/class/gpio/unexport echo yyy+2 /sys/class/gpio/unexport The driver will save gpio configure after we release all gpio of a serial port. For examples to change mode gpio with F81532/534 Evalaution Board. F81532 EVB port0: F81437 (RS232 only) port1: F81439 (RS232/RS485/RS422 ... etc.) F81534 EVB port0/1: F81437 (RS232 only) port2/3: F81439 (RS232/RS485/RS422 ... etc.) 1. RS232 Mode (Default IC Mode) 1. Set struct serial_rs485 flags without SER_RS485_ENABLED (control F81532/534 RTS control) 2. Set M2/M1/M0 as 0/0/1 (control F81532/534 output pin to control transceiver mode) 2. RS485 Mode (RTS Low when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED 2. Set M2/M1/M0 as 0/1/0 3. RS485 Mode (RTS High when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and SER_RS485_RTS_ON_SEND 2. Set M2/M1/M0 as 0/1/1 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c set_mode.c. Please use it carefully. Changelog v5 1. Change the configure data address F81534_CUSTOM_ADDRESS_START from 0x4000 to 0x2f00 (for MP F/W ver:AA66) 2. Change f81534_port_disable/enable() from H/W mode to S/W mode It'll skip all rx data when port is not opened. 3. Some function modifier add with static (Thanks for Paul Bolle) 4. It's will direct return when count=0 in f81534_write() to reduce spin_lock usage. v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code re-submit it to correct subsystem 2. Remove all custom ioctl commands Signed-off-by: Peter Hung hpeter+linux_ker...@gmail.com --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 3279 +++ 3 files changed, 3290 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate USB Fintek F81532/534 Multi-Ports Serial Driver + help
Re: [PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver
Hi Paul & Johan Paul Bolle 於 2015/7/15 下午 04:36 寫道: Just a few nits, I'm afraid. +int f81534_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + [...] +} static? Thanks Paul for point this out. And sorry for Johan. It's seems to make a new patch V5. I'll merge some minor fix with newer patch. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver
Hi Paul Johan Paul Bolle 於 2015/7/15 下午 04:36 寫道: Just a few nits, I'm afraid. +int f81534_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + [...] +} static? Thanks Paul for point this out. And sorry for Johan. It's seems to make a new patch V5. I'll merge some minor fix with newer patch. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 & F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by default ioctl TIOCGRS485/TIOCSRS485 (for RS232/RS485/RS422 with transceiver) If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. There are 4x3 output-only ic pins to control transceiver mode. It's can be controlled via gpiolib. We could found the gpio number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where x is F81532/534 serial port and yyy is gpiochip number. After we found chip number, we can export 3 gpios(M2/M1/M0) per serial port by echo yyy > /sys/class/gpio/export echo yyy+1 > /sys/class/gpio/export echo yyy+2 > /sys/class/gpio/export then we can control it with echo [M0 value] > /sys/class/gpio/gpio[yyy]/value echo [M1 value] > /sys/class/gpio/gpio[yyy+1]/value echo [M2 value] > /sys/class/gpio/gpio[yyy+2]/value which M0/M1/M2 as your desired value, value is only 0 or 1. When configure complete, It's a must to free all gpio by echo yyy > /sys/class/gpio/unexport echo yyy+1 > /sys/class/gpio/unexport echo yyy+2 > /sys/class/gpio/unexport The driver will "save" gpio configure after we release all gpio of a serial port. For examples to change mode & gpio with F81532/534 Evalaution Board. F81532 EVB port0: F81437 (RS232 only) port1: F81439 (RS232/RS485/RS422 ... etc.) F81534 EVB port0/1: F81437 (RS232 only) port2/3: F81439 (RS232/RS485/RS422 ... etc.) 1. RS232 Mode (Default IC Mode) 1. Set struct serial_rs485 flags "without" SER_RS485_ENABLED (control F81532/534 RTS control) 2. Set M2/M1/M0 as 0/0/1 (control F81532/534 output pin to control transceiver mode) 2. RS485 Mode (RTS Low when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED 2. Set M2/M1/M0 as 0/1/0 3. RS485 Mode (RTS High when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and SER_RS485_RTS_ON_SEND 2. Set M2/M1/M0 as 0/1/1 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c & set_mode.c. Please use it carefully. Changelog v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code & re-submit it to correct subsystem 2. Remove all custom ioctl commands Signed-off-by: Peter Hung --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 3315 +++ 3 files changed, 3326 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate "USB Fintek F81532/534 Multi-Ports Serial Driver" + help + Say Y here if you want to use the Fintek F81532/534 Multi-Ports + usb to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called f81534. + + config USB_SERIAL_GARMIN tristate "USB Garmin GPS driver" help diff --git a/drivers/usb/serial/Makefile b
[PATCH V4 1/1] usb:serial:f81534 add F81532/534 driver
This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Features: 1. F81534 is 1-to-4 F81532 is 1-to-2 serial ports IC 2. Support Baudrate from B50 to B150 (excluding B100). 3. The RTS signal can be transformed their behavior with configuration by default ioctl TIOCGRS485/TIOCSRS485 (for RS232/RS485/RS422 with transceiver) If the driver setting with SER_RS485_ENABLED, the RTS signal will high with not in TX and low with in TX. If the driver setting with SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND, the RTS signal will low with not in TX and high with in TX. 4. There are 4x3 output-only ic pins to control transceiver mode. It's can be controlled via gpiolib. We could found the gpio number from /sys/class/tty/ttyUSB[x]/device/gpiochap[yyy] where x is F81532/534 serial port and yyy is gpiochip number. After we found chip number, we can export 3 gpios(M2/M1/M0) per serial port by echo yyy /sys/class/gpio/export echo yyy+1 /sys/class/gpio/export echo yyy+2 /sys/class/gpio/export then we can control it with echo [M0 value] /sys/class/gpio/gpio[yyy]/value echo [M1 value] /sys/class/gpio/gpio[yyy+1]/value echo [M2 value] /sys/class/gpio/gpio[yyy+2]/value which M0/M1/M2 as your desired value, value is only 0 or 1. When configure complete, It's a must to free all gpio by echo yyy /sys/class/gpio/unexport echo yyy+1 /sys/class/gpio/unexport echo yyy+2 /sys/class/gpio/unexport The driver will save gpio configure after we release all gpio of a serial port. For examples to change mode gpio with F81532/534 Evalaution Board. F81532 EVB port0: F81437 (RS232 only) port1: F81439 (RS232/RS485/RS422 ... etc.) F81534 EVB port0/1: F81437 (RS232 only) port2/3: F81439 (RS232/RS485/RS422 ... etc.) 1. RS232 Mode (Default IC Mode) 1. Set struct serial_rs485 flags without SER_RS485_ENABLED (control F81532/534 RTS control) 2. Set M2/M1/M0 as 0/0/1 (control F81532/534 output pin to control transceiver mode) 2. RS485 Mode (RTS Low when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED 2. Set M2/M1/M0 as 0/1/0 3. RS485 Mode (RTS High when TX Mode) 1. Set struct serial_rs485 flags with SER_RS485_ENABLED and SER_RS485_RTS_ON_SEND 2. Set M2/M1/M0 as 0/1/1 4. RS422 Mode 1. The RTS mode is dont care. 2. Set M2/M1/M0 as 0/0/0 Please reference https://bitbucket.org/hpeter/fintek-general/src/ with f81534/tools to get set_gpio.c set_mode.c. Please use it carefully. Changelog v4 1. clearify f81534_process_read_urb() with f81534_process_per_serial_block(). (referenced from mxuport.c) 2. We limited f81534_write() max tx kfifo with 124Bytes. Original subsystem is designed for auto tranmiting fifo data if available. But we must wait for tx_empty for next tx data (H/W design). With this kfifo size limit, we can use generic subsystem api with f81534_write(). When usb_serial_generic_write_start() called after first write URB complete, the fifo will no data. The generic subsystem of write will go to idle state. Until we received TX_EMPTY and release write spinlock, the fifo will fill max 124Bytes by following f81534_write(). v3 1. Migrate read, write and some routine from custom code to usbserial subsystem callback function. 2. Use more defines to replece magic numbers to make it meaningful 3. Make more comments as document in source code. v2 1. v1 version submit to staging tree, but Greg KH advised me to cleanup source code re-submit it to correct subsystem 2. Remove all custom ioctl commands Signed-off-by: Peter Hung hpeter+linux_ker...@gmail.com --- drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile |1 + drivers/usb/serial/f81534.c | 3315 +++ 3 files changed, 3326 insertions(+) create mode 100644 drivers/usb/serial/f81534.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 56ecb8b..0642864 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -255,6 +255,16 @@ config USB_SERIAL_F81232 To compile this driver as a module, choose M here: the module will be called f81232. +config USB_SERIAL_F8153X + tristate USB Fintek F81532/534 Multi-Ports Serial Driver + help + Say Y here if you want to use the Fintek F81532/534 Multi-Ports + usb to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called f81534. + + config USB_SERIAL_GARMIN tristate USB Garmin GPS driver help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 349d9df..9e43b7b 100644 --- a/drivers/usb
Re: [PATCH V3 1/1] usb:serial:f81534 add F81532/534 driver
Hi Johan, Peter Hung 於 2015/7/9 上午 11:15 寫道: > This driver is for Fintek F81532/F81534 USB to Serial Ports IC. > Please pending for the driver, I found a problem with prepare_write_buffer(). The driver submit write block size != real tx send size. It's will ok on transmitting small mount data, but it's will fail on transmitting large mount data. I'll fix for this problem and re-send patch. Sorry for found bug so lately. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3 1/1] usb:serial:f81534 add F81532/534 driver
Hi Johan, Peter Hung 於 2015/7/9 上午 11:15 寫道: This driver is for Fintek F81532/F81534 USB to Serial Ports IC. Please pending for the driver, I found a problem with prepare_write_buffer(). The driver submit write block size != real tx send size. It's will ok on transmitting small mount data, but it's will fail on transmitting large mount data. I'll fix for this problem and re-send patch. Sorry for found bug so lately. -- With Best Regards, Peter Hung -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/