diff options
author | Ohad Ben-Cohen <ohad@wizery.com> | 2010-04-16 12:23:06 -0500 |
---|---|---|
committer | Hari Kanigeri <h-kanigeri2@ti.com> | 2010-07-09 17:58:21 -0500 |
commit | 369478cf3ef1b2d150da39966c884b8cb2ef3949 (patch) | |
tree | 3ca7c4a15aee0e217ec8b7bed6246e11b10ad970 /arch/arm | |
parent | 52730570f5d7dc00669d6d13222c05ba0189064f (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/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/remoteproc44xx.c | 231 | ||||
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 15 | ||||
-rw-r--r-- | arch/arm/plat-omap/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/remoteproc.h | 75 | ||||
-rw-r--r-- | arch/arm/plat-omap/remoteproc.c | 345 |
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>"); |