mdmgpio: add support/driver for gpio controlled modem (tenderloin)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 9c55cc2..e03550c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -766,6 +766,16 @@
---help---
Generic HSUART engine, which calls platform specific code to facilitate High speed UART driver".
+config MDMGPIO
+ tristate "modem gpio control"
+ depends on SYSFS
+ default n
+ help
+ If you say yes here you get support for modem gpio control.
+
+ This driver can also be built as a module, choose M here: the
+ module will be called mdmgpio.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5cb303a..110403a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -88,3 +88,4 @@
obj-$(CONFIG_USER_PINS) += user-pins.o
obj-$(CONFIG_KERNEL_LOG) += klog.o
obj-$(CONFIG_HSUART) += hsuart.o hsuart_tty.o
+obj-$(CONFIG_MDMGPIO) += mdmgpio.o
diff --git a/drivers/misc/mdmgpio.c b/drivers/misc/mdmgpio.c
new file mode 100644
index 0000000..f8670e5
--- /dev/null
+++ b/drivers/misc/mdmgpio.c
@@ -0,0 +1,230 @@
+/* Copyright (c) 2011, Hewlett-Packard Development Company, All rights reserved.
+ *
+ * mdmgpio.c - Linux kernel modules for modem gppio control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/mdmgpio.h>
+
+static ssize_t uim_cd_gpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int value = 0;
+ struct mdmgpio_platform_data *pdata;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ if (pdata->get_gpio_value)
+ value = pdata->get_gpio_value(pdata->uim_cd_gpio);
+ else
+ return -EINVAL;
+
+ return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t uim_cd_gpio_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t ret = -EINVAL;
+ char *after;
+ struct mdmgpio_platform_data *pdata;
+ unsigned long value = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+
+ if (!pdata)
+ return -EINVAL;
+ if (isspace(*after))
+ count++;
+ if (count == size) {
+ ret = count;
+ if (pdata->set_gpio_value)
+ pdata->set_gpio_value(pdata->uim_cd_gpio, !!value);
+ else
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static ssize_t mdm_disable_gpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int value = 0;
+ struct mdmgpio_platform_data *pdata;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (pdata->get_gpio_value)
+ value = pdata->get_gpio_value(pdata->mdm_disable_gpio);
+ else
+ return -EINVAL;
+
+ return sprintf(buf,"%u\n", value);
+}
+
+static ssize_t mdm_disable_gpio_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t ret = -EINVAL;
+ char *after;
+ struct mdmgpio_platform_data *pdata;
+ unsigned long value = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (isspace(*after))
+ count++;
+ if (count == size) {
+ ret = count;
+ if (pdata->set_gpio_value)
+ pdata->set_gpio_value(pdata->mdm_disable_gpio, !!value);
+ else
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static ssize_t mdm_poweron_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int value = 0;
+ struct mdmgpio_platform_data *pdata;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (pdata->mdm_poweron_status)
+ value = pdata->mdm_poweron_status();
+
+ return sprintf(buf,"%u\n", value);
+}
+
+static ssize_t mdm_poweron_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t ret = -EINVAL;
+ char *after;
+ struct mdmgpio_platform_data *pdata;
+ unsigned long value = simple_strtoul(buf, &after, 10);
+ size_t count = after - buf;
+
+ pdata = (struct mdmgpio_platform_data *)dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (isspace(*after))
+ count++;
+ if (count == size) {
+ ret = count;
+ if (pdata->mdm_poweron)
+ pdata->mdm_poweron(!!value);
+
+ }
+ return ret;
+}
+
+static struct device_attribute mdmgpio_attrs[] = {
+ __ATTR(uim_cd_gpio, 0644, uim_cd_gpio_show, uim_cd_gpio_store),
+ __ATTR(mdm_disable_gpio, 0644, mdm_disable_gpio_show, mdm_disable_gpio_store),
+ __ATTR(mdm_poweron, 0644, mdm_poweron_show, mdm_poweron_store),
+ __ATTR_NULL,
+};
+
+static int mdmgpio_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i;
+ struct mdmgpio_platform_data *pdata;
+
+ printk("%s\n", __func__);
+ pdata = (struct mdmgpio_platform_data *)pdev->dev.platform_data;
+ if (pdata == NULL) {
+ printk(KERN_ERR"%s: null platform data\n", __func__);
+ return -EINVAL;
+ }
+
+ for( i = 0; attr_name(mdmgpio_attrs[i]); i++) {
+ ret = device_create_file(&pdev->dev, &mdmgpio_attrs[i]);
+ if (ret < 0) {
+ printk(KERN_ERR "%s:failed to create sysfs file %s\n",
+ __func__, attr_name(mdmgpio_attrs[i]));
+ break;
+ }
+ }
+ if (ret < 0)
+ while(--i >= 0)
+ device_remove_file(&pdev->dev, &mdmgpio_attrs[i]);
+
+ return ret;
+}
+
+static int mdmgpio_remove(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i;
+ struct mdmgpio_platform_data *pdata;
+
+ printk("%s\n", __func__);
+
+ pdata = (struct mdmgpio_platform_data *)pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ for(i = 0; attr_name(mdmgpio_attrs[i]); i++) {
+ device_remove_file(&pdev->dev, &mdmgpio_attrs[i]);
+ }
+ return ret;
+}
+
+static struct platform_driver mdmgpio_driver = {
+ .probe = mdmgpio_probe,
+ .remove = mdmgpio_remove,
+ .driver = {
+ .name = "mdmgpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init mdmgpio_init(void)
+{
+ printk("%s\n", __func__);
+ platform_driver_register(&mdmgpio_driver);
+ return 0;
+}
+
+static void __exit mdmgpio_exit(void)
+{
+ printk("%s\n", __func__);
+ platform_driver_unregister(&mdmgpio_driver);
+}
+
+module_init(mdmgpio_init);
+module_exit(mdmgpio_exit);
+
+MODULE_AUTHOR("Hao Song<hao.song@hp.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/mdmgpio.h b/include/linux/mdmgpio.h
new file mode 100644
index 0000000..e143083
--- /dev/null
+++ b/include/linux/mdmgpio.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2010, Hewlett-Packard Development Company, L.P. All rights reserved.
+ *
+ * mdmgpio.h - Linux kernel modules for modem gpio control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_MDMGPIO_H
+#define __LINUX_MDMGPIO_H
+
+
+struct mdmgpio_platform_data {
+ int uim_cd_gpio;
+ int mdm_disable_gpio;
+ int (*get_gpio_value)(int gpionum);
+ int (*set_gpio_value)(int gpionum, int value);
+ int (*mdm_poweron)(int on);
+ int (*mdm_poweron_status)(void);
+};
+#endif
\ No newline at end of file