Skip to content

Commit

Permalink
serial: 8250_ni16550: Add support for NIC7A69
Browse files Browse the repository at this point in the history
This device uses a 33.333MHz clock with a prescaler value of 1.125 to
achieve baud rates within 1% error up to 921600 baud. We query ACPI
standard _DSD properties to determine if each port is an RS-232 or RS-485
port.

Signed-off-by: Kyle Roeschley <[email protected]>
Natinst-ReviewBoard-ID: 286745
  • Loading branch information
kroeschl committed Apr 22, 2019
1 parent 4a640ec commit c9ffae3
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 9 deletions.
1 change: 1 addition & 0 deletions drivers/acpi/acpi_pnp.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
{"NIC7750"}, /* National Instruments (NI) 16550 PNP */
{"NIC7772"}, /* National Instruments (NI) 16550 PNP */
{"NIC792B"}, /* National Instruments (NI) 16550 PNP */
{"NIC7A69"}, /* National Instruments (NI) 16550 PNP */
{"PMC2430"}, /* Pace 56 Voice Internal Plug & Play Modem */
{"PNP0500"}, /* Generic standard PC COM port */
{"PNP0501"}, /* Generic 16550A-compatible COM port */
Expand Down
50 changes: 41 additions & 9 deletions drivers/tty/serial/8250/8250_pnp.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "8250.h"

#include <linux/ni16550.h>
#include <linux/property.h>

#define UNKNOWN_DEV 0x3000
#define CIR_PORT 0x0800
Expand All @@ -32,6 +33,7 @@
#define NI_CAP_PMR 0x0001
#define NI_CLK_33333333 0x0002
#define NI_CPR_CLK_25000000 0x0008
#define NI_CPR_CLK_33333333 0x0010

static bool is_niport(struct pnp_dev *dev)
{
Expand Down Expand Up @@ -219,6 +221,7 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "NIC7750", NI_CLK_33333333 },
{ "NIC7772", NI_CAP_PMR | NI_16BYTE_FIFO },
{ "NIC792B", NI_CPR_CLK_25000000 },
{ "NIC7A69", NI_CPR_CLK_33333333 },
/* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
{ "nEC8241", 0 },
/* Pace 56 Voice Internal Plug & Play Modem */
Expand Down Expand Up @@ -502,10 +505,15 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)

#ifdef CONFIG_SERIAL_8250_NI16550
if (is_niport(dev)) {
WARN_ON((flags & (NI_CLK_33333333 | NI_CPR_CLK_25000000)) ==
(NI_CLK_33333333 | NI_CPR_CLK_25000000));
bool rs232_property = false;

WARN_ON(hweight32(flags & (NI_CPR_CLK_25000000 |
NI_CPR_CLK_33333333 |
NI_CLK_33333333)) > 1);

if (flags & NI_CLK_33333333)
uart.port.uartclk = 33333333;

if (flags & NI_CPR_CLK_25000000) {
/* Sets UART clock rate to 22.222 MHz
* with prescaler 1.125.
Expand All @@ -515,6 +523,27 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
ni16550_config_prescaler(uart.port.iobase, 0x9);
}

if (flags & NI_CPR_CLK_33333333) {
const char *transceiver;

/*
* Set UART clock rate to 29.629 MHz
* with prescaler 1.125.
*/
uart.port.uartclk = 29629629;
uart.mcr_force = UART_MCR_CLKSEL;
ni16550_config_prescaler(uart.port.iobase, 0x9);

if (device_property_read_string(&dev->dev,
"transceiver",
&transceiver)) {
dev_err(&dev->dev, "transceiver property missing\n");
return -EINVAL;
}

rs232_property = strncmp(transceiver, "RS-232", 6) == 0;
}

uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;

if (flags & NI_16BYTE_FIFO)
Expand All @@ -523,18 +552,21 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
uart.port.type = PORT_NI16550_F128;

/*
* NI UARTs are by default connected to RS-485 transceivers,
* unless the PMR register is implemented, and the UART is
* dual-mode capable. Then it could be in RS-232 mode and if it
* is, we will register as a standard 8250 port.
* NI UARTs may be connected to RS-485 or RS-232 transceivers,
* depending on the ACPI 'transceiver' property and whether or
* not the PMR is implemented. If the PMR is implemented and
* the port is in RS-232 mode, register as a standard 8250 port
* and print about it.
*/
if ((flags & NI_CAP_PMR) && is_rs232_mode(uart.port.iobase))
pr_info("NI 16550 at I/O 0x%x (irq = %d) is dual-mode capable and is in RS-232 mode\n",
(unsigned int)uart.port.iobase,
uart.port.irq);
else
/* Either the PMR register is not implemented, or it is
* and the UART is in RS-485 mode as set in the PMR
else if (!rs232_property)
/*
* Either the PMR is implemented and set to RS-485 mode
* or it's not implemented and the 'transceiver' ACPI
* property is 'RS-485';
*/
ni16550_port_setup(&uart.port);
}
Expand Down

0 comments on commit c9ffae3

Please sign in to comment.