/*
* NXP (Philips) SCC+++(SCN+++) serial driver
*
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
*
* Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de)
*
* 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, or
* (at your option) any later version.
*/
#if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/platform_data/serial-sccnxp.h>
#include <linux/regulator/consumer.h>
#define SCCNXP_NAME "uart-sccnxp"
#define SCCNXP_MAJOR 204
#define SCCNXP_MINOR 205
#define SCCNXP_MR_REG (0x00)
# define MR0_BAUD_NORMAL (0 << 0)
# define MR0_BAUD_EXT1 (1 << 0)
# define MR0_BAUD_EXT2 (5 << 0)
# define MR0_FIFO (1 << 3)
# define MR0_TXLVL (1 << 4)
# define MR1_BITS_5 (0 << 0)
# define MR1_BITS_6 (1 << 0)
# define MR1_BITS_7 (2 << 0)
# define MR1_BITS_8 (3 << 0)
# define MR1_PAR_EVN (0 << 2)
# define MR1_PAR_ODD (1 << 2)
# define MR1_PAR_NO (4 << 2)
# define MR2_STOP1 (7 << 0)
# define MR2_STOP2 (0xf << 0)
#define SCCNXP_SR_REG (0x01)
#define SCCNXP_CSR_REG SCCNXP_SR_REG
# define SR_RXRDY (1 << 0)
# define SR_FULL (1 << 1)
# define SR_TXRDY (1 << 2)
# define SR_TXEMT (1 << 3)
# define SR_OVR (1 << 4)
# define SR_PE (1 << 5)
# define SR_FE (1 << 6)
# define SR_BRK (1 << 7)
#define SCCNXP_CR_REG (0x02)
# define CR_RX_ENABLE (1 << 0)
# define CR_RX_DISABLE (1 << 1)
# define CR_TX_ENABLE (1 << 2)
# define CR_TX_DISABLE (1 << 3)
# define CR_CMD_MRPTR1 (0x01 << 4)
# define CR_CMD_RX_RESET (0x02 << 4)
# define CR_CMD_TX_RESET (0x03 << 4)
# define CR_CMD_STATUS_RESET (0x04 << 4)
# define CR_CMD_BREAK_RESET (0x05 << 4)
# define CR_CMD_START_BREAK (0x06 << 4)
# define CR_CMD_STOP_BREAK (0x07 << 4)
# define CR_CMD_MRPTR0 (0x0b << 4)
#define SCCNXP_RHR_REG (0x03)
#define SCCNXP_THR_REG SCCNXP_RHR_REG
#define SCCNXP_IPCR_REG (0x04)
#define SCCNXP_ACR_REG SCCNXP_IPCR_REG
# define ACR_BAUD0 (0 << 7)
# define ACR_BAUD1 (1 << 7)
# define ACR_TIMER_MODE (6 << 4)
#define SCCNXP_ISR_REG (0x05)
#define SCCNXP_IMR_REG SCCNXP_ISR_REG
# define IMR_TXRDY (1 << 0)
# define IMR_RXRDY (1 << 1)
# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
#define SCCNXP_IPR_REG (0x0d)
#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
#define SCCNXP_SOP_REG (0x0e)
#define SCCNXP_ROP_REG (0x0f)
/* Route helpers */
#define MCTRL_MASK(sig) (0xf << (sig))
#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0)
#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0)
#define SCCNXP_HAVE_IO 0x00000001
#define SCCNXP_HAVE_MR0 0x00000002
struct sccnxp_chip {
const char *name;
unsigned int nr;
unsigned long freq_min;
unsigned long freq_std;
unsigned long freq_max;
unsigned int flags;
unsigned int fifosize;
};
struct sccnxp_port {
struct uart_driver uart;
struct uart_port port[SCCNXP_MAX_UARTS];
bool opened[SCCNXP_MAX_UARTS];
int irq;
u8 imr;
struct sccnxp_chip *chip;
#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
struct console console;
#endif
spinlock_t lock;
bool poll;
struct timer_list timer;
struct sccnxp_pdata pdata;
struct regulator *regulator;
};
static const struct sccnxp_chip sc2681 = {
.name = "SC2681",
.nr = 2,
.freq_min = 1000000,
.freq_std = 3686400,
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
};
static const struct sccnxp_chip sc2691 = {
.name = "SC2691",
.nr = 1,
.freq_min = 1000000,
.freq_std = 3686400,
.freq_max = 4000000,
.flags = 0,
.fifosize = 3,
};
static const struct sccnxp_chip sc2692 = {
.name = "SC2692",
.nr = 2,
.freq_min = 1000000,
.freq_std = 3686400,
.freq_max = 4000000,
.flags = SCCNXP_HAVE_IO,
.fifosize = 3,
};
static const struct sccnxp_chip sc2891 = {
.name = "SC2891",
.nr = 1,
.freq_min = 100000,
.freq_std = 3686400,
.freq_max = 8000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 16,
};
static const struct sccnxp_chip sc2892 = {
.name = "SC2892",
.nr = 2,
.freq_min = 100000,
.freq_std = 3686400,
.freq_max = 8000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 16,
};
static const struct sccnxp_chip sc28202 = {
.name = "SC28202",
.nr = 2,
.freq_min = 1000000,
.freq_std = 14745600,
.freq_max = 50000000,
.flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
.fifosize = 256,
};