diff options
author | Angela Stegmaier <angelabaker@ti.com> | 2010-09-09 10:10:25 -0500 |
---|---|---|
committer | Ricardo Perez Olivares <x0081762@ti.com> | 2010-09-14 19:28:55 -0500 |
commit | 5ce43feeb813cb212f233a361ae96f4412fc23a4 (patch) | |
tree | e04b0e0b750f51f1c8f0321c36628a81b6d1ff08 /drivers/dsp/syslink/devh | |
parent | 21c0be13701968b9e995c79fd3f2dfc53f5596be (diff) |
SYSLINK:devh: adding devh to syslink tree
This patch adds devh to syslink tree
Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Diffstat (limited to 'drivers/dsp/syslink/devh')
-rw-r--r-- | drivers/dsp/syslink/devh/44xx/Kbuild | 7 | ||||
-rw-r--r-- | drivers/dsp/syslink/devh/44xx/devh44xx.c | 720 | ||||
-rw-r--r-- | drivers/dsp/syslink/devh/Kbuild | 7 | ||||
-rw-r--r-- | drivers/dsp/syslink/devh/devh.c | 261 | ||||
-rw-r--r-- | drivers/dsp/syslink/devh/devh.h | 64 |
5 files changed, 1059 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/devh/44xx/Kbuild b/drivers/dsp/syslink/devh/44xx/Kbuild new file mode 100644 index 000000000000..1cc02051301f --- /dev/null +++ b/drivers/dsp/syslink/devh/44xx/Kbuild @@ -0,0 +1,7 @@ + +obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh44xx.o + +ccflags-y += -Wno-strict-prototypes + +#Header files +ccflags-y += -Iarch/arm/plat-omap/include/syslink diff --git a/drivers/dsp/syslink/devh/44xx/devh44xx.c b/drivers/dsp/syslink/devh/44xx/devh44xx.c new file mode 100644 index 000000000000..0e1d09b09d0c --- /dev/null +++ b/drivers/dsp/syslink/devh/44xx/devh44xx.c @@ -0,0 +1,720 @@ +/* + * Device Handler machine-specific module for OMAP4 + * + * 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 <linux/sched.h> +#include <mach/irqs.h> +#include <plat/omap_device.h> +#include <plat/iommu.h> +#include <plat/remoteproc.h> +#if defined(CONFIG_TILER_OMAP) +#include <mach/tiler.h> +#endif + +#include <syslink/ipc.h> + +#include "../devh.h" +#include "../../ipu_pm/ipu_pm.h" + +static struct mutex local_gate; + +struct omap_devh_runtime_info { + int brd_state; + struct iommu *iommu; + struct omap_rproc *rproc; +}; + +enum { + DEVH_BRDST_RUNNING, + DEVH_BRDST_STOPPED, + DEVH_BRDST_ERROR, +}; + +static struct omap_devh_platform_data *devh_get_plat_data_by_name(char *name) +{ + int i, j = devh_get_plat_data_size(); + struct omap_devh_platform_data *pdata = devh_get_plat_data(); + + if (name) { + for (i = 0; i < j; i++) { + if (!(strcmp(name, pdata[i].name))) + return &pdata[i]; + } + } + return NULL; +} + +static int devh44xx_notifier_call(struct notifier_block *nb, + unsigned long val, void *v, + struct omap_devh_platform_data *pdata) +{ + int err = 0; + pid_t my_pid = current->tgid; + struct omap_devh_runtime_info *pinfo = NULL; + struct omap_devh_platform_data *pdata2 = NULL; + + if (pdata) + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + else + return -EINVAL; + + if (pinfo->brd_state == DEVH_BRDST_RUNNING) { + err = mutex_lock_interruptible(&local_gate); + if (err) + goto exit; + err = ipu_pm_notifications(PM_PID_DEATH, (void *)my_pid); + if (err) { + pinfo->brd_state = DEVH_BRDST_ERROR; + if (!strcmp(pdata->name, "SysM3")) { + pdata2 = devh_get_plat_data_by_name("AppM3"); + if (pdata2) { + pinfo = + (struct omap_devh_runtime_info *) + pdata2->private_data; + pinfo->brd_state = DEVH_BRDST_ERROR; + } + } + } + mutex_unlock(&local_gate); + } + +exit: + return err; +} + +static int devh44xx_sysm3_iommu_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("SysM3"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (!pdata) + return 0; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + switch ((int)val) { + case IOMMU_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + case IOMMU_FAULT: + pinfo->brd_state = DEVH_BRDST_ERROR; + return 0; + default: + return 0; + } +} + +static int devh44xx_appm3_iommu_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("AppM3"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (!pdata) + return 0; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + switch ((int)val) { + case IOMMU_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + case IOMMU_FAULT: + pinfo->brd_state = DEVH_BRDST_ERROR; + return 0; + default: + return 0; + } +} + +static int devh44xx_tesla_iommu_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("Tesla"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (!pdata) + return 0; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + switch ((int)val) { + case IOMMU_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + case IOMMU_FAULT: + pinfo->brd_state = DEVH_BRDST_ERROR; + return 0; + default: + return 0; + } +} + +static struct notifier_block devh_notify_nb_iommu_tesla = { + .notifier_call = devh44xx_tesla_iommu_notifier_call, +}; +static struct notifier_block devh_notify_nb_iommu_ducati0 = { + .notifier_call = devh44xx_sysm3_iommu_notifier_call, +}; +static struct notifier_block devh_notify_nb_iommu_ducati1 = { + .notifier_call = devh44xx_appm3_iommu_notifier_call, +}; + +static int devh44xx_sysm3_ipc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("SysM3"); + + switch ((int)val) { + case IPC_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static int devh44xx_appm3_ipc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("AppM3"); + + switch ((int)val) { + case IPC_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static int devh44xx_tesla_ipc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("Tesla"); + + switch ((int)val) { + case IPC_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static struct notifier_block devh_notify_nb_ipc_tesla = { + .notifier_call = devh44xx_tesla_ipc_notifier_call, +}; +static struct notifier_block devh_notify_nb_ipc_ducati1 = { + .notifier_call = devh44xx_appm3_ipc_notifier_call, +}; +static struct notifier_block devh_notify_nb_ipc_ducati0 = { + .notifier_call = devh44xx_sysm3_ipc_notifier_call, +}; + +static int devh44xx_sysm3_rproc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("SysM3"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (pdata) + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + else + return -EINVAL; + + switch ((int)val) { + case OMAP_RPROC_START: + pinfo->brd_state = DEVH_BRDST_RUNNING; + pinfo->iommu = iommu_get("ducati"); + if (pinfo->iommu != ERR_PTR(-ENODEV) && + pinfo->iommu != ERR_PTR(-EINVAL)) + iommu_register_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati0); + else + pinfo->iommu = NULL; + return 0; + case OMAP_RPROC_STOP: + pinfo->brd_state = DEVH_BRDST_STOPPED; + if (pinfo->iommu != NULL) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati0); + iommu_put(pinfo->iommu); + pinfo->iommu = NULL; + } + return 0; + default: + return 0; + } +} + +static int devh44xx_appm3_rproc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("AppM3"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (pdata) + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + else + return -EINVAL; + + switch ((int)val) { + case OMAP_RPROC_START: + pinfo->brd_state = DEVH_BRDST_RUNNING; + pinfo->iommu = iommu_get("ducati"); + if (pinfo->iommu != ERR_PTR(-ENODEV) && + pinfo->iommu != ERR_PTR(-EINVAL)) + iommu_register_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati1); + else + pinfo->iommu = NULL; + return 0; + case OMAP_RPROC_STOP: + pinfo->brd_state = DEVH_BRDST_STOPPED; + if (pinfo->iommu != NULL) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati1); + iommu_put(pinfo->iommu); + pinfo->iommu = NULL; + } + return 0; + default: + return 0; + } +} + +static int devh44xx_tesla_rproc_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("Tesla"); + struct omap_devh_runtime_info *pinfo = NULL; + + if (pdata) + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + else + return -EINVAL; + + switch ((int)val) { + case OMAP_RPROC_START: + pinfo->brd_state = DEVH_BRDST_RUNNING; + pinfo->iommu = iommu_get("tesla"); + if (pinfo->iommu != ERR_PTR(-ENODEV) && + pinfo->iommu != ERR_PTR(-EINVAL)) + iommu_register_notifier(pinfo->iommu, + &devh_notify_nb_iommu_tesla); + else + pinfo->iommu = NULL; + return 0; + case OMAP_RPROC_STOP: + pinfo->brd_state = DEVH_BRDST_STOPPED; + if (pinfo->iommu != NULL) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_tesla); + iommu_put(pinfo->iommu); + pinfo->iommu = NULL; + } + return 0; + default: + return 0; + } +} + +static struct notifier_block devh_notify_nb_rproc_tesla = { + .notifier_call = devh44xx_tesla_rproc_notifier_call, +}; +static struct notifier_block devh_notify_nb_rproc_ducati0 = { + .notifier_call = devh44xx_sysm3_rproc_notifier_call, +}; +static struct notifier_block devh_notify_nb_rproc_ducati1 = { + .notifier_call = devh44xx_appm3_rproc_notifier_call, +}; + +#if defined(CONFIG_TILER_OMAP) +static int devh44xx_sysm3_tiler_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("SysM3"); + + switch ((int)val) { + case TILER_DEVICE_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static int devh44xx_appm3_tiler_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("AppM3"); + + switch ((int)val) { + case TILER_DEVICE_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static int devh44xx_tesla_tiler_notifier_call(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct omap_devh_platform_data *pdata = + devh_get_plat_data_by_name("Tesla"); + + switch ((int)val) { + case TILER_DEVICE_CLOSE: + return devh44xx_notifier_call(nb, val, v, pdata); + default: + return 0; + } +} + +static struct notifier_block devh_notify_nb_tiler_tesla = { + .notifier_call = devh44xx_tesla_tiler_notifier_call, +}; +static struct notifier_block devh_notify_nb_tiler_ducati0 = { + .notifier_call = devh44xx_sysm3_tiler_notifier_call, +}; +static struct notifier_block devh_notify_nb_tiler_ducati1 = { + .notifier_call = devh44xx_appm3_tiler_notifier_call, +}; +#endif + +static inline int devh44xx_sysm3_register(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* register will kernel modules for event notifications. */ + ipc_register_notifier(&devh_notify_nb_ipc_ducati0); + pinfo->rproc = omap_rproc_get("ducati-proc0"); + if (pinfo->rproc != ERR_PTR(-ENODEV)) + omap_rproc_register_notifier(pinfo->rproc, + &devh_notify_nb_rproc_ducati0); + else + pinfo->rproc = NULL; +#if defined(CONFIG_TILER_OMAP) + tiler_reg_notifier(&devh_notify_nb_tiler_ducati0); +#endif + + return retval; +} + +static inline int devh44xx_appm3_register(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* register will kernel modules for event notifications. */ + ipc_register_notifier(&devh_notify_nb_ipc_ducati1); + pinfo->rproc = omap_rproc_get("ducati-proc1"); + if (pinfo->rproc != ERR_PTR(-ENODEV)) + omap_rproc_register_notifier(pinfo->rproc, + &devh_notify_nb_rproc_ducati1); + else + pinfo->rproc = NULL; +#if defined(CONFIG_TILER_OMAP) + tiler_reg_notifier(&devh_notify_nb_tiler_ducati1); +#endif + + return retval; +} + +static inline int devh44xx_tesla_register(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* register will kernel modules for event notifications. */ + ipc_register_notifier(&devh_notify_nb_ipc_tesla); + pinfo->rproc = omap_rproc_get("tesla"); + if (pinfo->rproc != ERR_PTR(-ENODEV)) + omap_rproc_register_notifier(pinfo->rproc, + &devh_notify_nb_rproc_tesla); + else + pinfo->rproc = NULL; +#if defined(CONFIG_TILER_OMAP) + tiler_reg_notifier(&devh_notify_nb_tiler_tesla); +#endif + + return retval; +} + +static inline int devh44xx_sysm3_unregister(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* un-register will kernel modules for event notifications. */ + ipc_unregister_notifier(&devh_notify_nb_ipc_ducati0); + if (pinfo->rproc) { + omap_rproc_unregister_notifier(pinfo->rproc, + &devh_notify_nb_rproc_ducati0); + omap_rproc_put(pinfo->rproc); + } + if (pinfo->iommu) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati0); + iommu_put(pinfo->iommu); + } +#if defined(CONFIG_TILER_OMAP) + tiler_unreg_notifier(&devh_notify_nb_tiler_ducati0); +#endif + + return retval; +} + +static inline int devh44xx_appm3_unregister(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* un-register will kernel modules for event notifications. */ + ipc_unregister_notifier(&devh_notify_nb_ipc_ducati1); + if (pinfo->rproc) { + omap_rproc_unregister_notifier(pinfo->rproc, + &devh_notify_nb_rproc_ducati1); + omap_rproc_put(pinfo->rproc); + } + if (pinfo->iommu) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_ducati1); + iommu_put(pinfo->iommu); + } +#if defined(CONFIG_TILER_OMAP) + tiler_unreg_notifier(&devh_notify_nb_tiler_ducati1); +#endif + + return retval; +} + +static inline int devh44xx_tesla_unregister(struct omap_devh *devh) +{ + int retval = 0; + struct omap_devh_platform_data *pdata = NULL; + struct omap_devh_runtime_info *pinfo = NULL; + + if (!devh->dev) + return -EINVAL; + + pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; + + if (!pdata) + return -EINVAL; + + pinfo = (struct omap_devh_runtime_info *)pdata->private_data; + + /* un-register will kernel modules for event notifications. */ + ipc_unregister_notifier(&devh_notify_nb_ipc_tesla); + if (pinfo->rproc) { + omap_rproc_unregister_notifier(pinfo->rproc, + &devh_notify_nb_rproc_tesla); + omap_rproc_put(pinfo->rproc); + } + if (pinfo->iommu) { + iommu_unregister_notifier(pinfo->iommu, + &devh_notify_nb_iommu_tesla); + iommu_put(pinfo->iommu); + } +#if defined(CONFIG_TILER_OMAP) + tiler_unreg_notifier(&devh_notify_nb_tiler_tesla); +#endif + return retval; +} + +static struct omap_devh_runtime_info omap4_sysm3_runtime_info = { + .brd_state = DEVH_BRDST_STOPPED, + .iommu = NULL, + .rproc = NULL, +}; + +static struct omap_devh_runtime_info omap4_appm3_runtime_info = { + .brd_state = DEVH_BRDST_STOPPED, + .iommu = NULL, + .rproc = NULL, +}; + +static struct omap_devh_runtime_info omap4_tesla_runtime_info = { + .brd_state = DEVH_BRDST_STOPPED, + .iommu = NULL, + .rproc = NULL, +}; + +static struct omap_devh_ops omap4_sysm3_ops = { + .register_notifiers = devh44xx_sysm3_register, + .unregister_notifiers = devh44xx_sysm3_unregister, +}; + +static struct omap_devh_ops omap4_appm3_ops = { + .register_notifiers = devh44xx_appm3_register, + .unregister_notifiers = devh44xx_appm3_unregister, +}; + +static struct omap_devh_ops omap4_tesla_ops = { + .register_notifiers = devh44xx_tesla_register, + .unregister_notifiers = devh44xx_tesla_unregister, +}; + +static struct omap_devh_platform_data omap4_devh_data[] = { + { + .name = "Tesla", + .ops = &omap4_tesla_ops, + .proc_id = 0, + .private_data = &omap4_tesla_runtime_info, + }, + { + .name = "SysM3", + .ops = &omap4_sysm3_ops, + .proc_id = 2, + .private_data = &omap4_sysm3_runtime_info, + }, + { + .name = "AppM3", + .ops = &omap4_appm3_ops, + .proc_id = 1, + .private_data = &omap4_appm3_runtime_info, + }, +}; + +int devh_get_plat_data_size(void) +{ + return ARRAY_SIZE(omap4_devh_data); +} +EXPORT_SYMBOL(devh_get_plat_data_size); + + +#define NR_DEVH_DEVICES ARRAY_SIZE(omap4_devh_data) + +static struct platform_device *omap4_devh_pdev[NR_DEVH_DEVICES]; + +struct omap_devh_platform_data *devh_get_plat_data(void) +{ + return omap4_devh_data; +} + +static int __init omap4_devh_init(void) +{ + int i, err; + + mutex_init(&local_gate); + for (i = 0; i < NR_DEVH_DEVICES; i++) { + struct platform_device *pdev; + + pdev = platform_device_alloc("omap-devicehandler", i); + if (!pdev) { + err = -ENOMEM; + goto err_out; + } + + err = platform_device_add_data(pdev, &omap4_devh_data[i], + sizeof(omap4_devh_data[0])); + sema_init(&(omap4_devh_data[i].sem_handle), 0); + err = platform_device_add(pdev); + if (err) + goto err_out; + omap4_devh_pdev[i] = pdev; + } + return 0; + +err_out: + while (i--) + platform_device_put(omap4_devh_pdev[i]); + return err; +} +module_init(omap4_devh_init); + +static void __exit omap4_devh_exit(void) +{ + int i; + + for (i = 0; i < NR_DEVH_DEVICES; i++) + platform_device_unregister(omap4_devh_pdev[i]); +} +module_exit(omap4_devh_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("OMAP4 Device Handler module"); +MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>"); diff --git a/drivers/dsp/syslink/devh/Kbuild b/drivers/dsp/syslink/devh/Kbuild new file mode 100644 index 000000000000..65184bd3b59e --- /dev/null +++ b/drivers/dsp/syslink/devh/Kbuild @@ -0,0 +1,7 @@ + +obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh.o + +ccflags-y += -Wno-strict-prototypes + +#Header files +ccflags-y += -Iarch/arm/plat-omap/include/syslink diff --git a/drivers/dsp/syslink/devh/devh.c b/drivers/dsp/syslink/devh/devh.c new file mode 100644 index 000000000000..a9bed7c49938 --- /dev/null +++ b/drivers/dsp/syslink/devh/devh.c @@ -0,0 +1,261 @@ +/* + * OMAP Device Handler driver + * + * Copyright (C) 2010 Texas Instruments Inc. + * + * Written by Angela Stegmaier <angelabaker@ti.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 "devh.h" + +#define OMAP_DEVH_NAME "omap-devh" +#define DRV_NAME "omap-devicehandler" + +static struct class *omap_devh_class; +static dev_t omap_devh_dev; +static atomic_t num_of_devhs; +static struct platform_driver omap_devh_driver; + +static int omap_devh_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct omap_devh *devh; + + devh = container_of(inode->i_cdev, struct omap_devh, cdev); + if (!devh->dev) + return -EINVAL; + + filp->private_data = devh; + + return ret; +} + +static int omap_devh_release(struct inode *inode, struct file *filp) +{ + struct omap_devh *devh = filp->private_data; + if (!devh || !devh->dev) + return -EINVAL; + + return 0; +} + +static int omap_devh_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + struct omap_devh *devh = filp->private_data; + + if (!devh) + return -EINVAL; + + if (_IOC_TYPE(cmd) != DEVH_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > DEVH_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) { + + /* + * this will be updated to support user registering for event + * notifications. + */ + case DEVH_IOCWAITONEVENTS: + /*rc = omap_devh_wait_on_events(devh);*/ + break; + default: + return -ENOTTY; + } + + return rc; +} + +static const struct file_operations omap_devh_fops = { + .open = omap_devh_open, + .release = omap_devh_release, + .ioctl = omap_devh_ioctl, + .owner = THIS_MODULE, +}; + +static int omap_devh_probe(struct platform_device *pdev) +{ + int ret = 0, major, minor; + struct device *tmpdev; + struct device *dev = &pdev->dev; + struct omap_devh_platform_data *pdata = dev->platform_data; + struct omap_devh *devh; + + if (!pdata || !pdata->name || !pdata->ops) + return -EINVAL; + + dev_info(dev, "%s: adding devh %s\n", __func__, pdata->name); + + devh = kzalloc(sizeof(struct omap_devh), GFP_KERNEL); + if (!devh) { + dev_err(dev, "%s: kzalloc failed\n", __func__); + ret = -ENOMEM; + goto out; + } + + platform_set_drvdata(pdev, devh); + major = MAJOR(omap_devh_dev); + minor = atomic_read(&num_of_devhs); + atomic_inc(&num_of_devhs); + + devh->dev = dev; + devh->minor = minor; + devh->name = pdata->name; + + cdev_init(&devh->cdev, &omap_devh_fops); + devh->cdev.owner = THIS_MODULE; + ret = cdev_add(&devh->cdev, MKDEV(major, minor), 1); + if (ret) { + dev_err(dev, "%s: cdev_add failed: %d\n", __func__, ret); + goto free_devh; + } + + tmpdev = device_create(omap_devh_class, NULL, + MKDEV(major, minor), + NULL, + OMAP_DEVH_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_DEVH_NAME, + pdata->name, + MAJOR(omap_devh_dev), + minor); + + if (pdata->ops->register_notifiers) + pdata->ops->register_notifiers(devh); + + return 0; + +clean_cdev: + cdev_del(&devh->cdev); +free_devh: + kfree(devh); +out: + return ret; +} + +static int omap_devh_remove(struct platform_device *pdev) +{ + int major = MAJOR(omap_devh_dev); + struct device *dev = &pdev->dev; + struct omap_devh_platform_data *pdata = dev->platform_data; + struct omap_devh *devh = platform_get_drvdata(pdev); + + if (!pdata || !devh) + return -EINVAL; + + if (pdata->ops->unregister_notifiers) + pdata->ops->unregister_notifiers(devh); + + dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n", + OMAP_DEVH_NAME, + pdata->name, + major, + devh->minor); + + device_destroy(omap_devh_class, MKDEV(major, devh->minor)); + cdev_del(&devh->cdev); + kfree(devh); + + return 0; +} + +static struct platform_driver omap_devh_driver = { + .probe = omap_devh_probe, + .remove = omap_devh_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init omap_devh_init(void) +{ + int num = devh_get_plat_data_size(); + int ret; + + ret = alloc_chrdev_region(&omap_devh_dev, 0, num, OMAP_DEVH_NAME); + if (ret) { + pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret); + goto out; + } + + omap_devh_class = class_create(THIS_MODULE, OMAP_DEVH_NAME); + if (IS_ERR(omap_devh_class)) { + ret = PTR_ERR(omap_devh_class); + pr_err("%s: class_create failed: %d\n", __func__, ret); + goto unreg_region; + } + + atomic_set(&num_of_devhs, 0); + + ret = platform_driver_register(&omap_devh_driver); + if (ret) { + pr_err("%s: platform_driver_register failed: %d\n", + __func__, ret); + goto out; + } + return 0; +unreg_region: + unregister_chrdev_region(omap_devh_dev, num); +out: + return ret; +} +module_init(omap_devh_init); + +static void __exit omap_devh_exit(void) +{ + int num = devh_get_plat_data_size(); + pr_info("%s\n", __func__); + platform_driver_unregister(&omap_devh_driver); + class_destroy(omap_devh_class); + unregister_chrdev_region(omap_devh_dev, num); +} +module_exit(omap_devh_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("OMAP Device Handler driver"); +MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>"); diff --git a/drivers/dsp/syslink/devh/devh.h b/drivers/dsp/syslink/devh/devh.h new file mode 100644 index 000000000000..81dbb1b67df4 --- /dev/null +++ b/drivers/dsp/syslink/devh/devh.h @@ -0,0 +1,64 @@ +/* + * OMAP Device Handler driver + * + * Copyright (C) 2010 Texas Instruments Inc. + * + * Written by Angela Stegmaier <angelabaker@ti.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 DEVH_H +#define DEVH_H + +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/semaphore.h> + +#define DEVH_IOC_MAGIC 'P' + +#define DEVH_IOCWAITONEVENTS _IOR(DEVH_IOC_MAGIC, 0, int) + +#define DEVH_IOC_MAXNR (1) + +struct omap_devh; + +struct omap_devh_ops { + int (*register_notifiers)(struct omap_devh *devh); + int (*unregister_notifiers)(struct omap_devh *devh); +}; + +struct omap_devh_platform_data { + struct omap_devh_ops *ops; + char *name; + int proc_id; + struct semaphore sem_handle; + void *private_data; +}; + +struct omap_devh { + struct device *dev; + struct cdev cdev; + atomic_t count; + int state; + int minor; + char *name; +}; + +extern struct omap_devh_platform_data *devh_get_plat_data(void); +extern int devh_get_plat_data_size(void); + +#endif /* DEVH_H */ |