summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250/8250_pci.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-09 07:08:37 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-03-09 07:08:37 +0100
commitbecba85f0e1ca8ab97bd7e836a7129a94ace1ff2 (patch)
tree3a43cb5edc60310c89790ab0961f5276bd9ca615 /drivers/tty/serial/8250/8250_pci.c
parent9eccca0843205f87c00404b663188b88eb248051 (diff)
parent3372ec28622083ac87daf18918a222fbee06f6f9 (diff)
Merge 4.0-rc3 into tty-testing
This resolves a merge issue in drivers/tty/serial/8250/8250_pci.c Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250/8250_pci.c')
-rw-r--r--drivers/tty/serial/8250/8250_pci.c214
1 files changed, 198 insertions, 16 deletions
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 892eb32cdef4..11784e9ad9c2 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -27,6 +27,7 @@
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h>
+#include <linux/platform_data/dma-hsu.h>
#include "8250.h"
@@ -1525,6 +1526,148 @@ byt_serial_setup(struct serial_private *priv,
return ret;
}
+#define INTEL_MID_UART_PS 0x30
+#define INTEL_MID_UART_MUL 0x34
+
+static void intel_mid_set_termios_50M(struct uart_port *p,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud = tty_termios_baud_rate(termios);
+ u32 ps, mul;
+
+ /*
+ * The uart clk is 50Mhz, and the baud rate come from:
+ * baud = 50M * MUL / (DIV * PS * DLAB)
+ *
+ * For those basic low baud rate we can get the direct
+ * scalar from 2746800, like 115200 = 2746800/24. For those
+ * higher baud rate, we handle them case by case, mainly by
+ * adjusting the MUL/PS registers, and DIV register is kept
+ * as default value 0x3d09 to make things simple.
+ */
+
+ ps = 0x10;
+
+ switch (baud) {
+ case 500000:
+ case 1000000:
+ case 1500000:
+ case 3000000:
+ mul = 0x3a98;
+ p->uartclk = 48000000;
+ break;
+ case 2000000:
+ case 4000000:
+ mul = 0x2710;
+ ps = 0x08;
+ p->uartclk = 64000000;
+ break;
+ case 2500000:
+ mul = 0x30d4;
+ p->uartclk = 40000000;
+ break;
+ case 3500000:
+ mul = 0x3345;
+ ps = 0x0c;
+ p->uartclk = 56000000;
+ break;
+ default:
+ mul = 0x2400;
+ p->uartclk = 29491200;
+ }
+
+ writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
+ writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
+
+ serial8250_do_set_termios(p, termios, old);
+}
+
+static bool intel_mid_dma_filter(struct dma_chan *chan, void *param)
+{
+ struct hsu_dma_slave *s = param;
+
+ if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
+ return false;
+
+ chan->private = s;
+ return true;
+}
+
+static int intel_mid_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx,
+ int index, struct pci_dev *dma_dev)
+{
+ struct device *dev = port->port.dev;
+ struct uart_8250_dma *dma;
+ struct hsu_dma_slave *tx_param, *rx_param;
+
+ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+ if (!tx_param)
+ return -ENOMEM;
+
+ rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+ if (!rx_param)
+ return -ENOMEM;
+
+ rx_param->chan_id = index * 2 + 1;
+ tx_param->chan_id = index * 2;
+
+ dma->rxconf.src_maxburst = 64;
+ dma->txconf.dst_maxburst = 64;
+
+ rx_param->dma_dev = &dma_dev->dev;
+ tx_param->dma_dev = &dma_dev->dev;
+
+ dma->fn = intel_mid_dma_filter;
+ dma->rx_param = rx_param;
+ dma->tx_param = tx_param;
+
+ port->port.type = PORT_16750;
+ port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ port->dma = dma;
+
+ return pci_default_setup(priv, board, port, idx);
+}
+
+#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b
+#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c
+#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d
+
+static int pnw_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *pdev = priv->dev;
+ struct pci_dev *dma_dev;
+ int index;
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_PNW_UART1:
+ index = 0;
+ break;
+ case PCI_DEVICE_ID_INTEL_PNW_UART2:
+ index = 1;
+ break;
+ case PCI_DEVICE_ID_INTEL_PNW_UART3:
+ index = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
+
+ port->port.set_termios = intel_mid_set_termios_50M;
+
+ return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
+}
+
static int
pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1989,6 +2132,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
},
{
.vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PNW_UART3,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pnw_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BSW_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
@@ -2864,6 +3028,7 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200,
pbn_byt,
+ pbn_pnw,
pbn_qrk,
pbn_omegapci,
pbn_NETMOS9900_2s_115200,
@@ -3630,6 +3795,11 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 0x80,
.reg_shift = 2,
},
+ [pbn_pnw] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ },
[pbn_qrk] = {
.flags = FL_BASE0,
.num_ports = 1,
@@ -4006,41 +4176,41 @@ static void pciserial_remove_one(struct pci_dev *dev)
pci_disable_device(dev);
}
-#ifdef CONFIG_PM
-static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pciserial_suspend_one(struct device *dev)
{
- struct serial_private *priv = pci_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct serial_private *priv = pci_get_drvdata(pdev);
if (priv)
pciserial_suspend_ports(priv);
- pci_save_state(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
-static int pciserial_resume_one(struct pci_dev *dev)
+static int pciserial_resume_one(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct serial_private *priv = pci_get_drvdata(pdev);
int err;
- struct serial_private *priv = pci_get_drvdata(dev);
-
- pci_set_power_state(dev, PCI_D0);
- pci_restore_state(dev);
if (priv) {
/*
* The device may have been disabled. Re-enable it.
*/
- err = pci_enable_device(dev);
+ err = pci_enable_device(pdev);
/* FIXME: We cannot simply error out here */
if (err)
- dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n");
+ dev_err(dev, "Unable to re-enable ports, trying to continue.\n");
pciserial_resume_ports(priv);
}
return 0;
}
#endif
+static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one,
+ pciserial_resume_one);
+
static struct pci_device_id serial_pci_tbl[] = {
/* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
@@ -5363,6 +5533,19 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_byt },
/*
+ * Intel Penwell
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pnw},
+
+ /*
* Intel Quark x1000
*/
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
@@ -5510,10 +5693,9 @@ static struct pci_driver serial_pci_driver = {
.name = "serial",
.probe = pciserial_init_one,
.remove = pciserial_remove_one,
-#ifdef CONFIG_PM
- .suspend = pciserial_suspend_one,
- .resume = pciserial_resume_one,
-#endif
+ .driver = {
+ .pm = &pciserial_pm_ops,
+ },
.id_table = serial_pci_tbl,
.err_handler = &serial8250_err_handler,
};