Re: [PATCH] usb:serial: Add Fintek F81532/534 driver

2016-05-30 Thread Peter Hung

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

2016-05-30 Thread Peter Hung

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

2016-03-01 Thread Peter Hung

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

2016-03-01 Thread Peter Hung

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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-22 Thread Peter Hung
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

2016-02-17 Thread Peter Hung

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

2016-02-17 Thread Peter Hung

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

2016-02-17 Thread Peter Hung

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

2016-02-17 Thread Peter Hung

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

2016-02-15 Thread Peter Hung

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

2016-02-15 Thread Peter Hung

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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-02-15 Thread Peter Hung
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

2016-01-31 Thread Peter Hung

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

2016-01-31 Thread Peter Hung

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

2016-01-31 Thread Peter Hung

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

2016-01-31 Thread Peter Hung

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

2016-01-29 Thread Peter Hung

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

2016-01-29 Thread Peter Hung

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

2016-01-29 Thread Peter Hung

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

2016-01-29 Thread Peter Hung

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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung

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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung
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

2016-01-28 Thread Peter Hung

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

2016-01-28 Thread Peter Hung
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

2016-01-27 Thread Peter Hung
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

2016-01-27 Thread Peter Hung
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

2016-01-22 Thread Peter Hung

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

2016-01-22 Thread Peter Hung

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

2016-01-21 Thread Peter Hung
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

2016-01-21 Thread Peter Hung
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

2016-01-21 Thread Peter Hung
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

2016-01-21 Thread Peter Hung
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

2015-12-27 Thread Peter Hung

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

2015-12-27 Thread Peter Hung

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

2015-12-14 Thread Peter Hung

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

2015-12-14 Thread Peter Hung

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

2015-12-01 Thread Peter Hung
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

2015-12-01 Thread Peter Hung
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

2015-11-30 Thread Peter Hung
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

2015-11-30 Thread Peter Hung
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

2015-11-30 Thread Peter Hung
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

2015-11-30 Thread Peter Hung
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

2015-11-04 Thread Peter Hung
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

2015-11-04 Thread Peter Hung

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

2015-11-04 Thread Peter Hung

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

2015-11-04 Thread Peter Hung

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

2015-11-04 Thread Peter Hung
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

2015-11-04 Thread Peter Hung

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

2015-11-04 Thread Peter Hung

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

2015-11-04 Thread Peter Hung

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

2015-11-02 Thread Peter Hung
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

2015-11-02 Thread Peter Hung
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

2015-10-21 Thread Peter Hung

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

2015-10-21 Thread Peter Hung

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

2015-09-17 Thread Peter Hung
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

2015-09-17 Thread Peter Hung
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

2015-08-05 Thread Peter Hung
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

2015-08-05 Thread Peter Hung
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

2015-07-27 Thread Peter Hung
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

2015-07-27 Thread Peter Hung

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

2015-07-27 Thread Peter Hung

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

2015-07-27 Thread Peter Hung
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

2015-07-23 Thread Peter Hung
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

2015-07-23 Thread Peter Hung
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

2015-07-20 Thread Peter Hung
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

2015-07-20 Thread Peter Hung
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

2015-07-15 Thread Peter Hung

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

2015-07-15 Thread Peter Hung

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

2015-07-13 Thread Peter Hung
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

2015-07-13 Thread Peter Hung
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

2015-07-10 Thread Peter Hung
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

2015-07-10 Thread Peter Hung
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/


  1   2   3   4   >