diff --git a/drivers/Kconfig b/drivers/Kconfig
index ece958d..dc7c14a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -152,4 +152,6 @@ source "drivers/vme/Kconfig"
source "drivers/pwm/Kconfig"
+source "drivers/modem_shm/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 5b42184..902dfec 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -139,3 +139,4 @@ obj-$(CONFIG_EXTCON) += extcon/
obj-$(CONFIG_MEMORY) += memory/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
+obj-$(CONFIG_MODEM_SHM) += modem_shm/
diff --git a/drivers/modem_shm/Kconfig b/drivers/modem_shm/Kconfig
new file mode 100644
index 0000000..f4b7e54
--- /dev/null
+++ b/drivers/modem_shm/Kconfig
@@ -0,0 +1,9 @@
+config MODEM_SHM
+ bool "Modem Access Framework"
+ default n
+ help
+ Add support for Modem Access Framework. It allows different
+ platform specific drivers to register modem access mechanisms
+ and allows transparent access to modem to the client drivers.
+
+ If unsure, say N.
diff --git a/drivers/modem_shm/Makefile b/drivers/modem_shm/Makefile
new file mode 100644
index 0000000..b77bcc0
--- /dev/null
+++ b/drivers/modem_shm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MODEM_SHM) := modem_access.o
diff --git a/drivers/modem_shm/modem_access.c b/drivers/modem_shm/modem_access.c
new file mode 100644
index 0000000..540234d
--- /dev/null
+++ b/drivers/modem_shm/modem_access.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi
+ * Arun Murthy <arun.murthy@stericsson.com>
+ *
+ * Heavily adapted from Regulator framework.
+ * Provides mechanisms for registering platform specific access
+ * mechanisms for modem.
+ * Also, exposes APIs for gettng/releasing the access and even
+ * query the access status, and the modem usage status.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/printk.h>
+#include <linux/modem_shm/modem.h>
+
+static struct class *modem_class;
+
+static int __modem_is_requested(struct device *dev, void *data)
+{
+ struct modem_desc *mdesc = (struct modem_desc *)data;
+
+ if (!mdesc->mclients) {
+ printk(KERN_ERR "modem_access: modem description is NULL\n");
+ return 0;
+ }
+ return atomic_read(&mdesc->mclients->cnt);
+}
+
+int modem_is_requested(struct modem_desc *mdesc)
+{
+ return class_for_each_device(modem_class, NULL, (void *)mdesc, __modem_is_requested);
+}
+
+int modem_release(struct modem_desc *mdesc)
+{
+ if (!mdesc->release)
+ return -EFAULT;
+
+ if (modem_is_requested(mdesc)) {
+ atomic_dec(&mdesc->mclients->cnt);
+ if (atomic_read(&mdesc->use_cnt) == 1) {
+ mdesc->release(mdesc);
+ atomic_dec(&mdesc->use_cnt);
+ }
+ } else
+ printk(KERN_WARNING
+ "modem_shm: client %s has not requested modem to release\n",
+ mdesc->mclients->name);
+ return 0;
+}
+
+int modem_request(struct modem_desc *mdesc)
+{
+ if (!mdesc->request)
+ return -EFAULT;
+
+ if (atomic_read(&mdesc->mclients->cnt) == 0) {
+ mdesc->request(mdesc);
+ atomic_inc(&mdesc->mclients->cnt);
+ atomic_inc(&mdesc->use_cnt);
+ if (atomic_read(&mdesc->use_cnt) > mdesc->no_clients) {
+ dev_warn(mdesc->dev,
+ "modem_shm: mismatch in the modem count\n");
+ }
+ } else
+ dev_warn(mdesc->dev,
+ "modem_shm: client '%s' has already requested modem\n",
+ dev_name(mdesc->mclients->dev));
+ return 0;
+}
+
+int modem_put(struct modem_desc *mdesc)
+{
+ if (atomic_read(&mdesc->cli_cnt)) {
+ atomic_dec(&mdesc->cli_cnt);
+ kfree(mdesc->mclients);
+ return 0;
+ } else {
+ dev_err(mdesc->dev, "mismatch in the no of clients\n");
+ return -EFAULT;
+ }
+}
+
+static int modem_match_device_by_name(struct device *dev, void *data)
+{
+ const char *name = data;
+ struct modem_desc *mdesc = dev_get_drvdata(dev);
+
+ return strcmp(mdesc->name, name) == 0;
+}
+
+struct modem_desc *modem_get(struct device *pdev, const char *name)
+{
+ struct clients *mcli;
+ struct modem_desc *mdesc = NULL;
+ struct device *dev = class_find_device(modem_class, NULL, (void *)name,
+ modem_match_device_by_name);
+ mdesc = dev ? dev_get_drvdata(dev): NULL;
+ if (mdesc) {
+ if (atomic_read(&mdesc->cli_cnt) >= mdesc->no_clients) {
+ dev_err(pdev, "already %d clients have requested\n",
+ mdesc->no_clients);
+ return NULL;
+ }
+ mcli = kzalloc(sizeof(struct clients), GFP_KERNEL);
+ if (!mcli) {
+ dev_err(pdev, "uanable to allocate memory\n");
+ return NULL;
+ }
+ mdesc->mclients = mcli;
+ mdesc->mclients->dev = pdev;
+ atomic_inc(&mdesc->cli_cnt);
+ atomic_set(&mdesc->mclients->cnt, 0);
+ }
+ return mdesc;
+}
+
+int modem_register(struct device *parent, struct modem_desc *mdesc)
+{
+ mdesc->dev = device_create(modem_class, parent, 0, mdesc, "%s", mdesc->name);
+ if (IS_ERR(mdesc->dev)) {
+ dev_err(parent, "failed to create device\n");
+ return PTR_ERR(mdesc->dev);
+ }
+
+ atomic_set(&mdesc->use_cnt, 0);
+ atomic_set(&mdesc->cli_cnt, 0);
+ return 0;
+}
+
+int modem_unregister(struct modem_desc *mdesc)
+{
+ device_unregister(mdesc->dev);
+ return 0;
+}
+
+static int modem_init(void)
+{
+ modem_class = class_create(THIS_MODULE, "modem_access");
+ if (IS_ERR(modem_class)) {
+ printk(KERN_ERR "modem_access: unable to create class\n");
+ return PTR_ERR(modem_class);
+ }
+
+ if (modem_class == NULL || IS_ERR(modem_class))
+ printk(KERN_ERR "modem_access: MODEM ERR0R");
+
+ return 0;
+}
+
+static void modem_exit(void)
+{
+ class_destroy(modem_class);
+}
+
+arch_initcall(modem_init);
+module_exit(modem_exit);diff --git a/include/linux/modem_shm/modem.h b/include/linux/modem_shm/modem.h
new file mode 100644
index 0000000..0addf48
--- /dev/null
+++ b/include/linux/modem_shm/modem.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi
+ * Arun Murthy <arun.murthy@stericsson.com>
+ *
+ * Heavily adapted from Regulator framework
+ */
+#ifndef __MODEM_H__
+#define __MODEM_H__
+
+#include <linux/device.h>
+
+struct clients {
+ struct device *dev;
+ const char *name;
+ atomic_t cnt;
+};
+
+struct modem_desc {
+ int (*request)(struct modem_desc *);
+ void (*release)(struct modem_desc *);
+ int (*is_requested)(struct modem_desc *);
+ struct clients *mclients;
+ struct device *dev;
+ char *name;
+ u8 no_clients;
+ atomic_t use_cnt;
+ atomic_t cli_cnt;
+};
+
+#ifdef CONFIG_MODEM_SHM
+int modem_register(struct device *parent, struct modem_desc *mdesc);
+int modem_unregister(struct modem_desc *mdesc);
+struct modem_desc *modem_get(struct device *dev, const char *name);
+int modem_put(struct modem_desc *mdesc);
+int modem_release(struct modem_desc *mdesc);
+int modem_is_requested(struct modem_desc *mdesc);
+int modem_request(struct modem_desc *mdesc);
+
+
+#else
+int modem_register(struct device *parent, struct modem_desc *mdesc)
+{
+ return NULL;
+}
+
+static inline int modem_unregister(struct modem_desc *mdesc)
+{
+ return NULL;
+}
+#endif
+#endif /* __MODEM_H__ */--
1.7.4.3