Date   

[PATCH 20/25] gpio-exar/8250-exar: Do not even instantiate a GPIO device for Commtech cards

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit a39f2fe7165647c2cd7bdbebb3d04061035e520f upstream.

Commtech adapters need the MPIOs for internal purposes, and the
gpio-exar driver already refused to pick them up. But there is actually
no point in even creating the underlying platform device.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Acked-by: Linus Walleij <linus.walleij@...>
Acked-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/gpio/gpio-exar.c | 3 ---
drivers/tty/serial/8250/8250_exar.c | 4 +++-
2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 5e0f16738e26..0a79436d8ba7 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -124,9 +124,6 @@ static int gpio_exar_probe(struct platform_device *pdev)
void __iomem *p;
int index, ret;

- if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
- return -ENODEV;
-
/*
* Map the pci device to get the register addresses.
* We will need to read and write those registers to control
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 6cab7b0512f3..e907f79b4766 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -233,7 +233,9 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
/* Setup Multipurpose Input/Output pins. */
setup_gpio(pcidev, p);

- port->port.private_data = xr17v35x_register_gpio(pcidev);
+ if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
+ port->port.private_data =
+ xr17v35x_register_gpio(pcidev);
}

return 0;
--
2.12.3


[PATCH 19/25] gpio: exar: Fix reading of directions and values

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 7f45a875da46a112f781c25cfa9bcb93aaed4712 upstream.

First, the logic for translating a register bit to the return code of
exar_get_direction and exar_get_value were wrong. And second, there was
a flip regarding the register bank in exar_get_direction.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Acked-by: Linus Walleij <linus.walleij@...>
Signed-off-by: Linus Walleij <linus.walleij@...>
---
drivers/gpio/gpio-exar.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 01f60ac86430..5e0f16738e26 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -68,7 +68,7 @@ static int exar_get(struct gpio_chip *chip, unsigned int reg)
value = readb(exar_gpio->regs + reg);
mutex_unlock(&exar_gpio->lock);

- return !!value;
+ return value;
}

static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -78,7 +78,7 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
int val;

addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
- val = exar_get(chip, addr) >> (offset % 8);
+ val = exar_get(chip, addr) & BIT(offset % 8);

return !!val;
}
@@ -89,8 +89,8 @@ static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
unsigned int addr;
int val;

- addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
- val = exar_get(chip, addr) >> (offset % 8);
+ addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+ val = exar_get(chip, addr) & BIT(offset % 8);

return !!val;
}
--
2.12.3


[PATCH 18/25] gpio: exar: Allocate resources on behalf of the platform device

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 5dab5872e59390aa9cca26ee629b95f7179f6c77 upstream.

Do not allocate resources on behalf of the parent device but on our own.
Otherwise, cleanup does not properly work if gpio-exar is removed but
not the parent device.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Acked-by: Linus Walleij <linus.walleij@...>
Signed-off-by: Linus Walleij <linus.walleij@...>
---
drivers/gpio/gpio-exar.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index f956b8fd67ca..01f60ac86430 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -139,7 +139,7 @@ static int gpio_exar_probe(struct platform_device *pdev)
if (!p)
return -ENOMEM;

- exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
+ exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
if (!exar_gpio)
return -ENOMEM;

@@ -160,7 +160,7 @@ static int gpio_exar_probe(struct platform_device *pdev)
exar_gpio->regs = p;
exar_gpio->index = index;

- ret = devm_gpiochip_add_data(&pcidev->dev,
+ ret = devm_gpiochip_add_data(&pdev->dev,
&exar_gpio->gpio_chip, exar_gpio);
if (ret)
goto err_destroy;
--
2.12.3


[PATCH 17/25] gpio-exar/8250-exar: Fix passing in of parent PCI device

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit d3936d7437e388f3a91995e8f07fb82affff2f0d upstream.

This fixes reloading of the GPIO driver for the same platform device
instance as created by the exar UART driver: First of all, the driver
sets drvdata to its own value during probing and does not restore the
original value on exit. But this won't help anyway as the core clears
drvdata after the driver left.

Set the platform device parent instead.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Acked-by: Linus Walleij <linus.walleij@...>
Acked-by: Greg Kroah-Hartman <gregkh@...>
Signed-off-by: Linus Walleij <linus.walleij@...>
---
drivers/gpio/gpio-exar.c | 2 +-
drivers/tty/serial/8250/8250_exar.c | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 866302332373..f956b8fd67ca 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -119,7 +119,7 @@ static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)

static int gpio_exar_probe(struct platform_device *pdev)
{
- struct pci_dev *pcidev = platform_get_drvdata(pdev);
+ struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
struct exar_gpio_chip *exar_gpio;
void __iomem *p;
int index, ret;
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index e78ed54a696b..6cab7b0512f3 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -190,7 +190,8 @@ xr17v35x_register_gpio(struct pci_dev *pcidev)
if (!pdev)
return NULL;

- platform_set_drvdata(pdev, pcidev);
+ pdev->dev.parent = &pcidev->dev;
+
if (platform_device_add(pdev) < 0) {
platform_device_put(pdev);
return NULL;
--
2.12.3


[PATCH 16/25] gpio: exar: Set proper output level in exar_direction_output

Jan Kiszka
 

From: Axel Lin <axel.lin@...>

commit eddeae073760aa3186e2fa0d14a12794687fa786 upstream.

Current code does not set output level in exar_direction_output, fix it.
Also move the direction_output/direction_input code block to avoid forward
declaration for exar_set_value().

Signed-off-by: Axel Lin <axel.lin@...>
Signed-off-by: Linus Walleij <linus.walleij@...>
---
drivers/gpio/gpio-exar.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 4fd6aea59c75..866302332373 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -59,17 +59,6 @@ static int exar_set_direction(struct gpio_chip *chip, int direction,
return 0;
}

-static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- return exar_set_direction(chip, 0, offset);
-}
-
-static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
-{
- return exar_set_direction(chip, 1, offset);
-}
-
static int exar_get(struct gpio_chip *chip, unsigned int reg)
{
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
@@ -116,6 +105,18 @@ static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
exar_update(chip, addr, value, offset % 8);
}

+static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ exar_set_value(chip, offset, value);
+ return exar_set_direction(chip, 0, offset);
+}
+
+static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ return exar_set_direction(chip, 1, offset);
+}
+
static int gpio_exar_probe(struct platform_device *pdev)
{
struct pci_dev *pcidev = platform_get_drvdata(pdev);
--
2.12.3


[PATCH 15/25] gpio: exar: add gpio for exar cards

Jan Kiszka
 

From: Sudip Mukherjee <sudip.mukherjee@...>

commit 6596e59e63cd4c0c0b787ce8c1e8bdd1d957b16e upstream.

Exar XR17V352/354/358 chips have 16 multi-purpose inputs/outputs which
can be controlled using gpio interface.

Add the gpio specific code.

Signed-off-by: Sudip Mukherjee <sudip.mukherjee@...>
Signed-off-by: Linus Walleij <linus.walleij@...>
[Jan: adjusted gpio_chip.parent to .dev for 4.4]
---
drivers/gpio/Kconfig | 7 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-exar.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+)
create mode 100644 drivers/gpio/gpio-exar.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 469dc378adeb..398b909ddecb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -184,6 +184,13 @@ config GPIO_ETRAXFS
help
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.

+config GPIO_EXAR
+ tristate "Support for GPIO pins on XR17V352/354/358"
+ depends on SERIAL_8250_EXAR
+ help
+ Selecting this option will enable handling of GPIO pins present
+ on Exar XR17V352/354/358 chips.
+
config GPIO_GE_FPGA
bool "GE FPGA based GPIO"
depends on GE_FPGA
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 986dbd838cea..68efdb54f8a7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
+obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
new file mode 100644
index 000000000000..4fd6aea59c75
--- /dev/null
+++ b/drivers/gpio/gpio-exar.c
@@ -0,0 +1,200 @@
+/*
+ * GPIO driver for Exar XR17V35X chip
+ *
+ * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@...>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#define EXAR_OFFSET_MPIOLVL_LO 0x90
+#define EXAR_OFFSET_MPIOSEL_LO 0x93
+#define EXAR_OFFSET_MPIOLVL_HI 0x96
+#define EXAR_OFFSET_MPIOSEL_HI 0x99
+
+#define DRIVER_NAME "gpio_exar"
+
+static DEFINE_IDA(ida_index);
+
+struct exar_gpio_chip {
+ struct gpio_chip gpio_chip;
+ struct mutex lock;
+ int index;
+ void __iomem *regs;
+ char name[20];
+};
+
+static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
+ unsigned int offset)
+{
+ struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+ int temp;
+
+ mutex_lock(&exar_gpio->lock);
+ temp = readb(exar_gpio->regs + reg);
+ temp &= ~BIT(offset);
+ if (val)
+ temp |= BIT(offset);
+ writeb(temp, exar_gpio->regs + reg);
+ mutex_unlock(&exar_gpio->lock);
+}
+
+static int exar_set_direction(struct gpio_chip *chip, int direction,
+ unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+
+ addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+ exar_update(chip, addr, direction, offset % 8);
+ return 0;
+}
+
+static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ return exar_set_direction(chip, 0, offset);
+}
+
+static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ return exar_set_direction(chip, 1, offset);
+}
+
+static int exar_get(struct gpio_chip *chip, unsigned int reg)
+{
+ struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+ int value;
+
+ mutex_lock(&exar_gpio->lock);
+ value = readb(exar_gpio->regs + reg);
+ mutex_unlock(&exar_gpio->lock);
+
+ return !!value;
+}
+
+static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+ int val;
+
+ addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+ val = exar_get(chip, addr) >> (offset % 8);
+
+ return !!val;
+}
+
+static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+ int val;
+
+ addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
+ val = exar_get(chip, addr) >> (offset % 8);
+
+ return !!val;
+}
+
+static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ unsigned int bank = offset / 8;
+ unsigned int addr;
+
+ addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+ exar_update(chip, addr, value, offset % 8);
+}
+
+static int gpio_exar_probe(struct platform_device *pdev)
+{
+ struct pci_dev *pcidev = platform_get_drvdata(pdev);
+ struct exar_gpio_chip *exar_gpio;
+ void __iomem *p;
+ int index, ret;
+
+ if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
+ return -ENODEV;
+
+ /*
+ * Map the pci device to get the register addresses.
+ * We will need to read and write those registers to control
+ * the GPIO pins.
+ * Using managed functions will save us from unmaping on exit.
+ * As the device is enabled using managed functions by the
+ * UART driver we can also use managed functions here.
+ */
+ p = pcim_iomap(pcidev, 0, 0);
+ if (!p)
+ return -ENOMEM;
+
+ exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
+ if (!exar_gpio)
+ return -ENOMEM;
+
+ mutex_init(&exar_gpio->lock);
+
+ index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
+
+ sprintf(exar_gpio->name, "exar_gpio%d", index);
+ exar_gpio->gpio_chip.label = exar_gpio->name;
+ exar_gpio->gpio_chip.dev = &pcidev->dev;
+ exar_gpio->gpio_chip.direction_output = exar_direction_output;
+ exar_gpio->gpio_chip.direction_input = exar_direction_input;
+ exar_gpio->gpio_chip.get_direction = exar_get_direction;
+ exar_gpio->gpio_chip.get = exar_get_value;
+ exar_gpio->gpio_chip.set = exar_set_value;
+ exar_gpio->gpio_chip.base = -1;
+ exar_gpio->gpio_chip.ngpio = 16;
+ exar_gpio->regs = p;
+ exar_gpio->index = index;
+
+ ret = devm_gpiochip_add_data(&pcidev->dev,
+ &exar_gpio->gpio_chip, exar_gpio);
+ if (ret)
+ goto err_destroy;
+
+ platform_set_drvdata(pdev, exar_gpio);
+
+ return 0;
+
+err_destroy:
+ ida_simple_remove(&ida_index, index);
+ mutex_destroy(&exar_gpio->lock);
+ return ret;
+}
+
+static int gpio_exar_remove(struct platform_device *pdev)
+{
+ struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
+
+ ida_simple_remove(&ida_index, exar_gpio->index);
+ mutex_destroy(&exar_gpio->lock);
+
+ return 0;
+}
+
+static struct platform_driver gpio_exar_driver = {
+ .probe = gpio_exar_probe,
+ .remove = gpio_exar_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+module_platform_driver(gpio_exar_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("Exar GPIO driver");
+MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@...>");
+MODULE_LICENSE("GPL");
--
2.12.3


[PATCH 14/25] gpio: Add devm_ apis for gpiochip_add_data and gpiochip_remove

Jan Kiszka
 

From: Laxman Dewangan <ldewangan@...>

commit 0cf3292cde22f8843ae5d1eeb8466d8121243c1a upstream.

Add device managed APIs devm_gpiochip_add_data() and
devm_gpiochip_remove() for the APIs gpiochip_add_data()
and gpiochip_remove().

This helps in reducing code in error path and sometimes
removal of .remove callback for driver unbind.

Signed-off-by: Laxman Dewangan <ldewangan@...>
---
drivers/gpio/gpiolib.c | 74 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/driver.h | 4 +++
2 files changed, 78 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 66fa17615d7c..c96dd9af9b2e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -433,6 +433,80 @@ void gpiochip_remove(struct gpio_chip *chip)
}
EXPORT_SYMBOL_GPL(gpiochip_remove);

+static void devm_gpio_chip_release(struct device *dev, void *res)
+{
+ struct gpio_chip *chip = *(struct gpio_chip **)res;
+
+ gpiochip_remove(chip);
+}
+
+static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
+
+{
+ struct gpio_chip **r = res;
+
+ if (!r || !*r) {
+ WARN_ON(!r || !*r);
+ return 0;
+ }
+
+ return *r == data;
+}
+
+/**
+ * devm_gpiochip_add_data() - Resource manager piochip_add_data()
+ * @dev: the device pointer on which irq_chip belongs to.
+ * @chip: the chip to register, with chip->base initialized
+ * Context: potentially before irqs will work
+ *
+ * Returns a negative errno if the chip can't be registered, such as
+ * because the chip->base is invalid or already associated with a
+ * different chip. Otherwise it returns zero as a success code.
+ *
+ * The gpio chip automatically be released when the device is unbound.
+ */
+int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
+ void *data)
+{
+ struct gpio_chip **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = gpiochip_add_data(chip, data);
+ if (ret < 0) {
+ devres_free(ptr);
+ return ret;
+ }
+
+ *ptr = chip;
+ devres_add(dev, ptr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
+
+/**
+ * devm_gpiochip_remove() - Resource manager of gpiochip_remove()
+ * @dev: device for which which resource was allocated
+ * @chip: the chip to remove
+ *
+ * A gpio_chip with any GPIOs still requested may not be removed.
+ */
+void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip)
+{
+ int ret;
+
+ ret = devres_release(dev, devm_gpio_chip_release,
+ devm_gpio_chip_match, chip);
+ if (!ret)
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL_GPL(devm_gpiochip_remove);
+
/**
* gpiochip_find() - iterator for locating a specific gpio_chip
* @data: data to pass to match function
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 424d11f4fa05..de502c7e4171 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -174,6 +174,10 @@ static inline int gpiochip_add(struct gpio_chip *chip)
return gpiochip_add_data(chip, NULL);
}
extern void gpiochip_remove(struct gpio_chip *chip);
+extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
+ void *data);
+extern void devm_gpiochip_remove(struct device *dev, struct gpio_chip *chip);
+
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));

--
2.12.3


[PATCH 13/25] gpio: add a data pointer to gpio_chip

Jan Kiszka
 

From: Linus Walleij <linus.walleij@...>

commit b08ea35a3296ee25c4cb53a977b752266dafa2c2 upstream.

This adds a void * pointer to gpio_chip so that driver can
assign and retrieve some states. This is done to get rid of
container_of() calls for gpio_chips embedded inside state
containers, so we can remove the need to have the gpio_chip
or later (planned) struct gpio_device be dynamically allocated
at registration time, so that its struct device can be properly
reference counted and not bound to its parent device (e.g.
a platform_device) but instead live on after unregistration
if it is opened by e.g. a char device or sysfs.

The data is added with the new function gpiochip_add_data()
and for compatibility we add static inline wrapper function
gpiochip_add() that will call gpiochip_add_data() with
NULL as argument. The latter will be removed once we have
exorcised gpiochip_add() from the kernel.

gpiochip_get_data() is added as a static inline accessor
for drivers to quickly get their data out.

Signed-off-by: Linus Walleij <linus.walleij@...>
---
drivers/gpio/gpiolib.c | 10 ++++++----
include/linux/gpio/driver.h | 14 +++++++++++++-
2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 06d345b087f8..66fa17615d7c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -280,7 +280,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
}

/**
- * gpiochip_add() - register a gpio_chip
+ * gpiochip_add_data() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
* Context: potentially before irqs will work
*
@@ -288,7 +288,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
* because the chip->base is invalid or already associated with a
* different chip. Otherwise it returns zero as a success code.
*
- * When gpiochip_add() is called very early during boot, so that GPIOs
+ * When gpiochip_add_data() is called very early during boot, so that GPIOs
* can be freely used, the chip->dev device must be registered before
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
@@ -296,7 +296,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/
-int gpiochip_add(struct gpio_chip *chip)
+int gpiochip_add_data(struct gpio_chip *chip, void *data)
{
unsigned long flags;
int status = 0;
@@ -308,6 +308,8 @@ int gpiochip_add(struct gpio_chip *chip)
if (!descs)
return -ENOMEM;

+ chip->data = data;
+
spin_lock_irqsave(&gpio_lock, flags);

if (base < 0) {
@@ -389,7 +391,7 @@ err_free_descs:
chip->label ? : "generic");
return status;
}
-EXPORT_SYMBOL_GPL(gpiochip_add);
+EXPORT_SYMBOL_GPL(gpiochip_add_data);

/**
* gpiochip_remove() - unregister a gpio_chip
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index d1baebf350d8..424d11f4fa05 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -23,6 +23,7 @@ struct seq_file;
* @dev: optional device providing the GPIOs
* @cdev: class device used by sysfs interface (may be NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
+ * @data: per-instance data assigned by the driver
* @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as
* enabling module power and clock; may sleep
@@ -92,6 +93,7 @@ struct gpio_chip {
struct device *dev;
struct device *cdev;
struct module *owner;
+ void *data;
struct list_head list;

int (*request)(struct gpio_chip *chip,
@@ -166,7 +168,11 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
unsigned offset);

/* add/remove chips */
-extern int gpiochip_add(struct gpio_chip *chip);
+extern int gpiochip_add_data(struct gpio_chip *chip, void *data);
+static inline int gpiochip_add(struct gpio_chip *chip)
+{
+ return gpiochip_add_data(chip, NULL);
+}
extern void gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data));
@@ -175,6 +181,12 @@ extern struct gpio_chip *gpiochip_find(void *data,
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);

+/* get driver data */
+static inline void *gpiochip_get_data(struct gpio_chip *chip)
+{
+ return chip->data;
+}
+
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);

#ifdef CONFIG_GPIOLIB_IRQCHIP
--
2.12.3


[PATCH 12/25] serial: uapi: Add support for bus termination

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit e8759ad17d41913dfeb49736ca7fbfbc96f32c54 upstream.

The Siemens IOT2040 comes with a RS485 interface that allows to enable
or disable bus termination via software. Add a bit to the flags field of
serial_rs485 that applications can set in order to request this feature
from the hardware. This seems generic enough to add it for everyone.
Existing driver will simply ignore it when set.

Signed-off-by: Sascha Weisenberger <sascha.weisenberger@...>
Signed-off-by: Jan Kiszka <jan.kiszka@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
include/uapi/linux/serial.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 25331f9faa76..7934e3247b45 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -121,6 +121,9 @@ struct serial_rs485 {
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
RTS pin after sent*/
#define SER_RS485_RX_DURING_TX (1 << 4)
+#define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus
+ termination
+ (if supported) */
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
__u32 padding[5]; /* Memory is cheap, new structs
--
2.12.3


[PATCH 11/25] serial: exar: Leave MPIOs as output for Commtech adapters

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit bea8be656185a2808a2f255f4a91ff18215a9d0c upstream.

Commtech adapters apparently need the original setting as outputs, see
https://marc.info/?l=linux-gpio&m=149557425201323&w=2. Account for that.

Fixes: 7dea8165f1d6 ("serial: exar: Preconfigure xr17v35x MPIOs as output")
Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Reviewed-by: Linus Walleij <linus.walleij@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 8d392ad207cf..e78ed54a696b 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -158,19 +158,26 @@ pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev,
return default_setup(priv, pcidev, idx, offset, port);
}

-static void setup_gpio(u8 __iomem *p)
+static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
{
+ /*
+ * The Commtech adapters required the MPIOs to be driven low. The Exar
+ * devices will export them as GPIOs, so we pre-configure them safely
+ * as inputs.
+ */
+ u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
+
writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
- writeb(0xff, p + UART_EXAR_MPIOSEL_7_0);
+ writeb(dir, p + UART_EXAR_MPIOSEL_7_0);
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
- writeb(0xff, p + UART_EXAR_MPIOSEL_15_8);
+ writeb(dir, p + UART_EXAR_MPIOSEL_15_8);
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
}

@@ -223,7 +230,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,

if (idx == 0) {
/* Setup Multipurpose Input/Output pins. */
- setup_gpio(p);
+ setup_gpio(pcidev, p);

port->port.private_data = xr17v35x_register_gpio(pcidev);
}
--
2.12.3


[PATCH 10/25] serial: exar: Preconfigure xr17v35x MPIOs as output

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 7dea8165f1d6434dc7572004363f86339f0f4322 upstream.

This is the safe default for GPIOs with unknown external wiring.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 9af4266eff96..8d392ad207cf 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -164,13 +164,13 @@ static void setup_gpio(u8 __iomem *p)
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
- writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ writeb(0xff, p + UART_EXAR_MPIOSEL_7_0);
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
- writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
+ writeb(0xff, p + UART_EXAR_MPIOSEL_15_8);
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
}

--
2.12.3


[PATCH 09/25] serial: 8250_EXAR: fix duplicate Kconfig text and add missing help text

Jan Kiszka
 

From: Paul Gortmaker <paul.gortmaker@...>

commit 49e1590c2ead870f4ae5568816241c4cb9bc1606 upstream.

In commit d0aeaa83f0b0f7a92615bbdd6b1f96812f7dcfd2 ("serial: exar:
split out the exar code from 8250_pci") the exar driver got its own
Kconfig. However the text for the new option was never changed from
the original 8250_PCI text, and hence it appears confusing when you
get asked the same question twice:

8250/16550 PCI device support (SERIAL_8250_PCI) [Y/n/m/?] (NEW)
8250/16550 PCI device support (SERIAL_8250_EXAR) [Y/n/m] (NEW)

Adding to the confusion, is that there is no help text for this new
option to indicate it is specific to a certain family of cards.

Fix both issues at the same time, as well as the space vs. tab issues
introduced in the same commit.

Fixes: d0aeaa83f0b0 ("serial: exar: split out the exar code from 8250_pci")
Cc: Jiri Slaby <jslaby@...>
Cc: linux-serial@...
Signed-off-by: Paul Gortmaker <paul.gortmaker@...>
Acked-by: Sudip Mukherjee <sudipm.mukherjee@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/Kconfig | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f69b0905468f..bf7b5b5f2868 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -117,9 +117,13 @@ config SERIAL_8250_PCI
by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL.

config SERIAL_8250_EXAR
- tristate "8250/16550 PCI device support"
- depends on SERIAL_8250_PCI
+ tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
+ depends on SERIAL_8250_PCI
default SERIAL_8250
+ help
+ This builds support for XR17C1xx, XR17V3xx and some Commtech
+ 422x PCIe serial cards that are not covered by the more generic
+ SERIAL_8250_PCI option.

config SERIAL_8250_HP300
tristate
--
2.12.3


[PATCH 08/25] serial: pci: Remove unused pci_boards entries

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 0d560a1d549379e46139fb9eeae0b43328c76dea upstream.

Became obsolete with the split-out of 8250_exar.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_pci.c | 22 ----------------------
1 file changed, 22 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 8437fec53126..144d23aa6e6d 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -2651,10 +2651,6 @@ enum pci_board_num_t {
pbn_b0_2_1843200,
pbn_b0_4_1843200,

- pbn_b0_2_1843200_200,
- pbn_b0_4_1843200_200,
- pbn_b0_8_1843200_200,
-
pbn_b0_1_4000000,

pbn_b0_bt_1_115200,
@@ -2871,24 +2867,6 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 8,
},

- [pbn_b0_2_1843200_200] = {
- .flags = FL_BASE0,
- .num_ports = 2,
- .base_baud = 1843200,
- .uart_offset = 0x200,
- },
- [pbn_b0_4_1843200_200] = {
- .flags = FL_BASE0,
- .num_ports = 4,
- .base_baud = 1843200,
- .uart_offset = 0x200,
- },
- [pbn_b0_8_1843200_200] = {
- .flags = FL_BASE0,
- .num_ports = 8,
- .base_baud = 1843200,
- .uart_offset = 0x200,
- },
[pbn_b0_1_4000000] = {
.flags = FL_BASE0,
.num_ports = 1,
--
2.12.3


[PATCH 07/25] serial: exar: Move Commtech adapters to 8250_exar as well

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit fc6cc9615779183f07d6ff4065368a732d09f49e upstream.

Those are Exar-based, too.

With the required refactoring of the code to fit into 8250_exar, we
automatically fix the same issue pci_xr17v35x_setup had before: 8XMODE,
FCTL, TXTRG and RXTRG were always only set for port 0. Now they are
initialized for the correct target port by using port.membase.

Now we can also cleanly fix the blacklist of 8250_pci so that all
Commtech devices are rejected and 8250_exar can handle them.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 83 +++++++++++++++++++--
drivers/tty/serial/8250/8250_pci.c | 139 +-----------------------------------
2 files changed, 79 insertions(+), 143 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index f489f25643c5..9af4266eff96 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -24,11 +24,15 @@

#include "8250.h"

-#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020
-#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
-#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
-#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
-#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
+#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
+#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
+#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a
+#define PCI_DEVICE_ID_COMMTECH_2328PCI335 0x000b
+#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020
+#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
+#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
+#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
+#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358

#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
@@ -84,6 +88,55 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
}

static int
+pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int offset = idx * 0x200;
+ unsigned int baud = 1843200;
+ u8 __iomem *p;
+ int err;
+
+ port->port.flags |= UPF_EXAR_EFR;
+ port->port.uartclk = baud * 16;
+
+ err = default_setup(priv, pcidev, idx, offset, port);
+ if (err)
+ return err;
+
+ p = port->port.membase;
+
+ writeb(0x00, p + UART_EXAR_8XMODE);
+ writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+ writeb(32, p + UART_EXAR_TXTRG);
+ writeb(32, p + UART_EXAR_RXTRG);
+
+ /*
+ * Setup Multipurpose Input/Output pins.
+ */
+ if (idx == 0) {
+ switch (pcidev->device) {
+ case PCI_DEVICE_ID_COMMTECH_4222PCI335:
+ case PCI_DEVICE_ID_COMMTECH_4224PCI335:
+ writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ break;
+ case PCI_DEVICE_ID_COMMTECH_2324PCI335:
+ case PCI_DEVICE_ID_COMMTECH_2328PCI335:
+ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
+ break;
+ }
+ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+ }
+
+ return 0;
+}
+
+static int
pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port, int idx)
{
@@ -291,6 +344,21 @@ static int __maybe_unused exar_resume(struct device *dev)

static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);

+static const struct exar8250_board pbn_fastcom335_2 = {
+ .num_ports = 2,
+ .setup = pci_fastcom335_setup,
+};
+
+static const struct exar8250_board pbn_fastcom335_4 = {
+ .num_ports = 4,
+ .setup = pci_fastcom335_setup,
+};
+
+static const struct exar8250_board pbn_fastcom335_8 = {
+ .num_ports = 8,
+ .setup = pci_fastcom335_setup,
+};
+
static const struct exar8250_board pbn_connect = {
.setup = pci_connect_tech_setup,
};
@@ -375,6 +443,11 @@ static struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x),
EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x),
EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x),
+
+ EXAR_DEVICE(COMMTECH, COMMTECH_4222PCI335, pbn_fastcom335_2),
+ EXAR_DEVICE(COMMTECH, COMMTECH_4224PCI335, pbn_fastcom335_4),
+ EXAR_DEVICE(COMMTECH, COMMTECH_2324PCI335, pbn_fastcom335_4),
+ EXAR_DEVICE(COMMTECH, COMMTECH_2328PCI335, pbn_fastcom335_8),
{ 0, }
};
MODULE_DEVICE_TABLE(pci, exar_pci_tbl);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index b961d688ab48..8437fec53126 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1752,67 +1752,6 @@ static int pci_eg20t_init(struct pci_dev *dev)
#endif
}

-#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
-#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
-#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */
-#define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */
-#define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */
-#define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */
-#define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */
-#define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */
-#define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */
-#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */
-#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
-#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */
-#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
-#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
-#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a
-#define PCI_DEVICE_ID_COMMTECH_2328PCI335 0x000b
-
-static int
-pci_fastcom335_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- u8 __iomem *p;
-
- p = pci_ioremap_bar(priv->dev, 0);
- if (p == NULL)
- return -ENOMEM;
-
- port->port.flags |= UPF_EXAR_EFR;
-
- /*
- * Setup Multipurpose Input/Output pins.
- */
- if (idx == 0) {
- switch (priv->dev->device) {
- case PCI_DEVICE_ID_COMMTECH_4222PCI335:
- case PCI_DEVICE_ID_COMMTECH_4224PCI335:
- writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
- writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
- writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
- break;
- case PCI_DEVICE_ID_COMMTECH_2324PCI335:
- case PCI_DEVICE_ID_COMMTECH_2328PCI335:
- writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
- writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
- writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
- break;
- }
- writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
- writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
- writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
- }
- writeb(0x00, p + UART_EXAR_8XMODE);
- writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
- writeb(32, p + UART_EXAR_TXTRG);
- writeb(32, p + UART_EXAR_RXTRG);
- iounmap(p);
-
- return pci_default_setup(priv, board, port, idx);
-}
-
static int
pci_wch_ch353_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -2597,38 +2536,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_asix_setup,
},
/*
- * Commtech, Inc. Fastcom adapters
- *
- */
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_4222PCI335,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_fastcom335_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_4224PCI335,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_fastcom335_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_2324PCI335,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_fastcom335_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_2328PCI335,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_fastcom335_setup,
- },
- /*
* Broadcom TruManage (NetXtreme)
*/
{
@@ -2739,10 +2646,6 @@ enum pci_board_num_t {

pbn_b0_4_1152000,

- pbn_b0_2_1152000_200,
- pbn_b0_4_1152000_200,
- pbn_b0_8_1152000_200,
-
pbn_b0_4_1250000,

pbn_b0_2_1843200,
@@ -2948,27 +2851,6 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 8,
},

- [pbn_b0_2_1152000_200] = {
- .flags = FL_BASE0,
- .num_ports = 2,
- .base_baud = 1152000,
- .uart_offset = 0x200,
- },
-
- [pbn_b0_4_1152000_200] = {
- .flags = FL_BASE0,
- .num_ports = 4,
- .base_baud = 1152000,
- .uart_offset = 0x200,
- },
-
- [pbn_b0_8_1152000_200] = {
- .flags = FL_BASE0,
- .num_ports = 8,
- .base_baud = 1152000,
- .uart_offset = 0x200,
- },
-
[pbn_b0_4_1250000] = {
.flags = FL_BASE0,
.num_ports = 4,
@@ -3682,6 +3564,7 @@ static const struct pci_device_id blacklist[] = {

/* Exar devices */
{ PCI_VDEVICE(EXAR, PCI_ANY_ID), },
+ { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
};

/*
@@ -5451,26 +5334,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_4 },

- /*
- * Commtech, Inc. Fastcom adapters
- */
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCI335,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_b0_2_1152000_200 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCI335,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_b0_4_1152000_200 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2324PCI335,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_b0_4_1152000_200 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2328PCI335,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_b0_8_1152000_200 },
-
/* Fintek PCI serial cards */
{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
--
2.12.3


[PATCH 06/25] serial: exar: Fix feature control register constants

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 7795753661f1a9423c3c8fbde322f6a2a8b94b68 upstream.

According to the XR17V352 manual, bit 4 is IrDA control and bit 5 for
485. Fortunately, no driver used them so far.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
include/uapi/linux/serial_reg.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h
index 1e5ac4e776da..cdb9f97a63c7 100644
--- a/include/uapi/linux/serial_reg.h
+++ b/include/uapi/linux/serial_reg.h
@@ -366,8 +366,8 @@
#define UART_EXAR_DVID 0x8d /* Device identification */

#define UART_EXAR_FCTR 0x08 /* Feature Control Register */
-#define UART_FCTR_EXAR_IRDA 0x08 /* IrDa data encode select */
-#define UART_FCTR_EXAR_485 0x10 /* Auto 485 half duplex dir ctl */
+#define UART_FCTR_EXAR_IRDA 0x10 /* IrDa data encode select */
+#define UART_FCTR_EXAR_485 0x20 /* Auto 485 half duplex dir ctl */
#define UART_FCTR_EXAR_TRGA 0x00 /* FIFO trigger table A */
#define UART_FCTR_EXAR_TRGB 0x60 /* FIFO trigger table B */
#define UART_FCTR_EXAR_TRGC 0x80 /* FIFO trigger table C */
--
2.12.3


[PATCH 05/25] serial: exar: Fix initialization of EXAR registers for ports > 0

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 5b5f252d67afd7bd5b923c664206d60800bf5054 upstream.

So far, pci_xr17v35x_setup always initialized 8XMODE, FCTR & Co. for
port 0 because it used the address of that port instead of moving the
pointer according to the port number. Fix this and remove the unneeded
temporary ioremap by moving default_setup up and reusing the membase it
fills into the port structure.

Fixes: 14faa8cce88e ("tty/8250 Add support for Commtech's Fastcom Async-335 and Fastcom Async-PCIe cards")
Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 22 +++++++++-------------
1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 58469d9d6515..f489f25643c5 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -157,27 +157,23 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
if (board->has_slave && idx >= 8)
port->port.uartclk /= 2;

- p = pci_ioremap_bar(pcidev, 0);
- if (!p)
- return -ENOMEM;
+ ret = default_setup(priv, pcidev, idx, offset, port);
+ if (ret)
+ return ret;

- /* Setup Multipurpose Input/Output pins. */
- if (idx == 0)
- setup_gpio(p);
+ p = port->port.membase;

writeb(0x00, p + UART_EXAR_8XMODE);
writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
writeb(128, p + UART_EXAR_TXTRG);
writeb(128, p + UART_EXAR_RXTRG);
- iounmap(p);

- ret = default_setup(priv, pcidev, idx, offset, port);
- if (ret)
- return ret;
+ if (idx == 0) {
+ /* Setup Multipurpose Input/Output pins. */
+ setup_gpio(p);

- if (idx == 0)
- port->port.private_data =
- xr17v35x_register_gpio(pcidev);
+ port->port.private_data = xr17v35x_register_gpio(pcidev);
+ }

return 0;
}
--
2.12.3


[PATCH 04/25] serial: exar: Fix mapping of port I/O resources

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit 24572af4fb6ce0726dbe12b0286de11d25ff008b upstream.

pcim_iomap_table only returns the table of mapping, it does not perform
them. For that, we need to call pcim_iomap, but only if that mapping was
not done before.

Fixes: d0aeaa83f0b0 ("serial: exar: split out the exar code from 8250_pci")
Signed-off-by: Jan Kiszka <jan.kiszka@...>
Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index e6b44a75a5e0..58469d9d6515 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -72,6 +72,9 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
const struct exar8250_board *board = priv->board;
unsigned int bar = 0;

+ if (!pcim_iomap_table(pcidev)[bar] && !pcim_iomap(pcidev, bar, 0))
+ return -ENOMEM;
+
port->port.iotype = UPIO_MEM;
port->port.mapbase = pci_resource_start(pcidev, bar) + offset;
port->port.membase = pcim_iomap_table(pcidev)[bar] + offset;
--
2.12.3


[PATCH 03/25] serial: 8250_pci: remove exar code

Jan Kiszka
 

From: Sudip Mukherjee <sudip.mukherjee@...>

commit 5d1a2388edee77930c8b542cf8be0c92342dbeb4 upstream.

Remove the Exar specific codes from 8250_pci and blacklist those chips
so that the new Exar serial driver binds to the devices.

Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Sudip Mukherjee <sudip.mukherjee@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_pci.c | 336 +------------------------------------
drivers/tty/serial/8250/Kconfig | 1 +
2 files changed, 4 insertions(+), 333 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index cf7f6151e66a..b961d688ab48 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1752,9 +1752,6 @@ static int pci_eg20t_init(struct pci_dev *dev)
#endif
}

-#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
-#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
-
#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */
@@ -1767,71 +1764,6 @@ static int pci_eg20t_init(struct pci_dev *dev)
#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */
#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */
-
-static int
-pci_xr17c154_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- port->port.flags |= UPF_EXAR_EFR;
- return pci_default_setup(priv, board, port, idx);
-}
-
-static inline int
-xr17v35x_has_slave(struct serial_private *priv)
-{
- const int dev_id = priv->dev->device;
-
- return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
- (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
-}
-
-static int
-pci_xr17v35x_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- u8 __iomem *p;
-
- p = pci_ioremap_bar(priv->dev, 0);
- if (p == NULL)
- return -ENOMEM;
-
- port->port.flags |= UPF_EXAR_EFR;
-
- /*
- * Setup the uart clock for the devices on expansion slot to
- * half the clock speed of the main chip (which is 125MHz)
- */
- if (xr17v35x_has_slave(priv) && idx >= 8)
- port->port.uartclk = (7812500 * 16 / 2);
-
- /*
- * Setup Multipurpose Input/Output pins.
- */
- if (idx == 0) {
- writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
- writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
- writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
- writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
- writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
- writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
- writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
- writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
- writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
- writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
- writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
- writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
- }
- writeb(0x00, p + UART_EXAR_8XMODE);
- writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
- writeb(128, p + UART_EXAR_TXTRG);
- writeb(128, p + UART_EXAR_RXTRG);
- iounmap(p);
-
- return pci_default_setup(priv, board, port, idx);
-}
-
#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a
@@ -1945,9 +1877,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
#define PCI_VENDOR_ID_ASIX 0x9710
-#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020
-#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
-#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936
@@ -2452,65 +2381,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_timedia_setup,
},
/*
- * Exar cards
- */
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17C152,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17c154_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17C154,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17c154_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17C158,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17c154_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17V352,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17V354,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17V358,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17V4358,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_EXAR,
- .device = PCI_DEVICE_ID_EXAR_XR17V8358,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- /*
* Xircom cards
*/
{
@@ -2758,27 +2628,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_fastcom335_setup,
},
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_4222PCIE,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_4224PCIE,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
- {
- .vendor = PCI_VENDOR_ID_COMMTECH,
- .device = PCI_DEVICE_ID_COMMTECH_4228PCIE,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_xr17v35x_setup,
- },
/*
* Broadcom TruManage (NetXtreme)
*/
@@ -2993,15 +2842,6 @@ enum pci_board_num_t {
pbn_computone_6,
pbn_computone_8,
pbn_sbsxrsio,
- pbn_exar_XR17C152,
- pbn_exar_XR17C154,
- pbn_exar_XR17C158,
- pbn_exar_XR17V352,
- pbn_exar_XR17V354,
- pbn_exar_XR17V358,
- pbn_exar_XR17V4358,
- pbn_exar_XR17V8358,
- pbn_exar_ibm_saturn,
pbn_pasemi_1682M,
pbn_ni8430_2,
pbn_ni8430_4,
@@ -3651,76 +3491,6 @@ static struct pciserial_board pci_boards[] = {
.reg_shift = 4,
},
/*
- * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
- * Only basic 16550A support.
- * XR17C15[24] are not tested, but they should work.
- */
- [pbn_exar_XR17C152] = {
- .flags = FL_BASE0,
- .num_ports = 2,
- .base_baud = 921600,
- .uart_offset = 0x200,
- },
- [pbn_exar_XR17C154] = {
- .flags = FL_BASE0,
- .num_ports = 4,
- .base_baud = 921600,
- .uart_offset = 0x200,
- },
- [pbn_exar_XR17C158] = {
- .flags = FL_BASE0,
- .num_ports = 8,
- .base_baud = 921600,
- .uart_offset = 0x200,
- },
- [pbn_exar_XR17V352] = {
- .flags = FL_BASE0,
- .num_ports = 2,
- .base_baud = 7812500,
- .uart_offset = 0x400,
- .reg_shift = 0,
- .first_offset = 0,
- },
- [pbn_exar_XR17V354] = {
- .flags = FL_BASE0,
- .num_ports = 4,
- .base_baud = 7812500,
- .uart_offset = 0x400,
- .reg_shift = 0,
- .first_offset = 0,
- },
- [pbn_exar_XR17V358] = {
- .flags = FL_BASE0,
- .num_ports = 8,
- .base_baud = 7812500,
- .uart_offset = 0x400,
- .reg_shift = 0,
- .first_offset = 0,
- },
- [pbn_exar_XR17V4358] = {
- .flags = FL_BASE0,
- .num_ports = 12,
- .base_baud = 7812500,
- .uart_offset = 0x400,
- .reg_shift = 0,
- .first_offset = 0,
- },
- [pbn_exar_XR17V8358] = {
- .flags = FL_BASE0,
- .num_ports = 16,
- .base_baud = 7812500,
- .uart_offset = 0x400,
- .reg_shift = 0,
- .first_offset = 0,
- },
- [pbn_exar_ibm_saturn] = {
- .flags = FL_BASE0,
- .num_ports = 1,
- .base_baud = 921600,
- .uart_offset = 0x200,
- },
-
- /*
* PA Semi PWRficient PA6T-1682M on-chip UART
*/
[pbn_pasemi_1682M] = {
@@ -3909,6 +3679,9 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(INTEL, 0x081d), },
{ PCI_VDEVICE(INTEL, 0x1191), },
{ PCI_VDEVICE(INTEL, 0x19d8), },
+
+ /* Exar devices */
+ { PCI_VDEVICE(EXAR, PCI_ANY_ID), },
};

/*
@@ -4347,58 +4120,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_VENDOR_ID_AFAVLAB,
PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
pbn_b0_4_1152000 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
- pbn_b0_2_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0,
- pbn_b0_4_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0,
- pbn_b0_8_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
- pbn_b0_2_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0,
- pbn_b0_4_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0,
- pbn_b0_8_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
- pbn_b0_2_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0,
- pbn_b0_4_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0,
- pbn_b0_8_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
- pbn_b0_2_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0,
- pbn_b0_4_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
- PCI_SUBVENDOR_ID_CONNECT_TECH,
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0,
- pbn_b0_8_1843200_200 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_VENDOR_ID_IBM, PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT,
- 0, 0, pbn_exar_ibm_saturn },
-
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_bt_1_115200 },
@@ -5126,45 +4847,6 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b3_8_115200 },
-
- /*
- * Exar Corp. XR17C15[248] Dual/Quad/Octal UART
- */
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17C152 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17C154 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17C158 },
- /*
- * Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs
- */
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V352 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V354 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V358 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V4358,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V4358 },
- { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V8358 },
/*
* Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
*/
@@ -5788,18 +5470,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_b0_8_1152000_200 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCIE,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V352 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCIE,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V354 },
- { PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4228PCIE,
- PCI_ANY_ID, PCI_ANY_ID,
- 0,
- 0, pbn_exar_XR17V358 },

/* Fintek PCI serial cards */
{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 92e3697a771c..f69b0905468f 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -119,6 +119,7 @@ config SERIAL_8250_PCI
config SERIAL_8250_EXAR
tristate "8250/16550 PCI device support"
depends on SERIAL_8250_PCI
+ default SERIAL_8250

config SERIAL_8250_HP300
tristate
--
2.12.3


[PATCH 02/25] serial: 8250_pci: Use symbolic constants for EXAR's MPIO registers

Jan Kiszka
 

From: Jan Kiszka <jan.kiszka@...>

commit b6fce7382d72274336aeafe6e44da755a371ed32 upstream.

Less magic that only requires comments.

Signed-off-by: Jan Kiszka <jan.kiszka@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_pci.c | 55 +++++++++++++++++++++++---------------
1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index cf3da51a3536..cf7f6151e66a 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1755,6 +1755,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358

+#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
+#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
+#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */
+#define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */
+#define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */
+#define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */
+#define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */
+#define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */
+#define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */
+#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */
+#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
+#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */
+
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1797,18 +1810,18 @@ pci_xr17v35x_setup(struct serial_private *priv,
* Setup Multipurpose Input/Output pins.
*/
if (idx == 0) {
- writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
- writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
- writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
- writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
- writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
- writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
- writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
- writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
- writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
- writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
- writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
- writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
+ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
+ writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
}
writeb(0x00, p + UART_EXAR_8XMODE);
writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
@@ -1844,20 +1857,20 @@ pci_fastcom335_setup(struct serial_private *priv,
switch (priv->dev->device) {
case PCI_DEVICE_ID_COMMTECH_4222PCI335:
case PCI_DEVICE_ID_COMMTECH_4224PCI335:
- writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */
- writeb(0x00, p + 0x92); /* MPIOINV[7:0] */
- writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */
+ writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
break;
case PCI_DEVICE_ID_COMMTECH_2324PCI335:
case PCI_DEVICE_ID_COMMTECH_2328PCI335:
- writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */
- writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */
- writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */
+ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
break;
}
- writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */
- writeb(0x00, p + 0x91); /* MPIO3T[7:0] */
- writeb(0x00, p + 0x94); /* MPIOOD[7:0] */
+ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
}
writeb(0x00, p + UART_EXAR_8XMODE);
writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
--
2.12.3


[PATCH 01/25] serial: exar: split out the exar code from 8250_pci

Jan Kiszka
 

From: Sudip Mukherjee <sudip.mukherjee@...>

commit d0aeaa83f0b0f7a92615bbdd6b1f96812f7dcfd2 upstream.

Add the serial driver for the Exar chips. And also register the
platform device for the GPIO provided by the Exar chips.

Reviewed-by: Andy Shevchenko <andy.shevchenko@...>
Signed-off-by: Sudip Mukherjee <sudip.mukherjee@...>
Signed-off-by: Greg Kroah-Hartman <gregkh@...>
---
drivers/tty/serial/8250/8250_exar.c | 396 ++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 4 +
drivers/tty/serial/8250/Makefile | 1 +
3 files changed, 401 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_exar.c

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
new file mode 100644
index 000000000000..e6b44a75a5e0
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -0,0 +1,396 @@
+/*
+ * Probe module for 8250/16550-type Exar chips PCI serial ports.
+ *
+ * Based on drivers/tty/serial/8250/8250_pci.c,
+ *
+ * Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved.
+ *
+ * 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.
+ */
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/8250_pci.h>
+
+#include <asm/byteorder.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020
+#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
+#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
+#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
+#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
+
+#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
+#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
+#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */
+#define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */
+#define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */
+#define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */
+#define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */
+#define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */
+#define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */
+#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */
+#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
+#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */
+
+struct exar8250;
+
+/**
+ * struct exar8250_board - board information
+ * @num_ports: number of serial ports
+ * @reg_shift: describes UART register mapping in PCI memory
+ */
+struct exar8250_board {
+ unsigned int num_ports;
+ unsigned int reg_shift;
+ bool has_slave;
+ int (*setup)(struct exar8250 *, struct pci_dev *,
+ struct uart_8250_port *, int);
+ void (*exit)(struct pci_dev *pcidev);
+};
+
+struct exar8250 {
+ unsigned int nr;
+ struct exar8250_board *board;
+ int line[0];
+};
+
+static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
+ int idx, unsigned int offset,
+ struct uart_8250_port *port)
+{
+ const struct exar8250_board *board = priv->board;
+ unsigned int bar = 0;
+
+ port->port.iotype = UPIO_MEM;
+ port->port.mapbase = pci_resource_start(pcidev, bar) + offset;
+ port->port.membase = pcim_iomap_table(pcidev)[bar] + offset;
+ port->port.regshift = board->reg_shift;
+
+ return 0;
+}
+
+static int
+pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int offset = idx * 0x200;
+ unsigned int baud = 1843200;
+
+ port->port.uartclk = baud * 16;
+ return default_setup(priv, pcidev, idx, offset, port);
+}
+
+static int
+pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int offset = idx * 0x200;
+ unsigned int baud = 921600;
+
+ port->port.uartclk = baud * 16;
+ return default_setup(priv, pcidev, idx, offset, port);
+}
+
+static void setup_gpio(u8 __iomem *p)
+{
+ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
+ writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
+ writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
+}
+
+static void *
+xr17v35x_register_gpio(struct pci_dev *pcidev)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("gpio_exar", PLATFORM_DEVID_AUTO);
+ if (!pdev)
+ return NULL;
+
+ platform_set_drvdata(pdev, pcidev);
+ if (platform_device_add(pdev) < 0) {
+ platform_device_put(pdev);
+ return NULL;
+ }
+
+ return pdev;
+}
+
+static int
+pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port, int idx)
+{
+ const struct exar8250_board *board = priv->board;
+ unsigned int offset = idx * 0x400;
+ unsigned int baud = 7812500;
+ u8 __iomem *p;
+ int ret;
+
+ port->port.uartclk = baud * 16;
+ /*
+ * Setup the uart clock for the devices on expansion slot to
+ * half the clock speed of the main chip (which is 125MHz)
+ */
+ if (board->has_slave && idx >= 8)
+ port->port.uartclk /= 2;
+
+ p = pci_ioremap_bar(pcidev, 0);
+ if (!p)
+ return -ENOMEM;
+
+ /* Setup Multipurpose Input/Output pins. */
+ if (idx == 0)
+ setup_gpio(p);
+
+ writeb(0x00, p + UART_EXAR_8XMODE);
+ writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+ writeb(128, p + UART_EXAR_TXTRG);
+ writeb(128, p + UART_EXAR_RXTRG);
+ iounmap(p);
+
+ ret = default_setup(priv, pcidev, idx, offset, port);
+ if (ret)
+ return ret;
+
+ if (idx == 0)
+ port->port.private_data =
+ xr17v35x_register_gpio(pcidev);
+
+ return 0;
+}
+
+static void pci_xr17v35x_exit(struct pci_dev *pcidev)
+{
+ struct exar8250 *priv = pci_get_drvdata(pcidev);
+ struct uart_8250_port *port = serial8250_get_port(priv->line[0]);
+ struct platform_device *pdev = port->port.private_data;
+
+ platform_device_unregister(pdev);
+ port->port.private_data = NULL;
+}
+
+static int
+exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+ unsigned int nr_ports, i, bar = 0, maxnr;
+ struct exar8250_board *board;
+ struct uart_8250_port uart;
+ struct exar8250 *priv;
+ int rc;
+
+ board = (struct exar8250_board *)ent->driver_data;
+ if (!board)
+ return -EINVAL;
+
+ rc = pcim_enable_device(pcidev);
+ if (rc)
+ return rc;
+
+ maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3);
+
+ nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f;
+
+ priv = devm_kzalloc(&pcidev->dev, sizeof(*priv) +
+ sizeof(unsigned int) * nr_ports,
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->board = board;
+
+ memset(&uart, 0, sizeof(uart));
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ
+ | UPF_EXAR_EFR;
+ uart.port.irq = pcidev->irq;
+ uart.port.dev = &pcidev->dev;
+
+ for (i = 0; i < nr_ports && i < maxnr; i++) {
+ rc = board->setup(priv, pcidev, &uart, i);
+ if (rc) {
+ dev_err(&pcidev->dev, "Failed to setup port %u\n", i);
+ break;
+ }
+
+ dev_dbg(&pcidev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
+
+ priv->line[i] = serial8250_register_8250_port(&uart);
+ if (priv->line[i] < 0) {
+ dev_err(&pcidev->dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq,
+ uart.port.iotype, priv->line[i]);
+ break;
+ }
+ }
+ priv->nr = i;
+ pci_set_drvdata(pcidev, priv);
+ return 0;
+}
+
+static void exar_pci_remove(struct pci_dev *pcidev)
+{
+ struct exar8250 *priv = pci_get_drvdata(pcidev);
+ unsigned int i;
+
+ for (i = 0; i < priv->nr; i++)
+ serial8250_unregister_port(priv->line[i]);
+
+ if (priv->board->exit)
+ priv->board->exit(pcidev);
+}
+
+static int __maybe_unused exar_suspend(struct device *dev)
+{
+ struct pci_dev *pcidev = to_pci_dev(dev);
+ struct exar8250 *priv = pci_get_drvdata(pcidev);
+ unsigned int i;
+
+ for (i = 0; i < priv->nr; i++)
+ if (priv->line[i] >= 0)
+ serial8250_suspend_port(priv->line[i]);
+
+ /* Ensure that every init quirk is properly torn down */
+ if (priv->board->exit)
+ priv->board->exit(pcidev);
+
+ return 0;
+}
+
+static int __maybe_unused exar_resume(struct device *dev)
+{
+ struct pci_dev *pcidev = to_pci_dev(dev);
+ struct exar8250 *priv = pci_get_drvdata(pcidev);
+ unsigned int i;
+
+ for (i = 0; i < priv->nr; i++)
+ if (priv->line[i] >= 0)
+ serial8250_resume_port(priv->line[i]);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
+
+static const struct exar8250_board pbn_connect = {
+ .setup = pci_connect_tech_setup,
+};
+
+static const struct exar8250_board pbn_exar_ibm_saturn = {
+ .num_ports = 1,
+ .setup = pci_xr17c154_setup,
+};
+
+static const struct exar8250_board pbn_exar_XR17C15x = {
+ .setup = pci_xr17c154_setup,
+};
+
+static const struct exar8250_board pbn_exar_XR17V35x = {
+ .setup = pci_xr17v35x_setup,
+ .exit = pci_xr17v35x_exit,
+};
+
+static const struct exar8250_board pbn_exar_XR17V4358 = {
+ .num_ports = 12,
+ .has_slave = true,
+ .setup = pci_xr17v35x_setup,
+ .exit = pci_xr17v35x_exit,
+};
+
+static const struct exar8250_board pbn_exar_XR17V8358 = {
+ .num_ports = 16,
+ .has_slave = true,
+ .setup = pci_xr17v35x_setup,
+ .exit = pci_xr17v35x_exit,
+};
+
+#define CONNECT_DEVICE(devid, sdevid, bd) { \
+ PCI_DEVICE_SUB( \
+ PCI_VENDOR_ID_EXAR, \
+ PCI_DEVICE_ID_EXAR_##devid, \
+ PCI_SUBVENDOR_ID_CONNECT_TECH, \
+ PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_##sdevid), 0, 0, \
+ (kernel_ulong_t)&bd \
+ }
+
+#define EXAR_DEVICE(vend, devid, bd) { \
+ PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \
+ }
+
+#define IBM_DEVICE(devid, sdevid, bd) { \
+ PCI_DEVICE_SUB( \
+ PCI_VENDOR_ID_EXAR, \
+ PCI_DEVICE_ID_EXAR_##devid, \
+ PCI_VENDOR_ID_IBM, \
+ PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \
+ (kernel_ulong_t)&bd \
+ }
+
+static struct pci_device_id exar_pci_tbl[] = {
+ CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
+ CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
+ CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect),
+ CONNECT_DEVICE(XR17C152, UART_1_1, pbn_connect),
+ CONNECT_DEVICE(XR17C154, UART_2_2, pbn_connect),
+ CONNECT_DEVICE(XR17C158, UART_4_4, pbn_connect),
+ CONNECT_DEVICE(XR17C152, UART_2, pbn_connect),
+ CONNECT_DEVICE(XR17C154, UART_4, pbn_connect),
+ CONNECT_DEVICE(XR17C158, UART_8, pbn_connect),
+ CONNECT_DEVICE(XR17C152, UART_2_485, pbn_connect),
+ CONNECT_DEVICE(XR17C154, UART_4_485, pbn_connect),
+ CONNECT_DEVICE(XR17C158, UART_8_485, pbn_connect),
+
+ IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn),
+
+ /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */
+ EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x),
+ EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x),
+ EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x),
+
+ /* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */
+ EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x),
+ EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358),
+ EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358),
+ EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x),
+ EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x),
+ EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x),
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, exar_pci_tbl);
+
+static struct pci_driver exar_pci_driver = {
+ .name = "exar_serial",
+ .probe = exar_pci_probe,
+ .remove = exar_pci_remove,
+ .driver = {
+ .pm = &exar_pci_pm,
+ },
+ .id_table = exar_pci_tbl,
+};
+module_pci_driver(exar_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Exar Serial Dricer");
+MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@...>");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 6412f1455beb..92e3697a771c 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -116,6 +116,10 @@ config SERIAL_8250_PCI
Note that serial ports on NetMos 9835 Multi-I/O cards are handled
by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL.

+config SERIAL_8250_EXAR
+ tristate "8250/16550 PCI device support"
+ depends on SERIAL_8250_PCI
+
config SERIAL_8250_HP300
tristate
depends on SERIAL_8250 && HP300
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index e177f8681ada..ce75a9241d36 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
+obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
--
2.12.3

8201 - 8220 of 8699