aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/samsung_duallcd/extension/mdnie.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/samsung_duallcd/extension/mdnie.c')
-rw-r--r--drivers/video/samsung_duallcd/extension/mdnie.c729
1 files changed, 729 insertions, 0 deletions
diff --git a/drivers/video/samsung_duallcd/extension/mdnie.c b/drivers/video/samsung_duallcd/extension/mdnie.c
new file mode 100644
index 0000000..e2ad4cc
--- /dev/null
+++ b/drivers/video/samsung_duallcd/extension/mdnie.c
@@ -0,0 +1,729 @@
+/* /linux/driver/video/samsung/mdnie.c
+ *
+ * Samsung SoC mDNIe driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics.
+ * Author: InKi Dae <inki.dae@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+
+#include <plat/fimd_lite_ext.h>
+#include <mach/map.h>
+
+#include "regs-mdnie.h"
+#include "mdnie.h"
+#include "s5p_fimd_ext.h"
+#include "cmc623.h"
+
+/* FIXME:!! need to change chip id dynamically */
+#define MDNIE_CHIP_ID "cmc623p"
+
+static const char *mode_name[MODE_MAX] = {
+ "dynamic",
+ "standard",
+ "natural",
+ "movie"
+};
+
+static const char *scenario_name[SCENARIO_MAX] = {
+ "ui",
+ "gallery",
+ "video",
+ "vtcall",
+ "camera",
+ "browser",
+ "negative",
+ "bypass"
+};
+
+static const char *tone_name[TONE_MAX] = {
+ "",
+ "warm",
+ "cold",
+};
+
+static const char *tone_browser_name[TONE_BR_MAX] = {
+ "tone1",
+ "tone2",
+ "tone3"
+};
+
+static const char *outdoor_name[OUTDOOR_MAX] = {
+ "",
+ "outdoor"
+};
+
+#if defined(DEBUG)
+#define mdnie_info(fmt, args...) \
+ do { \
+ printk(KERN_NOTICE"%s:"fmt"\n", __func__, ##args); \
+ } while (0);
+#else
+#define mdnie_info(fmt, args...)
+#endif
+
+static struct mdnie_platform_data
+ *to_mdnie_platform_data(struct s5p_fimd_ext_device *fx_dev)
+{
+ return fx_dev->dev.platform_data ?
+ (struct mdnie_platform_data *)fx_dev->dev.platform_data : NULL;
+}
+
+static void mdnie_write_tune(struct s5p_mdnie *mdnie,
+ const unsigned short *tune,
+ unsigned int size)
+{
+ unsigned int i = 0;
+
+ mdnie_info("size[%d]", size);
+ while (i < size) {
+ writel(tune[i + 1], mdnie->regs + tune[i] * 4);
+ i += 2;
+ }
+}
+
+static int mdnie_request_fw(struct s5p_mdnie *mdnie, const char *name)
+{
+ const struct firmware *fw;
+ char fw_path[MDNIE_MAX_STR+1];
+ int ret;
+
+ snprintf(fw_path, MDNIE_MAX_STR, MDNIE_FW_PATH, MDNIE_CHIP_ID, name);
+ mdnie_info("fw_path[%s]", fw_path);
+ mutex_lock(&mdnie->lock);
+
+ ret = request_firmware(&fw, fw_path, mdnie->dev);
+ if (ret) {
+ dev_err(mdnie->dev, "failed to request firmware.\n");
+ mutex_unlock(&mdnie->lock);
+ return ret;
+ }
+
+ mdnie_write_tune(mdnie, (const unsigned short *)fw->data,
+ fw->size / sizeof(const unsigned short));
+ release_firmware(fw);
+
+ mutex_unlock(&mdnie->lock);
+
+ return 0;
+}
+
+static int mdnie_request_tables(struct s5p_mdnie *mdnie, const char *name)
+{
+ struct mdnie_tables *tables;
+ int i;
+
+ mdnie_info("name[%s]", name);
+ tables = (struct mdnie_tables *)&mdnie_main_tables;
+ if (!tables) {
+ dev_err(mdnie->dev, "mode mdnie tables is NULL.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mdnie_main_tables); i++) {
+ if (strcmp(name , tables[i].name) == 0) {
+ mdnie_info("tune_id[%d]name[%s]", i, tables[i].name);
+ mdnie_write_tune(mdnie, tables[i].value,
+ tables[i].size);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int mdnie_get_name(struct s5p_mdnie *mdnie, char *name,
+ enum mdnie_set set)
+{
+ enum mdnie_mode mode = mdnie->mode;
+ enum mdnie_scenario scenario = mdnie->scenario;
+ int tone = mdnie->tone;
+ enum mdnie_outdoor outdoor = mdnie->outdoor;
+
+ mdnie_info("set[%d]:mode[%d]scenario[%d]tone[%d]outdoor[%d]",
+ set, mode, scenario, tone, outdoor);
+ switch (scenario) {
+ case SCENARIO_CAMERA:
+ strcat(name, scenario_name[scenario]);
+ if (outdoor == OUTDOOR_ON) {
+ strcat(name, "_");
+ strcat(name , outdoor_name[outdoor]);
+ }
+ break;
+ case SCENARIO_BROWSER:
+ strcat(name, scenario_name[scenario]);
+ strcat(name, "_");
+ strcat(name, tone_browser_name[tone]);
+ break;
+ default:
+ if (set == SET_MAIN ||
+ (tone == TONE_NORMAL && outdoor == OUTDOOR_OFF)) {
+ if (scenario < SCENARIO_MODE_MAX) {
+ if (mode < MODE_MAX)
+ strcat(name, mode_name[mode]);
+
+ strcat(name, "_");
+
+ if (scenario < SCENARIO_MODE_MAX)
+ strcat(name,
+ scenario_name[scenario]);
+ } else
+ strcat(name, scenario_name[scenario]);
+ } else {
+ if (tone < TONE_MAX)
+ strcat(name, tone_name[tone]);
+
+ if (tone != TONE_NORMAL && outdoor == OUTDOOR_ON)
+ strcat(name, "_");
+
+ if (outdoor < OUTDOOR_MAX)
+ strcat(name , outdoor_name[outdoor]);
+ }
+ break;
+ }
+
+ return strlen(name);
+}
+
+static int mdnie_set_commit(struct s5p_mdnie *mdnie,
+ enum mdnie_set set)
+{
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ char name[MDNIE_MAX_STR+1];
+ int ret = 0, len = 0;
+
+ memset(name, 0, MDNIE_MAX_STR+1);
+ len = mdnie_get_name(mdnie, name, set);
+ if (len == 0) {
+ dev_err(mdnie->dev, "failed to find tune.\n");
+ return ret;
+ }
+
+ if (mops && mops->tune) {
+ ret = mops->tune(mdnie, name);
+ if (ret) {
+ dev_err(mdnie->dev, "failed to set tune.\n");
+ return ret;
+ }
+ } else {
+ dev_err(mdnie->dev, "invalid mdnie mops.\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int mdnie_check_tone(struct s5p_mdnie *mdnie, int tone)
+{
+ unsigned long max_tone;
+
+ if (mdnie->scenario == SCENARIO_BROWSER)
+ max_tone = TONE_BR_MAX;
+ else
+ max_tone = TONE_MAX;
+
+ if (tone >= max_tone) {
+ dev_err(mdnie->dev, "invalid mdnie tone.\n");
+ return -EINVAL;
+ }
+
+ if (mdnie->scenario != SCENARIO_VIDEO
+ && mdnie->scenario != SCENARIO_BROWSER) {
+ /* Set to default */
+ mdnie->tone = 0;
+ dev_err(mdnie->dev, "invalid mdnie scenario.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+struct mdnie_manager_ops mdnie_set_mops = {
+ .tune = mdnie_request_tables,
+ .commit = mdnie_set_commit,
+ .check_tone = mdnie_check_tone,
+};
+
+static void mdnie_set_size(struct s5p_mdnie *mdnie,
+ unsigned int width, unsigned int height)
+{
+ unsigned int size;
+
+ writel(0x0, mdnie->regs + MDNIE_R0);
+
+ /* Input Data Unmask */
+ writel(0x077, mdnie->regs + MDNIE_R1);
+
+ /* LCD width */
+ size = readl(mdnie->regs + MDNIE_R3);
+ size &= ~MDNIE_R34_WIDTH_MASK;
+ size |= width;
+ writel(size, mdnie->regs + MDNIE_R3);
+
+ /* LCD height */
+ size = readl(mdnie->regs + MDNIE_R4);
+ size &= ~MDNIE_R35_HEIGHT_MASK;
+ size |= height;
+ writel(size, mdnie->regs + MDNIE_R4);
+
+ /* unmask all */
+ writel(0, mdnie->regs + MDNIE_R28);
+}
+
+static void mdnie_init_hardware(struct s5p_mdnie *mdnie)
+{
+ struct mdnie_platform_data *pdata = NULL;
+
+ pdata = mdnie->pdata;
+
+ /* set display size. */
+ mdnie_set_size(mdnie, pdata->width, pdata->height);
+}
+
+static int mdnie_setup(struct s5p_fimd_ext_device *fx_dev, unsigned int enable)
+{
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ int ret = 0;
+
+ mdnie_info("enable[%d]", enable);
+ if (enable) {
+ int i;
+ mdnie_init_hardware(mdnie);
+ if (mops && mops->commit) {
+ for (i = 0; i < SET_MAX; i++) {
+ ret = mops->commit(mdnie, i);
+ if (ret) {
+ dev_err(mdnie->dev, "invalid mdnie set.\n");
+ goto error;
+ }
+ }
+ } else {
+ dev_err(mdnie->dev, "invalid mdnie mops.\n");
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ return ret;
+}
+
+static ssize_t store_mdnie_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ unsigned long prev_mode;
+ unsigned long mode;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &mode);
+ if (ret) {
+ dev_err(&fx_dev->dev, "invalid mode value.\n");
+ return -EINVAL;
+ }
+
+ if (mode >= MODE_MAX) {
+ dev_err(&fx_dev->dev, "invalid mdnie mode.\n");
+ return -EINVAL;
+ }
+
+ if (mdnie->scenario >= SCENARIO_MODE_MAX) {
+ dev_err(&fx_dev->dev, "invalid mdnie scenario.\n");
+ mdnie->scenario = SCENARIO_UI;
+ }
+
+ prev_mode = mdnie->mode;
+ mdnie->mode = mode;
+ mdnie_info("mode[%d]", mdnie->mode);
+ if (mops && mops->commit) {
+ ret = mops->commit(mdnie, SET_MAIN);
+ if (ret) {
+ dev_err(&fx_dev->dev, "failed to set mode.\n");
+ goto error_restore;
+ }
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_restore;
+ }
+
+ return count;
+
+error_restore:
+ mdnie->mode = prev_mode;
+ return ret;
+}
+
+static ssize_t show_mdnie_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+
+ mdnie_info("mode[%d]", mdnie->mode);
+ return snprintf(buf, PAGE_SIZE, "%d\n", mdnie->mode);
+}
+
+static ssize_t store_mdnie_scenario(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ unsigned long prev_scenario;
+ unsigned long scenario;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &scenario);
+ if (ret) {
+ dev_err(&fx_dev->dev, "invalid scenario value.\n");
+ return -EINVAL;
+ }
+
+ if (scenario >= SCENARIO_MAX) {
+ dev_err(&fx_dev->dev, "invalid mdnie scenario.\n");
+ return -EINVAL;
+ }
+
+ prev_scenario = mdnie->scenario;
+ mdnie->scenario = scenario;
+ mdnie_info("scenario[%d]", mdnie->scenario);
+ if (mops && mops->commit) {
+ ret = mops->commit(mdnie, SET_MAIN);
+ if (ret) {
+ dev_err(&fx_dev->dev, "failed to set scenario.\n");
+ goto error_restore;
+ }
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_restore;
+ }
+
+ return count;
+
+error_restore:
+ mdnie->scenario = prev_scenario;
+ return ret;
+}
+
+static ssize_t show_mdnie_scenario(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+
+ mdnie_info("scenario[%d]", mdnie->scenario);
+ return snprintf(buf, PAGE_SIZE, "%d\n", mdnie->scenario);
+}
+
+static ssize_t store_mdnie_tone(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ unsigned long prev_tone;
+ unsigned long tone;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &tone);
+ if (ret) {
+ dev_err(&fx_dev->dev, "invalid tone value.\n");
+ return -EINVAL;
+ }
+
+ if (mops && mops->check_tone) {
+ ret = mops->check_tone(mdnie, tone);
+ if (ret) {
+ dev_err(&fx_dev->dev, "failed to set tone.\n");
+ return ret;
+ }
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_mops;
+ }
+
+ prev_tone = mdnie->tone;
+ mdnie->tone = tone;
+ mdnie_info("tone[%d]", mdnie->tone);
+ if (mops && mops->commit) {
+ ret = mops->commit(mdnie, SET_OPTIONAL);
+ if (ret) {
+ dev_err(&fx_dev->dev, "failed to set tone.\n");
+ goto error_restore;
+ }
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_restore;
+ }
+
+ return count;
+
+error_restore:
+ mdnie->tone = prev_tone;
+error_mops:
+ return ret;
+}
+
+static ssize_t show_mdnie_tone(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+
+ mdnie_info("tone[%d]", mdnie->tone);
+ return snprintf(buf, PAGE_SIZE, "%d\n", mdnie->tone);
+}
+
+static ssize_t store_mdnie_outdoor(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ unsigned long prev_outdoor;
+ unsigned long outdoor;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &outdoor);
+ if (ret) {
+ dev_err(&fx_dev->dev, "invalid outdoor value.\n");
+ return -EINVAL;
+ }
+
+ if (outdoor >= OUTDOOR_MAX) {
+ dev_err(&fx_dev->dev, "invalid mdnie outdoor.\n");
+ return -EINVAL;
+ }
+
+ if (mdnie->scenario != SCENARIO_VIDEO
+ && mdnie->scenario != SCENARIO_CAMERA) {
+ /* Set to default */
+ mdnie->outdoor = OUTDOOR_OFF;
+ dev_err(&fx_dev->dev, "invalid mdnie scenario.\n");
+ return -EIO;
+ }
+
+ prev_outdoor = mdnie->outdoor;
+ mdnie->outdoor = outdoor;
+ mdnie_info("outdoor[%d]", mdnie->outdoor);
+ if (mops && mops->commit) {
+ ret = mops->commit(mdnie, SET_OPTIONAL);
+ if (ret) {
+ dev_err(&fx_dev->dev, "failed to set outdoor.\n");
+ goto error_restore;
+ }
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_restore;
+ }
+
+ return count;
+
+error_restore:
+ mdnie->outdoor = prev_outdoor;
+ return ret;
+}
+
+static ssize_t show_mdnie_outdoor(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+
+ mdnie_info("outdoor[%d]", mdnie->outdoor);
+ return snprintf(buf, PAGE_SIZE, "%d\n", mdnie->outdoor);
+}
+
+static ssize_t store_mdnie_tune(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+ struct mdnie_manager_ops *mops = mdnie->mops;
+ unsigned long prev_tune;
+ unsigned long tune;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &tune);
+ if (ret) {
+ dev_err(&fx_dev->dev, "invalid tune value.\n");
+ return -EINVAL;
+ }
+
+ if (tune >= TUNE_MAX) {
+ dev_err(&fx_dev->dev, "invalid mdnie tune.\n");
+ return -EINVAL;
+ }
+
+ prev_tune = mdnie->tune;
+ mdnie->tune = tune;
+ mdnie_info("tune[%d]", mdnie->tune);
+ if (mops) {
+ if (mdnie->tune == TUNE_FW)
+ mops->tune = mdnie_request_fw;
+ else
+ mops->tune = mdnie_request_tables;
+ } else {
+ dev_err(&fx_dev->dev, "invalid mdnie mops.\n");
+ ret = -EINVAL;
+ goto error_restore;
+ }
+
+ return count;
+
+error_restore:
+ mdnie->tune = prev_tune;
+ return ret;
+}
+
+static ssize_t show_mdnie_tune(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct s5p_fimd_ext_device *fx_dev = to_fimd_ext_device(dev);
+ struct s5p_mdnie *mdnie = fimd_ext_get_drvdata(fx_dev);
+
+ mdnie_info("tune[%d]", mdnie->tune);
+ return snprintf(buf, PAGE_SIZE, "%d\n", mdnie->tune);
+}
+
+/* sys/devices/platform/mdnie */
+static struct device_attribute mdnie_device_attrs[] = {
+ __ATTR(mode, S_IRUGO|S_IWUSR, show_mdnie_mode,
+ store_mdnie_mode),
+ __ATTR(scenario, S_IRUGO|S_IWUSR, show_mdnie_scenario,
+ store_mdnie_scenario),
+ __ATTR(tone, S_IRUGO|S_IWUSR, show_mdnie_tone,
+ store_mdnie_tone),
+ __ATTR(outdoor, S_IRUGO|S_IWUSR, show_mdnie_outdoor,
+ store_mdnie_outdoor),
+ __ATTR(tune, S_IRUGO|S_IWUSR, show_mdnie_tune,
+ store_mdnie_tune),
+};
+
+static int mdnie_probe(struct s5p_fimd_ext_device *fx_dev)
+{
+ struct resource *res;
+ struct s5p_mdnie *mdnie;
+ int ret = -EINVAL;
+ int i;
+
+ mdnie = kzalloc(sizeof(struct s5p_mdnie), GFP_KERNEL);
+ if (!mdnie) {
+ dev_err(&fx_dev->dev, "failed to alloc mdnie object.\n");
+ return -EFAULT;
+ }
+
+ mdnie->dev = &fx_dev->dev;
+
+ mdnie->pdata = to_mdnie_platform_data(fx_dev);
+ if (mdnie->pdata == NULL) {
+ dev_err(&fx_dev->dev, "platform_data is NULL.\n");
+ return -EFAULT;
+ }
+
+ res = s5p_fimd_ext_get_resource(fx_dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&fx_dev->dev, "failed to get io memory region.\n");
+ return -EINVAL;
+ }
+
+ mdnie->regs = ioremap(res->start, resource_size(res));
+ if (!mdnie->regs) {
+ dev_err(&fx_dev->dev, "failed to remap io region.\n'");
+ return -EFAULT;
+ }
+
+ mdnie->mode = MODE_STANDARD;
+ mdnie->scenario = SCENARIO_UI;
+ mdnie->tone = TONE_NORMAL;
+ mdnie->outdoor = OUTDOOR_OFF;
+ mdnie->tune = TUNE_TBL;
+ mdnie->mops = &mdnie_set_mops;
+
+ mutex_init(&mdnie->lock);
+
+ fimd_ext_set_drvdata(fx_dev, mdnie);
+
+ for (i = 0; i < ARRAY_SIZE(mdnie_device_attrs); i++) {
+ ret = device_create_file(&fx_dev->dev,
+ &mdnie_device_attrs[i]);
+ if (ret)
+ break;
+ }
+
+ if (ret < 0)
+ dev_err(&fx_dev->dev, "failed to add sysfs entries\n");
+
+ dev_info(&fx_dev->dev, "mDNIe driver has been probed.\n");
+
+ return 0;
+}
+
+static struct s5p_fimd_ext_driver fimd_ext_driver = {
+ .driver = {
+ .name = "mdnie",
+ .owner = THIS_MODULE,
+ },
+ .probe = mdnie_probe,
+ .setup = mdnie_setup,
+};
+
+static int __init mdnie_init(void)
+{
+ return s5p_fimd_ext_driver_register(&fimd_ext_driver);
+}
+
+static void __exit mdnie_exit(void)
+{
+}
+
+arch_initcall(mdnie_init);
+module_exit(mdnie_exit);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
+MODULE_DESCRIPTION("mDNIe Driver");
+MODULE_LICENSE("GPL");
+