aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/uart_select.c
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/misc/uart_select.c
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
samsung update 1
Diffstat (limited to 'drivers/misc/uart_select.c')
-rw-r--r--drivers/misc/uart_select.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/drivers/misc/uart_select.c b/drivers/misc/uart_select.c
new file mode 100644
index 00000000000..22d14393b50
--- /dev/null
+++ b/drivers/misc/uart_select.c
@@ -0,0 +1,156 @@
+/*
+ * uart_sel.c - UART Selection Driver
+ *
+ * Copyright (C) 2009 Samsung Electronics
+ * Kim Kyuwon <q1.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/uart_select.h>
+
+struct uart_select {
+ struct uart_select_platform_data *pdata;
+ struct rw_semaphore rwsem;
+};
+
+static int uart_saved_state = UART_SW_PATH_NA;
+
+static ssize_t uart_select_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uart_select *uart_sel =
+ platform_get_drvdata(to_platform_device(dev));
+ int ret;
+ int path;
+
+ path = uart_sel->pdata->get_uart_switch();
+
+ down_read(&uart_sel->rwsem);
+ uart_saved_state = path;
+ if (path == UART_SW_PATH_NA)
+ ret = sprintf(buf, "NA\n");
+ else if (path == UART_SW_PATH_CP)
+ ret = sprintf(buf, "CP\n");
+ else
+ ret = sprintf(buf, "AP\n");
+ up_read(&uart_sel->rwsem);
+
+ return ret;
+}
+
+static ssize_t uart_select_store_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct uart_select *uart_sel =
+ platform_get_drvdata(to_platform_device(dev));
+ struct uart_select_platform_data *pdata = uart_sel->pdata;
+ int path;
+
+ if (!count)
+ return -EINVAL;
+
+ down_write(&uart_sel->rwsem);
+ if (!strncmp(buf, "CP", 2))
+ path = UART_SW_PATH_CP;
+ else if (!strncmp(buf, "AP", 2))
+ path = UART_SW_PATH_AP;
+ else {
+ up_write(&uart_sel->rwsem);
+ dev_err(dev, "Invalid cmd !!\n");
+ return -EINVAL;
+ }
+ pdata->set_uart_switch(path);
+ uart_saved_state = path;
+ up_write(&uart_sel->rwsem);
+
+ return count;
+}
+
+static struct device_attribute uart_select_attr = {
+ .attr = {
+ .name = "path",
+ .mode = 0644,
+ },
+ .show = uart_select_show_state,
+ .store = uart_select_store_state,
+};
+
+/* Used in uart isr to avoid triggering sysrq when uart is not in AP */
+int uart_sel_get_state(void)
+{
+ if (uart_saved_state < 0)
+ return -EPERM;
+ else
+ return uart_saved_state;
+}
+EXPORT_SYMBOL(uart_sel_get_state);
+
+static int __devinit uart_select_probe(struct platform_device *pdev)
+{
+ struct uart_select *uart_sel;
+ struct uart_select_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ uart_sel = kzalloc(sizeof(struct uart_select), GFP_KERNEL);
+ if (!uart_sel) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, uart_sel);
+ uart_sel->pdata = pdata;
+ init_rwsem(&uart_sel->rwsem);
+
+ uart_saved_state = pdata->get_uart_switch();
+
+ ret = device_create_file(&pdev->dev, &uart_select_attr);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to crreate device file\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devexit uart_select_remove(struct platform_device *pdev)
+{
+ device_remove_file(&pdev->dev, &uart_select_attr);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver uart_select_driver = {
+ .probe = uart_select_probe,
+ .remove = __devexit_p(uart_select_remove),
+ .driver = {
+ .name = "uart-select",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init uart_select_init(void)
+{
+ return platform_driver_register(&uart_select_driver);
+}
+module_init(uart_select_init);
+
+static void __exit uart_select_exit(void)
+{
+ platform_driver_unregister(&uart_select_driver);
+}
+module_exit(uart_select_exit);
+
+MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
+MODULE_DESCRIPTION("UART Selection Driver");
+MODULE_LICENSE("GPL v2");