summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2010-04-16 12:23:06 -0500
committerHari Kanigeri <h-kanigeri2@ti.com>2010-07-09 17:58:21 -0500
commit369478cf3ef1b2d150da39966c884b8cb2ef3949 (patch)
tree3ca7c4a15aee0e217ec8b7bed6246e11b10ad970 /arch/arm
parent52730570f5d7dc00669d6d13222c05ba0189064f (diff)
ARM: Initial Proc support.
This is the initial proc support. Hari: Adapted changes to OMAP4. This still needs following changes: 1. Adapt to hwmod 2. Support to OMAP3 Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/Makefile6
-rw-r--r--arch/arm/mach-omap2/remoteproc44xx.c231
-rw-r--r--arch/arm/plat-omap/Kconfig15
-rw-r--r--arch/arm/plat-omap/Makefile1
-rw-r--r--arch/arm/plat-omap/include/plat/remoteproc.h75
-rw-r--r--arch/arm/plat-omap/remoteproc.c345
6 files changed, 673 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 84c36d09f9a7..6c4afe050c2a 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -114,6 +114,12 @@ endif
iommu-y += iommu2.o omap-iommu.o
obj-$(CONFIG_OMAP_IOMMU) += $(iommu-y)
+ifeq ($(CONFIG_OMAP_REMOTE_PROC),y)
+obj-$(CONFIG_ARCH_OMAP2) += remoteproc24xx.o
+obj-$(CONFIG_ARCH_OMAP3) += remoteproc3xxx.o
+obj-$(CONFIG_ARCH_OMAP4) += remoteproc44xx.o
+endif
+
i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
obj-y += $(i2c-omap-m) $(i2c-omap-y)
diff --git a/arch/arm/mach-omap2/remoteproc44xx.c b/arch/arm/mach-omap2/remoteproc44xx.c
new file mode 100644
index 000000000000..7c082cf13ab1
--- /dev/null
+++ b/arch/arm/mach-omap2/remoteproc44xx.c
@@ -0,0 +1,231 @@
+/*
+ * Remote Processor machine-specific module for OMAP3
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <plat/remoteproc.h>
+#include <mach/irqs.h>
+#include <plat/omap_device.h>
+
+#include "cm.h"
+#include "prm.h"
+
+#define RM_M3_RST1ST 0x1
+#define RM_M3_RST2ST 0x2
+#define RM_M3_RST3ST 0x4
+#define RM_M3_REL_RST1_MASK 0x2
+#define RM_M3_REL_RST2_MASK 0x0
+#define RM_M3_AST_RST1_MASK 0x3
+#define RM_M3_AST_RST2_MASK 0x2
+
+#define M3_CLK_MOD_MODE_HW_AUTO 0x1
+#define M3_CLKTRCTRL_SW_WKUP 0x2
+#define M3_CLKTRCTRL_SW_SLEEP 0x1
+#define M3_CLKACTIVITY_MPU_M3_CLK 0x100
+
+static inline int proc44x_sysm3_start(struct omap_rproc *rproc)
+{
+ u32 reg;
+ int counter = 10;
+ struct device *dev = rproc->dev;
+
+ /* Module is managed automatically by HW */
+ cm_write_mod_reg(M3_CLK_MOD_MODE_HW_AUTO, OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET);
+
+ /* Enable the M3 clock */
+ cm_write_mod_reg(M3_CLKTRCTRL_SW_WKUP, OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);
+ do {
+ reg = cm_read_mod_reg(OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);
+ if (reg & M3_CLKACTIVITY_MPU_M3_CLK) {
+ dev_info(dev, "M3 clock enabled:"
+ "OMAP4430_CM_DUCATI_CLKSTCTRL = 0x%x\n", reg);
+ break;
+ }
+ msleep(1);
+ } while (--counter);
+ if (counter == 0) {
+ dev_info(dev, "FAILED TO ENABLE DUCATI M3 CLOCK !%x\n", reg);
+ return -EFAULT;
+ }
+
+ /* De-assert RST1, and clear the Reset status */
+ dev_info(dev, "De-assert RST1\n");
+ prm_write_mod_reg(RM_M3_REL_RST1_MASK, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTCTRL_OFFSET);
+ while (!(prm_read_mod_reg(OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTST_OFFSET) & RM_M3_RST1ST))
+ ;
+ dev_info(dev, "RST1 released!");
+
+ prm_write_mod_reg(RM_M3_RST1ST, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTST_OFFSET);
+
+ return 0;
+}
+
+static inline int proc44x_appm3_start(struct omap_rproc *rproc)
+{
+ struct device *dev = rproc->dev;
+
+ /* De-assert RST2, and clear the Reset status */
+ dev_info(dev, "De-assert RST2\n");
+ prm_write_mod_reg(RM_M3_REL_RST2_MASK, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTCTRL_OFFSET);
+
+ while (!(prm_read_mod_reg(OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTST_OFFSET) & RM_M3_RST2ST))
+ ;
+ dev_info(dev, "RST2 released!");
+
+ prm_write_mod_reg(RM_M3_RST2ST, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTST_OFFSET);
+
+ return 0;
+}
+
+static inline int proc44x_sysm3_stop(struct omap_rproc *rproc)
+{
+ struct device *dev = rproc->dev;
+
+ dev_info(dev, "assert RST1\n");
+ prm_write_mod_reg(RM_M3_AST_RST1_MASK, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTCTRL_OFFSET);
+ /* Disable the M3 clock */
+ cm_write_mod_reg(M3_CLKTRCTRL_SW_SLEEP, OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);
+ return 0;
+}
+
+static inline int proc44x_appm3_stop(struct omap_rproc *rproc)
+{
+ struct device *dev = rproc->dev;
+
+ dev_info(dev, "assert RST2\n");
+ prm_write_mod_reg(RM_M3_AST_RST2_MASK, OMAP4430_PRM_CORE_MOD,
+ OMAP4_RM_DUCATI_RSTCTRL_OFFSET);
+ return 0;
+}
+
+static inline int omap4_rproc_get_state(struct omap_rproc *rproc)
+{
+ return rproc->state;
+}
+
+static struct omap_rproc_ops omap4_ducati0_ops = {
+ .start = proc44x_sysm3_start,
+ .stop = proc44x_sysm3_stop,
+ .get_state = omap4_rproc_get_state,
+};
+
+static struct omap_rproc_ops omap4_ducati1_ops = {
+ .start = proc44x_appm3_start,
+ .stop = proc44x_appm3_stop,
+ .get_state = omap4_rproc_get_state,
+};
+
+static struct omap_rproc_ops omap4_tesla_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
+static struct omap_rproc_platform_data omap4_rproc_data[] = {
+ {
+ .name = "tesla",
+ .ops = &omap4_tesla_ops,
+ .oh_name = "tesla_hwmod",
+ },
+ {
+ .name = "ducati-proc0",
+ .ops = &omap4_ducati0_ops,
+ .oh_name = "ducati_hwmod0",
+ },
+ {
+ .name = "ducati-proc1",
+ .ops = &omap4_ducati1_ops,
+ .oh_name = "ducati_hwmod1",
+ },
+};
+
+struct omap_rproc_platform_data *remoteproc_get_plat_data(void)
+{
+ return omap4_rproc_data;
+}
+
+int remoteproc_get_plat_data_size(void)
+{
+ return ARRAY_SIZE(omap4_rproc_data);
+}
+EXPORT_SYMBOL(remoteproc_get_plat_data_size);
+
+
+#define NR_RPROC_DEVICES ARRAY_SIZE(omap4_rproc_data)
+
+static struct platform_device *omap4_rproc_pdev[NR_RPROC_DEVICES];
+
+static int __init omap4_rproc_init(void)
+{
+ int i, err;
+
+ for (i = 0; i < NR_RPROC_DEVICES; i++) {
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("omap-remoteproc", i);
+ if (!pdev) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = platform_device_add_data(pdev, &omap4_rproc_data[i],
+ sizeof(omap4_rproc_data[0]));
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_out;
+ omap4_rproc_pdev[i] = pdev;
+ }
+ return 0;
+
+err_out:
+ while (i--)
+ platform_device_put(omap4_rproc_pdev[i]);
+ return err;
+}
+module_init(omap4_rproc_init);
+
+static void __exit omap4_rproc_exit(void)
+{
+ int i;
+
+ for (i = 0; i < NR_RPROC_DEVICES; i++)
+ platform_device_unregister(omap4_rproc_pdev[i]);
+}
+module_exit(omap4_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP4 Remote Processor module");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
+MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@ti.com>");
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 33256d8a9003..a5a473a88050 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -147,6 +147,21 @@ config OMAP_MBOX_FWK
Say Y here if you want to use OMAP Mailbox framework support for
DSP, IVA1.0 and IVA2 in OMAP1/2/3.
+config OMAP_REMOTE_PROC
+ bool "Remote Processor framework support"
+ depends on ARCH_OMAP
+ help
+ Say Y here if you want to use OMAP Remote Processor framework
+ support for DSP, IVA, Tesla and Ducati (OMAP2/3/4).
+
+config OMAP_RPROC_MEMPOOL_SIZE
+ hex "Physical memory pool size for remote processor (in bytes)"
+ depends on OMAP_REMOTE_PROC
+ default 0x600000
+ help
+ Allocate specified size of memory at booting time to avoid allocation
+ failure under heavy memory fragmentation after some use time.
+
config OMAP_IOMMU
tristate
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index faf831d27918..4cd4ebd9dd01 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -36,5 +36,6 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
+obj-$(CONFIG_OMAP_REMOTE_PROC) += remoteproc.o
obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o \ No newline at end of file
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h
new file mode 100644
index 000000000000..351553d18fc4
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/remoteproc.h
@@ -0,0 +1,75 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Ohad Ben-Cohen <ohad@wizery.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef REMOTEPROC_H
+#define REMOTEPROC_H
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+
+#define RPROC_IOC_MAGIC 'P'
+
+#define RPROC_IOCMONITOR _IO(RPROC_IOC_MAGIC, 0)
+#define RPROC_IOCSTART _IO(RPROC_IOC_MAGIC, 1)
+#define RPROC_IOCSTOP _IO(RPROC_IOC_MAGIC, 2)
+#define RPROC_IOCGETSTATE _IOR(RPROC_IOC_MAGIC, 3, int)
+
+#define RPROC_IOC_MAXNR (3)
+
+struct omap_rproc;
+
+struct omap_rproc_ops {
+ int (*startup)(struct omap_rproc *rproc);
+ int (*shutdown)(struct omap_rproc *rproc);
+ int (*start)(struct omap_rproc *rproc);
+ int (*stop)(struct omap_rproc *rproc);
+ int (*get_state)(struct omap_rproc *rproc);
+};
+
+struct omap_rproc_clk_t {
+ void *clk_handle;
+ const char *dev_id;
+ const char *con_id;
+};
+
+struct omap_rproc_platform_data {
+ struct omap_rproc_ops *ops;
+ char *name;
+ char *oh_name;
+};
+
+struct omap_rproc {
+ struct device *dev;
+ struct cdev cdev;
+ atomic_t count;
+ int state;
+ int minor;
+};
+
+extern struct omap_rproc_platform_data *remoteproc_get_plat_data(void);
+extern int remoteproc_get_plat_data_size(void);
+
+struct omap_rproc *rproc_get(const char *name);
+void rproc_put(struct omap_rproc *obj);
+
+#endif /* REMOTEPROC_H */
diff --git a/arch/arm/plat-omap/remoteproc.c b/arch/arm/plat-omap/remoteproc.c
new file mode 100644
index 000000000000..95a272fb91c9
--- /dev/null
+++ b/arch/arm/plat-omap/remoteproc.c
@@ -0,0 +1,345 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Ohad Ben-Cohen <ohad@wizery.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <plat/remoteproc.h>
+
+#define OMAP_RPROC_NAME "omap-rproc"
+#define DRV_NAME "omap-remoteproc"
+
+static struct class *omap_rproc_class;
+static dev_t omap_rproc_dev;
+static atomic_t num_of_rprocs;
+static struct platform_driver omap_rproc_driver;
+
+static inline int rproc_start(struct omap_rproc *rproc)
+{
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ return pdata->ops->start(rproc);
+}
+
+static inline int rproc_stop(struct omap_rproc *rproc)
+{
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ return pdata->ops->stop(rproc);
+}
+
+static inline int rproc_get_state(struct omap_rproc *rproc)
+{
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ return pdata->ops->get_state(rproc);
+}
+static int omap_rproc_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct omap_rproc *rproc;
+ struct omap_rproc_platform_data *pdata;
+
+ rproc = container_of(inode->i_cdev, struct omap_rproc, cdev);
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+
+ if (pdata->ops->startup) {
+ ret = pdata->ops->startup(rproc);
+ if (ret)
+ goto out;
+ }
+ filp->private_data = rproc;
+
+out:
+ return ret;
+}
+
+static int omap_rproc_release(struct inode *inode, struct file *filp)
+{
+ struct omap_rproc_platform_data *pdata;
+ struct omap_rproc *rproc = filp->private_data;
+ if (!rproc || !rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+
+ if (pdata->ops->shutdown)
+ pdata->ops->shutdown(rproc);
+
+ return 0;
+}
+
+static int omap_rproc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ struct omap_rproc *rproc = filp->private_data;
+
+ if (!rproc)
+ return -EINVAL;
+
+ if (_IOC_TYPE(cmd) != RPROC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > RPROC_IOC_MAXNR)
+ return -ENOTTY;
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ return -EFAULT;
+ } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (!access_ok(VERIFY_READ, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case RPROC_IOCSTART:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ rc = rproc_start(rproc);
+ break;
+ case RPROC_IOCSTOP:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ rc = rproc_stop(rproc);
+ break;
+ case RPROC_IOCGETSTATE:
+ rc = rproc_get_state(rproc);
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return rc;
+}
+
+static int omap_rproc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+ vma->vm_flags |= VM_RESERVED;
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static const struct file_operations omap_rproc_fops = {
+ .open = omap_rproc_open,
+ .release = omap_rproc_release,
+ .ioctl = omap_rproc_ioctl,
+ .mmap = omap_rproc_mmap,
+ .owner = THIS_MODULE,
+};
+
+static int omap_rproc_probe(struct platform_device *pdev)
+{
+ int ret = 0, major, minor;
+ struct device *tmpdev;
+ struct device *dev = &pdev->dev;
+ struct omap_rproc_platform_data *pdata = dev->platform_data;
+ struct omap_rproc *rproc;
+
+ if (!pdata || !pdata->name || !pdata->oh_name || !pdata->ops)
+ return -EINVAL;
+
+ dev_info(dev, "%s: adding rproc %s\n", __func__, pdata->name);
+
+ rproc = kzalloc(sizeof(struct omap_rproc), GFP_KERNEL);
+ if (!rproc) {
+ dev_err(dev, "%s: kzalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, rproc);
+ major = MAJOR(omap_rproc_dev);
+ minor = atomic_read(&num_of_rprocs);
+ atomic_inc(&num_of_rprocs);
+
+ rproc->dev = dev;
+ rproc->minor = minor;
+
+ cdev_init(&rproc->cdev, &omap_rproc_fops);
+ rproc->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&rproc->cdev, MKDEV(major, minor), 1);
+ if (ret) {
+ dev_err(dev, "%s: cdev_add failed: %d\n", __func__, ret);
+ goto free_rproc;
+ }
+
+ tmpdev = device_create(omap_rproc_class, NULL,
+ MKDEV(major, minor),
+ NULL,
+ OMAP_RPROC_NAME "%d", minor);
+ if (IS_ERR(tmpdev)) {
+ ret = PTR_ERR(tmpdev);
+ pr_err("%s: device_create failed: %d\n", __func__, ret);
+ goto clean_cdev;
+ }
+
+ pr_info("%s initialized %s, major: %d, base-minor: %d\n",
+ OMAP_RPROC_NAME,
+ pdata->name,
+ MAJOR(omap_rproc_dev),
+ minor);
+ return 0;
+
+clean_cdev:
+ cdev_del(&rproc->cdev);
+free_rproc:
+ kfree(rproc);
+out:
+ return ret;
+}
+
+static int omap_rproc_remove(struct platform_device *pdev)
+{
+ int major = MAJOR(omap_rproc_dev);
+ struct device *dev = &pdev->dev;
+ struct omap_rproc_platform_data *pdata = dev->platform_data;
+ struct omap_rproc *rproc = platform_get_drvdata(pdev);
+
+ if (!pdata || !rproc)
+ return -EINVAL;
+
+ dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n",
+ OMAP_RPROC_NAME,
+ pdata->name,
+ major,
+ rproc->minor);
+
+ device_destroy(omap_rproc_class, MKDEV(major, rproc->minor));
+ cdev_del(&rproc->cdev);
+
+ return 0;
+}
+
+#ifndef CONFIG_PM
+#define omap_rproc_suspend NULL
+#define omap_rproc_resume NULL
+#define omap_rproc_runtime_suspend NULL
+#define omap_rproc_runtime_resume NULL
+#endif
+
+
+const static struct dev_pm_ops omap_rproc_dev_pm_ops = {
+ .suspend = omap_rproc_suspend,
+ .resume = omap_rproc_resume,
+ .runtime_suspend = omap_rproc_runtime_suspend,
+ .runtime_resume = omap_rproc_runtime_resume,
+};
+
+static struct platform_driver omap_rproc_driver = {
+ .probe = omap_rproc_probe,
+ .remove = omap_rproc_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &omap_rproc_dev_pm_ops,
+ },
+};
+
+
+static int __init omap_rproc_init(void)
+{
+ int num = remoteproc_get_plat_data_size();
+ int ret;
+
+ ret = alloc_chrdev_region(&omap_rproc_dev, 0, num, OMAP_RPROC_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
+ goto out;
+ }
+
+ omap_rproc_class = class_create(THIS_MODULE, OMAP_RPROC_NAME);
+ if (IS_ERR(omap_rproc_class)) {
+ ret = PTR_ERR(omap_rproc_class);
+ pr_err("%s: class_create failed: %d\n", __func__, ret);
+ goto unreg_region;
+ }
+
+ atomic_set(&num_of_rprocs, 0);
+
+ ret = platform_driver_register(&omap_rproc_driver);
+ if (ret) {
+ pr_err("%s: platform_driver_register failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+ return 0;
+unreg_region:
+ unregister_chrdev_region(omap_rproc_dev, num);
+out:
+ return ret;
+}
+module_init(omap_rproc_init);
+
+static void __exit omap_rproc_exit(void)
+{
+ int num = remoteproc_get_plat_data_size();
+ pr_info("%s\n", __func__);
+ class_destroy(omap_rproc_class);
+ unregister_chrdev_region(omap_rproc_dev, num);
+}
+module_exit(omap_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor driver");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
+MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@ti.com>");