aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/samsung.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/samsung.c')
-rw-r--r--drivers/tty/serial/samsung.c274
1 files changed, 267 insertions, 7 deletions
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 2468df0..a3b31b8 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -52,6 +52,8 @@
#include "samsung.h"
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
/* UART name and device definitions */
#define S3C24XX_SERIAL_NAME "ttySAC"
@@ -67,7 +69,8 @@
#define RXSTAT_DUMMY_READ (0x10000000)
#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_MIDAS) || \
- defined(CONFIG_MACH_SLP_PQ)||defined(CONFIG_MACH_P10)
+ defined(CONFIG_MACH_SLP_PQ) || defined(CONFIG_MACH_P10) || \
+ defined(CONFIG_MACH_PX) || defined(CONFIG_MACH_TRATS)
/* Devices */
#define CONFIG_BT_S3C_UART 0
#define CONFIG_GPS_S3C_UART 1
@@ -197,7 +200,16 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
+#ifdef CONFIG_CSR_GSD4T_CDMA
+#define CSR_GPS_WORK_AROUND_RX_ISR /*it should be applied to*/
+#define CSR_GPS_WORK_AROUND_UART_DRIVER /*it should be applied to*/
+/*#define CSR_GPS_DEBUG */ /* just debug code*/
+/*#define CSR_GPS_DEBUG_RAW_DATA */ /*just debug code*/
+#endif
+#ifdef CSR_GPS_DEBUG
+#define GPIO_GPS_DEBUG_NEW EXYNOS4_GPK1(2)
+#endif
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
@@ -209,7 +221,32 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
struct uart_port *port = &ourport->port;
struct tty_struct *tty = port->state->port.tty;
unsigned int ufcon, ch, flag, ufstat, uerstat;
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ int max_count = 256;
+ unsigned char received_data[256];
+ unsigned char received_flag[256];
+ int received_data_count = 0;
+#else
int max_count = 64;
+#endif
+#ifdef CSR_GPS_DEBUG
+ int overrun = 0;
+ static int gpio_init = 0;
+ static int active_signal = 1;
+#endif
+#ifdef CSR_GPS_DEBUG_RAW_DATA
+ char received_data_string[256*2+1];
+ int i;
+#endif
+#ifdef CSR_GPS_DEBUG
+ if (gpio_init == 0) {
+ s3c_gpio_cfgpin(GPIO_GPS_DEBUG_NEW, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_DEBUG_NEW, S3C_GPIO_PULL_NONE);
+ gpio_init = 1;
+ }
+
+ gpio_set_value(GPIO_GPS_DEBUG_NEW, active_signal);
+#endif
while (max_count-- > 0) {
ufcon = rd_regl(port, S3C2410_UFCON);
@@ -252,16 +289,32 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
/* check for break */
if (uerstat & S3C2410_UERSTAT_BREAK) {
dbg("break!\n");
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ printk(KERN_ERR KERN_DEBUG "break!\n");
+#endif
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
}
- if (uerstat & S3C2410_UERSTAT_FRAME)
+ if (uerstat & S3C2410_UERSTAT_FRAME) {
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ printk(KERN_ERR KERN_DEBUG "frame error!\n");
+#endif
port->icount.frame++;
- if (uerstat & S3C2410_UERSTAT_OVERRUN)
+ }
+ if (uerstat & S3C2410_UERSTAT_OVERRUN) {
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ printk(KERN_ERR KERN_DEBUG "overrun error!\n");
+#endif
port->icount.overrun++;
-
+#ifdef CSR_GPS_DEBUG
+ if (overrun == 0) {
+ overrun = 1;
+ active_signal = !active_signal;
+ }
+#endif
+ }
uerstat &= port->read_status_mask;
if (uerstat & S3C2410_UERSTAT_BREAK)
@@ -273,18 +326,72 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, ch))
+ if (uart_handle_sysrq_char(port, ch)) {
+ printk(KERN_ERR KERN_DEBUG "break-sysrq\n");
goto ignore_char;
+ }
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ received_data[received_data_count] = ch;
+ received_flag[received_data_count] = flag;
+ received_data_count++;
+#else
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
ch, flag);
+#endif
ignore_char:
continue;
}
+#ifdef CSR_GPS_WORK_AROUND_RX_ISR
+ if (received_data_count) {
+#ifdef CSR_GPS_DEBUG_RAW_DATA
+ if (tty->index == 1) {
+ int nibble;
+ unsigned char *ptr_src, *ptr_dst;
+
+ ptr_src = received_data;
+ ptr_dst = received_data_string;
+
+ for (i = 0; i < received_data_count; i++, ptr_src++) {
+ nibble = (*ptr_src >> 4) & 0x0F;
+ if (9 < nibble)
+ *ptr_dst = nibble - 10 + 'A';
+ else
+ *ptr_dst = nibble + '0';
+
+ ptr_dst++;
+
+ nibble = (*ptr_src) & 0x0F;
+
+ if (9 < nibble)
+ *ptr_dst = nibble - 10 + 'A';
+ else
+ *ptr_dst = nibble + '0';
+
+ ptr_dst++;
+ }
+
+ *ptr_dst = '\0';
+ printk(KERN_ERR KERN_DEBUG "CGPS:%s\n", \
+ received_data_string);
+ }
+#endif /* CSR_GPS_DEBUG_RAW_DATA */
+ tty_insert_flip_string_flags(tty, \
+ (const unsigned char *)received_data, \
+ (const char *)received_flag, \
+ (size_t) received_data_count); /* yr check */
+ tty_flip_buffer_push(tty);
+ }
+#else /* !CSR_GPS_WORK_AROUND_RX_ISR */
tty_flip_buffer_push(tty);
+#endif /* CSR_GPS_WORK_AROUND_RX_ISR */
out:
+#ifdef CSR_GPS_DEBUG
+ /*oif overrun, gpio toggle*/
+ gpio_set_value(GPIO_GPS_DEBUG_NEW, !active_signal);
+#endif
return IRQ_HANDLED;
}
@@ -366,7 +473,7 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_MIDAS) || \
defined(CONFIG_MACH_SLP_PQ) || defined(CONFIG_MACH_P10) || \
- defined(CONFIG_MACH_U1CAMERA_BD)
+ defined(CONFIG_MACH_PX) || defined(CONFIG_MACH_TRATS)
unsigned int umcon = 0;
umcon = rd_regl(port, S3C2410_UMCON);
@@ -723,7 +830,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
* Ask the core to calculate the divisor for us.
*/
#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_MIDAS) || \
- defined(CONFIG_MACH_SLP_PQ)||defined(CONFIG_MACH_P10)
+ defined(CONFIG_MACH_SLP_PQ) || defined(CONFIG_MACH_P10) || \
+ defined(CONFIG_MACH_PX) || defined(CONFIG_MACH_TRATS)
baud = uart_get_baud_rate(port, termios, old, 0, 4000000); // 4Mbps
#else
baud = uart_get_baud_rate(port, termios, old, 0, 3000000);
@@ -1200,6 +1308,152 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
}
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+#ifdef CSR_GPS_WORK_AROUND_UART_DRIVER
+static ssize_t s3c24xx_serial_rts_pullup_detect(struct device *dev, \
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ s3c_gpio_pull_t back_pull;
+ unsigned int back_cfg;
+
+ /*back_pull = s3c_gpio_getpull(GPIO_GPS_RTS); back up*/
+ back_pull = S3C_GPIO_PULL_NONE;
+ /*back_cfg = s3c_gpio_getcfg(GPIO_GPS_RTS);*/
+ back_cfg = S3C_GPIO_SFN(2);
+ s3c_gpio_setpull(GPIO_GPS_RTS, S3C_GPIO_PULL_DOWN);
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_OUTPUT);
+
+ gpio_set_value(GPIO_GPS_RTS, 0);
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_INPUT);
+
+ /*here, you may need a little delay*/
+ for (i = 0; i < 100; i++);
+ buf[0] = '0' + gpio_get_value(GPIO_GPS_RTS);
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, back_cfg);
+ s3c_gpio_setpull(GPIO_GPS_RTS, back_pull);
+
+ printk(KERN_ERR KERN_DEBUG \
+ "rts_cts_gate:detect RTS pin pulled_up - %c\n", buf[0]);
+
+ return 1;
+}
+
+static ssize_t s3c24xx_serial_rts_cts_config(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+
+ s3c_gpio_pull_t rts_pull_option, cts_pull_option;
+
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate:config [%c%c%c]\n", \
+ buf[0], buf[1], buf[2]);
+
+ rts_pull_option = S3C_GPIO_PULL_NONE;
+ cts_pull_option = S3C_GPIO_PULL_NONE;
+
+ if (buf[1] == '-') {
+ rts_pull_option = S3C_GPIO_PULL_DOWN;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: rts pull-down\n");
+ } else if (buf[1] == '+') {
+ rts_pull_option = S3C_GPIO_PULL_UP;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: rts pull-up\n");
+ } else {
+ rts_pull_option = S3C_GPIO_PULL_NONE;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: rts pull-none\n");
+ }
+
+ if (buf[2] == '-') {
+ cts_pull_option = S3C_GPIO_PULL_DOWN;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: cts pull-down\n");
+ } else if (buf[2] == '+') {
+ cts_pull_option = S3C_GPIO_PULL_UP;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: cts pull-up\n");
+ } else {
+ cts_pull_option = S3C_GPIO_PULL_NONE;
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: cts pull-none\n");
+ }
+
+ if (buf[0] == '0') { /* rts/cts*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: hw flow control\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+
+ s3c_gpio_cfgpin(GPIO_GPS_CTS, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(GPIO_GPS_CTS, cts_pull_option);
+ }
+ /* rts high cts high*/
+ else if (buf[0] == '1') { /* control pins for GPS reset*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: RTS-HIGH, CTS-HIGH\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+ gpio_set_value(GPIO_GPS_RTS, 1);
+
+ s3c_gpio_cfgpin(GPIO_GPS_CTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_CTS, cts_pull_option);
+ gpio_set_value(GPIO_GPS_CTS, 1);
+ }
+ /* rts high cts input*/
+ else if (buf[0] == '2') { /* control pins for GPS reset*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: RTS-HIGH, CTS-INPUT\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+ gpio_set_value(GPIO_GPS_RTS, 1);
+
+ s3c_gpio_cfgpin(GPIO_GPS_CTS, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(GPIO_GPS_CTS, cts_pull_option);
+ }
+ /* rts input cts input*/
+ else if (buf[0] == '3') { /* control pins for GPS reset */
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: RTS-INPUT, CTS-INPUT\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+
+ s3c_gpio_cfgpin(GPIO_GPS_CTS, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(GPIO_GPS_CTS, cts_pull_option);
+ }
+ /* rts input cts high */
+ else if (buf[0] == '4') { /*control pins for GPS reset*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: RTS-INPUT, CTS-HIGH\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_INPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+
+ s3c_gpio_cfgpin(GPIO_GPS_CTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_CTS, cts_pull_option);
+ gpio_set_value(GPIO_GPS_CTS, 1);
+ }
+ /*test rts high*/
+ else if (buf[0] == '5') { /*rts test - ouput 0*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate: RTS set 0\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+
+ gpio_set_value(GPIO_GPS_RTS, 0);
+ }
+ /* test rts low*/
+ else if (buf[0] == '6') { /*rts test - output 1*/
+ printk(KERN_ERR KERN_DEBUG "rts_cts_gate:RTS set 1\n");
+
+ s3c_gpio_cfgpin(GPIO_GPS_RTS, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(GPIO_GPS_RTS, rts_pull_option);
+
+ gpio_set_value(GPIO_GPS_RTS, 1);
+ }
+
+ return 1;
+}
+
+static DEVICE_ATTR(rts_cts_gate, \
+ S_IRGRP | S_IWGRP | S_IRUSR | S_IWUSR | S_IROTH, \
+ s3c24xx_serial_rts_pullup_detect, \
+ s3c24xx_serial_rts_cts_config);
+#endif
/* Device driver serial port probe */
@@ -1230,6 +1484,12 @@ int s3c24xx_serial_probe(struct platform_device *dev,
if (ret < 0)
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
+#ifdef CSR_GPS_WORK_AROUND_UART_DRIVER
+ ret = device_create_file(&dev->dev, &dev_attr_rts_cts_gate); /* woojun*/
+ if (ret < 0)
+ printk(KERN_ERR "%s: failed to add rts_cts_gate attr.\n", \
+ __func__);
+#endif
ret = s3c24xx_serial_cpufreq_register(ourport);
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");