V4L/DVB (13794): [Mantis/VP-3028] Initial go at Serial interface implementation, add support for VP-3028

Signed-off-by: Manu Abraham <manu@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
new file mode 100644
index 0000000..786fcc3
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -0,0 +1,139 @@
+#include <linux/spinlock.h>
+#include "mantis_common.h"
+
+struct mantis_uart_params {
+	enum mantis_baud	baud_rate;
+	enum mantis_parity	parity;
+};
+
+#define UART_MAX_BUF			16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	u32 stat, i;
+	unsigned long flags;
+
+	/* get data */
+	for (i = 0; i < (config->bytes + 1); i++) {
+
+		if (stat & MANTIS_UART_RXFIFO_FULL) {
+			dprintk(verbose, MANTIS_ERROR, 1, "RX Fifo FULL");
+		}
+		data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+		stat = mmread(MANTIS_UART_STAT);
+
+		dprintk(verbose, MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+		if (data[i] & (1 << 7)) {
+			dprintk(verbose, MANTIS_ERROR, 1, "UART framing error");
+			return -EINVAL;
+		}
+		if (data[i] & (1 << 6)) {
+			dprintk(verbose, MANTIS_ERROR, 1, "UART parity error");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+	struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	u8 buf[16];
+	int i;
+
+	dprintk(verbose, MANTIS_DEBUG, 1, "UART read");
+	mantis_uart_read(mantis, buf);
+
+	dprintk(verbose, MANTIS_DEBUG, 1, "UART: ");
+	for (i = 0; i < (config->bytes + 1); i++)
+		dprintk(verbose, MANTIS_DEBUG, 0, "<%02x> ", buf[i]);
+
+	dprintk(verbose, MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+			     struct mantis_uart_params *params)
+{
+	char* rates[] = { "B_9600", "B_19200", "B_38400", "B_57600", "B_115200" };
+	char* parity[] = { "NONE", "ODD", "EVEN" };
+
+	u32 reg;
+
+	dprintk(verbose, MANTIS_DEBUG, 1, "Set Parity <%s> Baud Rate <%s>",
+		parity[params->parity],
+		rates[params->baud_rate]);
+
+	mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+	reg = mmread(MANTIS_UART_BAUD);
+
+	switch (params->baud_rate) {
+	case MANTIS_BAUD_9600:
+		reg |= 0xd8;
+		break;
+	case MANTIS_BAUD_19200:
+		reg |= 0x6c;
+		break;
+	case MANTIS_BAUD_38400:
+		reg |= 0x36;
+		break;
+	case MANTIS_BAUD_57600:
+		reg |= 0x23;
+		break;
+	case MANTIS_BAUD_115200:
+		reg |= 0x11;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mmwrite(reg, MANTIS_UART_BAUD);
+
+	return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+	struct mantis_hwconfig *config = mantis->hwconfig;
+	struct mantis_uart_params params;
+
+	dprintk(verbose, MANTIS_DEBUG, 1, "Initializing UART ..");
+	/* default parity: */
+	params.baud_rate = config->baud_rate;
+	params.parity = config->parity;
+
+	init_waitqueue_head(&mantis->uart_wq);
+	spin_lock_init(&mantis->uart_lock);
+
+	INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+	/* disable interrupt */
+	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+	mantis_uart_setup(mantis, &params);
+
+	/* default 1 byte */
+	mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+	/* flush buffer */
+	mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+	/* enable interrupt */
+	mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+	mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+	schedule_work(&mantis->uart_work);
+
+	return 0;
+}
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+	/* disable interrupt */
+	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+}