Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fdc2de87 authored by Je Yen Tam's avatar Je Yen Tam Committed by Greg Kroah-Hartman
Browse files

serial/8250: Add support for NI-Serial PXI/PXIe+485 devices



Add support for NI-Serial PXIe-RS232, PXI-RS485 and PXIe-RS485 devices.

Signed-off-by: default avatarJe Yen Tam <je.yen.tam@ni.com>
Link: https://lore.kernel.org/r/20190726074012.2590-1-je.yen.tam@ni.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fe94347d
Loading
Loading
Loading
Loading
+288 −4
Original line number Original line Diff line number Diff line
@@ -730,8 +730,16 @@ static int pci_ni8430_init(struct pci_dev *dev)
}
}


/* UART Port Control Register */
/* UART Port Control Register */
#define NI8430_PORTCON	0x0f
#define NI16550_PCR_OFFSET	0x0f
#define NI8430_PORTCON_TXVR_ENABLE	(1 << 3)
#define NI16550_PCR_RS422	0x00
#define NI16550_PCR_ECHO_RS485	0x01
#define NI16550_PCR_DTR_RS485	0x02
#define NI16550_PCR_AUTO_RS485	0x03
#define NI16550_PCR_WIRE_MODE_MASK	0x03
#define NI16550_PCR_TXVR_ENABLE_BIT	BIT(3)
#define NI16550_PCR_RS485_TERMINATION_BIT	BIT(6)
#define NI16550_ACR_DTR_AUTO_DTR	(0x2 << 3)
#define NI16550_ACR_DTR_MANUAL_DTR	(0x0 << 3)


static int
static int
pci_ni8430_setup(struct serial_private *priv,
pci_ni8430_setup(struct serial_private *priv,
@@ -753,14 +761,117 @@ pci_ni8430_setup(struct serial_private *priv,
		return -ENOMEM;
		return -ENOMEM;


	/* enable the transceiver */
	/* enable the transceiver */
	writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
	writeb(readb(p + offset + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
	       p + offset + NI8430_PORTCON);
	       p + offset + NI16550_PCR_OFFSET);


	iounmap(p);
	iounmap(p);


	return setup_port(priv, port, bar, offset, board->reg_shift);
	return setup_port(priv, port, bar, offset, board->reg_shift);
}
}


static int pci_ni8431_config_rs485(struct uart_port *port,
	struct serial_rs485 *rs485)
{
	u8 pcr, acr;
	struct uart_8250_port *up;

	up = container_of(port, struct uart_8250_port, port);
	acr = up->acr;
	pcr = port->serial_in(port, NI16550_PCR_OFFSET);
	pcr &= ~NI16550_PCR_WIRE_MODE_MASK;

	if (rs485->flags & SER_RS485_ENABLED) {
		/* RS-485 */
		if ((rs485->flags & SER_RS485_RX_DURING_TX) &&
			(rs485->flags & SER_RS485_RTS_ON_SEND)) {
			dev_dbg(port->dev, "Invalid 2-wire mode\n");
			return -EINVAL;
		}

		if (rs485->flags & SER_RS485_RX_DURING_TX) {
			/* Echo */
			dev_vdbg(port->dev, "2-wire DTR with echo\n");
			pcr |= NI16550_PCR_ECHO_RS485;
			acr |= NI16550_ACR_DTR_MANUAL_DTR;
		} else {
			/* Auto or DTR */
			if (rs485->flags & SER_RS485_RTS_ON_SEND) {
				/* Auto */
				dev_vdbg(port->dev, "2-wire Auto\n");
				pcr |= NI16550_PCR_AUTO_RS485;
				acr |= NI16550_ACR_DTR_AUTO_DTR;
			} else {
				/* DTR-controlled */
				/* No Echo */
				dev_vdbg(port->dev, "2-wire DTR no echo\n");
				pcr |= NI16550_PCR_DTR_RS485;
				acr |= NI16550_ACR_DTR_MANUAL_DTR;
			}
		}
	} else {
		/* RS-422 */
		dev_vdbg(port->dev, "4-wire\n");
		pcr |= NI16550_PCR_RS422;
		acr |= NI16550_ACR_DTR_MANUAL_DTR;
	}

	dev_dbg(port->dev, "write pcr: 0x%08x\n", pcr);
	port->serial_out(port, NI16550_PCR_OFFSET, pcr);

	up->acr = acr;
	port->serial_out(port, UART_SCR, UART_ACR);
	port->serial_out(port, UART_ICR, up->acr);

	/* Update the cache. */
	port->rs485 = *rs485;

	return 0;
}

static int pci_ni8431_setup(struct serial_private *priv,
		 const struct pciserial_board *board,
		 struct uart_8250_port *uart, int idx)
{
	u8 pcr, acr;
	struct pci_dev *dev = priv->dev;
	void __iomem *addr;
	unsigned int bar, offset = board->first_offset;

	if (idx >= board->num_ports)
		return 1;

	bar = FL_GET_BASE(board->flags);
	offset += idx * board->uart_offset;

	addr = pci_ioremap_bar(dev, bar);
	if (!addr)
		return -ENOMEM;

	/* enable the transceiver */
	writeb(readb(addr + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
		addr + NI16550_PCR_OFFSET);

	pcr = readb(addr + NI16550_PCR_OFFSET);
	pcr &= ~NI16550_PCR_WIRE_MODE_MASK;

	/* set wire mode to default RS-422 */
	pcr |= NI16550_PCR_RS422;
	acr = NI16550_ACR_DTR_MANUAL_DTR;

	/* write port configuration to register */
	writeb(pcr, addr + NI16550_PCR_OFFSET);

	/* access and write to UART acr register */
	writeb(UART_ACR, addr + UART_SCR);
	writeb(acr, addr + UART_ICR);

	uart->port.rs485_config = &pci_ni8431_config_rs485;

	iounmap(addr);

	return setup_port(priv, uart, bar, offset, board->reg_shift);
}

static int pci_netmos_9900_setup(struct serial_private *priv,
static int pci_netmos_9900_setup(struct serial_private *priv,
				const struct pciserial_board *board,
				const struct pciserial_board *board,
				struct uart_8250_port *port, int idx)
				struct uart_8250_port *port, int idx)
@@ -1786,6 +1897,15 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM	0x10E9
#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM	0x10E9
#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM	0x11D8
#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM	0x11D8


#define PCIE_DEVICE_ID_NI_PXIE8430_2328	0x74C2
#define PCIE_DEVICE_ID_NI_PXIE8430_23216	0x74C1
#define PCI_DEVICE_ID_NI_PXI8431_4852	0x7081
#define PCI_DEVICE_ID_NI_PXI8431_4854	0x70DE
#define PCI_DEVICE_ID_NI_PXI8431_4858	0x70E3
#define PCI_DEVICE_ID_NI_PXI8433_4852	0x70E9
#define PCI_DEVICE_ID_NI_PXI8433_4854	0x70ED
#define PCIE_DEVICE_ID_NI_PXIE8431_4858	0x74C4
#define PCIE_DEVICE_ID_NI_PXIE8431_48516	0x74C3




/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
@@ -2011,6 +2131,87 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
		.setup		= pci_ni8430_setup,
		.setup		= pci_ni8430_setup,
		.exit		= pci_ni8430_exit,
		.exit		= pci_ni8430_exit,
	},
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCIE_DEVICE_ID_NI_PXIE8430_2328,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8430_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCIE_DEVICE_ID_NI_PXIE8430_23216,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8430_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCI_DEVICE_ID_NI_PXI8431_4852,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCI_DEVICE_ID_NI_PXI8431_4854,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCI_DEVICE_ID_NI_PXI8431_4858,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCI_DEVICE_ID_NI_PXI8433_4852,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCI_DEVICE_ID_NI_PXI8433_4854,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCIE_DEVICE_ID_NI_PXIE8431_4858,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	{
		.vendor		= PCI_VENDOR_ID_NI,
		.device		= PCIE_DEVICE_ID_NI_PXIE8431_48516,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.init		= pci_ni8430_init,
		.setup		= pci_ni8431_setup,
		.exit		= pci_ni8430_exit,
	},
	/* Quatech */
	/* Quatech */
	{
	{
		.vendor		= PCI_VENDOR_ID_QUATECH,
		.vendor		= PCI_VENDOR_ID_QUATECH,
@@ -2740,6 +2941,13 @@ enum pci_board_num_t {
	pbn_ni8430_4,
	pbn_ni8430_4,
	pbn_ni8430_8,
	pbn_ni8430_8,
	pbn_ni8430_16,
	pbn_ni8430_16,
	pbn_ni8430_pxie_8,
	pbn_ni8430_pxie_16,
	pbn_ni8431_2,
	pbn_ni8431_4,
	pbn_ni8431_8,
	pbn_ni8431_pxie_8,
	pbn_ni8431_pxie_16,
	pbn_ADDIDATA_PCIe_1_3906250,
	pbn_ADDIDATA_PCIe_1_3906250,
	pbn_ADDIDATA_PCIe_2_3906250,
	pbn_ADDIDATA_PCIe_2_3906250,
	pbn_ADDIDATA_PCIe_4_3906250,
	pbn_ADDIDATA_PCIe_4_3906250,
@@ -3381,6 +3589,55 @@ static struct pciserial_board pci_boards[] = {
		.uart_offset	= 0x10,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
		.first_offset	= 0x800,
	},
	},
	[pbn_ni8430_pxie_16] = {
		.flags		= FL_BASE0,
		.num_ports	= 16,
		.base_baud	= 3125000,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8430_pxie_8] = {
		.flags		= FL_BASE0,
		.num_ports	= 8,
		.base_baud	= 3125000,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8431_8] = {
		.flags		= FL_BASE0,
		.num_ports	= 8,
		.base_baud	= 3686400,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8431_4] = {
		.flags		= FL_BASE0,
		.num_ports	= 4,
		.base_baud	= 3686400,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8431_2] = {
		.flags		= FL_BASE0,
		.num_ports	= 2,
		.base_baud	= 3686400,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8431_pxie_16] = {
		.flags		= FL_BASE0,
		.num_ports	= 16,
		.base_baud	= 3125000,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	[pbn_ni8431_pxie_8] = {
		.flags		= FL_BASE0,
		.num_ports	= 8,
		.base_baud	= 3125000,
		.uart_offset	= 0x10,
		.first_offset	= 0x800,
	},
	/*
	/*
	 * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
	 * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
	 */
	 */
@@ -5063,6 +5320,33 @@ static const struct pci_device_id serial_pci_tbl[] = {
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8430_4 },
		pbn_ni8430_4 },
	{	PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_2328,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8430_pxie_8 },
	{	PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_23216,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8430_pxie_16 },
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4852,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_2 },
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4854,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_4 },
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4858,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_8 },
	{	PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_4858,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_pxie_8 },
	{	PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_48516,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_pxie_16 },
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4852,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_2 },
	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4854,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
		pbn_ni8431_4 },


	/*
	/*
	* ADDI-DATA GmbH communication cards <info@addi-data.com>
	* ADDI-DATA GmbH communication cards <info@addi-data.com>