diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/video/wmt/wmt-vpp.c | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/video/wmt/wmt-vpp.c')
-rwxr-xr-x | drivers/video/wmt/wmt-vpp.c | 1538 |
1 files changed, 1538 insertions, 0 deletions
diff --git a/drivers/video/wmt/wmt-vpp.c b/drivers/video/wmt/wmt-vpp.c new file mode 100755 index 00000000..4415477b --- /dev/null +++ b/drivers/video/wmt/wmt-vpp.c @@ -0,0 +1,1538 @@ +/*++ + * linux/drivers/video/wmt/wmt-vpp.c + * WonderMedia video post processor (VPP) driver + * + * Copyright c 2014 WonderMedia Technologies, Inc. + * + * 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, see <http://www.gnu.org/licenses/>. + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#define DEV_VPP_C + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <asm/uaccess.h> +#include <linux/kdev_t.h> +#include <linux/cdev.h> +#include <linux/dma-mapping.h> +#include <linux/major.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <mach/irqs.h> +#include <mach/hardware.h> +#include <linux/sched.h> +#include <linux/wmt-mb.h> +#include <linux/wmt-se.h> +#include <linux/poll.h> + +#undef DEBUG +/* #define DEBUG */ +/* #define DEBUG_DETAIL */ +#include "vpp.h" + +/*----------------------- PRIVATE MACRO --------------------------------------*/ + +/*----------------------- PRIVATE CONSTANTS ----------------------------------*/ +/* #define WMT_VPP_XXXX 1 *//*Example*/ +#define DEVICE_NAME "wmt-vpp" + +/*----------------------- PRIVATE TYPE --------------------------------------*/ +/* typedef xxxx wmt_vpp_xxx_t; *//*Example*/ + +/*----------------------- INTERNAL PRIVATE VARIABLES - -----------------------*/ +/* int wmt_vpp_xxx; *//*Example*/ +static DEFINE_SEMAPHORE(wmt_vpp_sem); +static struct class *wmt_vpp_class; +static int wmt_vpp_major; + +/*--------------------- INTERNAL PRIVATE FUNCTIONS ---------------------------*/ +/* void wmt_vpp_xxx(void); *//*Example*/ + +/*----------------------- Function Body --------------------------------------*/ +#ifdef CONFIG_PROC_FS +#define CONFIG_VPP_PROC +#ifdef CONFIG_VPP_PROC +unsigned int vpp_proc_value; +char vpp_proc_str[16]; +static ctl_table vpp_table[]; +static int vpp_do_proc(ctl_table *ctl, int write, + void *buffer, size_t *len, loff_t *ppos) +{ + int ret; + int ctl_name; + + ctl_name = (((int)ctl - (int)vpp_table) / sizeof(ctl_table)) + 1; + if (!write) { + switch (ctl_name) { + case 1: + vpp_proc_value = g_vpp.dbg_msg_level; + break; + case 2: + vpp_proc_value = g_vpp.dbg_wait; + break; + case 3: + vpp_proc_value = g_vpp.dbg_flag; + break; + case 8: + case 9: + vpp_proc_value = vpp_get_base_clock((ctl_name == 8) ? + VPP_MOD_GOVRH : VPP_MOD_GOVRH2); + break; + case 10: + vpp_proc_value = p_scl->scale_mode; + break; + case 11: + vpp_proc_value = p_scl->filter_mode; + break; +#ifdef CONFIG_WMT_HDMI + case 12: + vpp_proc_value = g_vpp.hdmi_cp_enable; + break; + case 13: + vpp_proc_value = g_vpp.hdmi_3d_type; + break; + case 14: + vpp_proc_value = g_vpp.hdmi_certify_flag; + break; +#endif + case 15: + vpp_proc_value = govrh_get_brightness(p_govrh); + break; + case 16: + vpp_proc_value = govrh_get_contrast(p_govrh); + break; + case 17: + vpp_proc_value = govrh_get_saturation(p_govrh); + break; + case 18: + vpp_proc_value = g_vpp.fb_manual; + break; + default: + break; + } + } + + ret = proc_dointvec(ctl, write, buffer, len, ppos); + if (write) { + switch (ctl_name) { + case 1: + DPRINT("---------- VPP debug level ----------\n"); + DPRINT("0-disable,255-show all\n"); + DPRINT("1-scale,2-disp fb,3-interrupt,4-timer\n"); + DPRINT("5-ioctl,6-diag,7-stream\n"); + DPRINT("-------------------------------------\n"); + g_vpp.dbg_msg_level = vpp_proc_value; + break; + case 2: + g_vpp.dbg_wait = vpp_proc_value; + vpp_dbg_wake_up(); + break; + case 3: + g_vpp.dbg_flag = vpp_proc_value; + break; +#ifdef CONFIG_WMT_EDID + case 6: + { + struct vout_t *vo; + + vo = vout_get_entry_adapter(vpp_proc_value); + if ((vo->inf) && (vo->inf->get_edid)) { + vo->status &= ~VPP_VOUT_STS_EDID; + if (vout_get_edid(vo->num)) { + int i; + + vo->edid_info.option = 0; + edid_dump(vo->edid); + for (i = 1; i <= vo->edid[126]; i++) + edid_dump(vo->edid + 128 * i); + if (!edid_parse(vo->edid, + &vo->edid_info)) + DBG_ERR("parse EDID\n"); + } else { + DBG_ERR("read EDID\n"); + } + } + } + break; +#endif + case 8: + case 9: + govrh_set_clock((ctl_name == 8) ? p_govrh : p_govrh2, + vpp_proc_value); + DPRINT("set govr pixclk %d\n", vpp_proc_value); + break; + case 10: + DPRINT("---------- scale mode ----------\n"); + DPRINT("0-recursive normal\n"); + DPRINT("1-recursive sw bilinear\n"); + DPRINT("2-recursive hw bilinear\n"); + DPRINT("3-realtime noraml (quality but x/32 limit)\n"); + DPRINT("4-realtime bilinear (fit edge w skip line)\n"); + DPRINT("-------------------------------------\n"); + p_scl->scale_mode = vpp_proc_value; + break; + case 11: + p_scl->filter_mode = vpp_proc_value; + break; +#ifdef CONFIG_WMT_HDMI + case 12: + g_vpp.hdmi_cp_enable = vpp_proc_value; + hdmi_set_cp_enable(vpp_proc_value); + break; + case 13: + g_vpp.hdmi_3d_type = vpp_proc_value; + hdmi_tx_vendor_specific_infoframe_packet(); + break; + case 14: + g_vpp.hdmi_certify_flag = vpp_proc_value; + break; +#endif + case 15: + govrh_set_brightness(p_govrh, vpp_proc_value); + break; + case 16: + govrh_set_contrast(p_govrh, vpp_proc_value); + break; + case 17: + govrh_set_saturation(p_govrh, vpp_proc_value); + break; + case 18: + g_vpp.fb_manual = vpp_proc_value; + break; + default: + break; + } + } + return ret; +} + +struct proc_dir_entry *vpp_proc_dir; +static ctl_table vpp_table[] = { + { /* .ctl_name = 1, */ + .procname = "dbg_msg", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 2, */ + .procname = "dbg_wait", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 3, */ + .procname = "dbg_flag", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 4, */ + .procname = "edid_disable", + .data = &edid_disable, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 5, */ + .procname = "edid_msg", + .data = &edid_msg_enable, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 6, */ + .procname = "vout_edid", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 7, */ + .procname = "vo_mode", + .data = vpp_proc_str, + .maxlen = 12, + .mode = 0666, + .proc_handler = &proc_dostring, + }, + { /* .ctl_name = 8, */ + .procname = "govr1_pixclk", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 9, */ + .procname = "govr2_pixclk", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 10, */ + .procname = "scl_scale_mode", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 11, */ + .procname = "scl_filter", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 12 */ + .procname = "hdmi_cp_enable", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 13 */ + .procname = "hdmi_3d", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 14 */ + .procname = "hdmi_certify", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 15 */ + .procname = "brightness", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 16 */ + .procname = "contrast", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 17 */ + .procname = "saturation", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* .ctl_name = 18 */ + .procname = "fb_manual", + .data = &vpp_proc_value, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = &vpp_do_proc, + }, + { /* end of table */ + } +}; + +static ctl_table vpp_root_table[] = { + { + .procname = "vpp", /* create path ==> /proc/sys/vpp */ + .mode = 0555, + .child = vpp_table + }, + { /* end of table */ + } +}; +static struct ctl_table_header *vpp_table_header; +#endif + +static int vpp_sts_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + struct govrh_regs *regs = (struct govrh_regs *) REG_GOVRH_BASE1_BEGIN; + unsigned int yaddr, caddr; + char *p = buf; + unsigned int reg; + + p += sprintf(p, "--- VPP HW status ---\n"); +#ifdef WMT_FTBLK_GOVRH + p += sprintf(p, "GOVRH memory read underrun error %d,cnt %d,cnt2 %d\n", + (regs->interrupt.val & 0x200) ? 1 : 0, + p_govrh->underrun_cnt, p_govrh2->underrun_cnt); + p_govrh->clr_sts(VPP_INT_ALL); +#endif + +#ifdef WMT_FTBLK_SCL + p += sprintf(p, "---------------------------------------\n"); + p += sprintf(p, "SCL TG error %d\n", scl_regs1->tg_sts.b.tgerr); + p += sprintf(p, "SCLR MIF1 read error %d\n", + scl_regs1->r_fifo_ctl.b.r1_mif_err); + p += sprintf(p, "SCLR MIF2 read error %d\n", + scl_regs1->r_fifo_ctl.b.r2_mif_err); + p += sprintf(p, "SCLW RGB fifo overflow %d\n", + scl_regs1->w_ff_ctl.b.mif_rgb_err); + p += sprintf(p, "SCLW Y fifo overflow %d\n", + scl_regs1->w_ff_ctl.b.mif_y_err); + p += sprintf(p, "SCLW C fifo overflow %d\n", + scl_regs1->w_ff_ctl.b.mif_c_err); + p_scl->clr_sts(VPP_INT_ALL); +#endif + + p += sprintf(p, "---------------------------------------\n"); + p += sprintf(p, "(880.0)GOVRH Enable %d,(900.0)TG %d\n", + regs->mif.b.enable, regs->tg_enable.b.enable); + + reg = inl(PM_CTRL_BASE_ADDR + 0x258); + p += sprintf(p, "--- POWER CONTROL ---\n"); + p += sprintf(p, "0x%x = 0x%x\n", PM_CTRL_BASE_ADDR + 0x258, reg); + p += sprintf(p, "HDCP %d,VPP %d,SCL %d,HDMI I2C %d\n", + (reg & BIT7) ? 1 : 0, (reg & BIT18) ? 1 : 0, + (reg & BIT21) ? 1 : 0, (reg & BIT22) ? 1 : 0); + p += sprintf(p, "HDMI %d,GOVR %d,NA12 %d\n", + (reg & BIT23) ? 1 : 0, (reg & BIT25) ? 1 : 0, + (reg & BIT16) ? 1 : 0); + p += sprintf(p, "DVO %d,HDMI OUT %d,LVDS %d\n", (reg & BIT29) ? 1 : 0, + (reg & BIT30) ? 1 : 0, (reg & BIT14) ? 1 : 0); + + p += sprintf(p, "--- VPP fb Address ---\n"); + +#ifdef WMT_FTBLK_GOVRH + govrh_get_fb_addr(p_govrh, &yaddr, &caddr); + p += sprintf(p, "GOVRH fb addr Y(0x%x) 0x%x, C(0x%x) 0x%x\n", + REG_GOVRH_YSA, yaddr, REG_GOVRH_CSA, caddr); + govrh_get_fb_addr(p_govrh2, &yaddr, &caddr); + p += sprintf(p, "GOVRH2 fb addr Y(0x%x) 0x%x, C(0x%x) 0x%x\n", + REG_GOVRH2_YSA, yaddr, REG_GOVRH2_CSA, caddr); +#endif + p_govrh->underrun_cnt = 0; + p_govrh2->underrun_cnt = 0; + return p - buf; +} + +static int vpp_reg_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + char *p = buf; + struct vpp_mod_base_t *mod_p; + int i; + + DPRINT("Product ID:0x%x\n", vpp_get_chipid()); + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->dump_reg) + mod_p->dump_reg(); + } +#ifdef WMT_FTBLK_HDMI + hdmi_reg_dump(); +#endif +#ifdef WMT_FTBLK_LVDS + lvds_reg_dump(); +#endif + return p - buf; +} +#endif + +irqreturn_t vpp_interrupt_routine(int irq, void *dev_id) +{ + enum vpp_int_t int_sts; + + switch (irq) { + case VPP_IRQ_VPPM: /* VPP */ + int_sts = p_vppm->get_sts(); + p_vppm->clr_sts(int_sts); + + vpp_dbg_show_val1(VPP_DBGLVL_INT, 0, "[VPP] VPPM INT", int_sts); + { + int i; + unsigned int mask; + struct vpp_irqproc_t *irqproc; + + for (i = 0, mask = 0x1; (i < 32) && int_sts; i++, mask <<= 1) { + if ((int_sts & mask) == 0) + continue; + + irqproc = vpp_irqproc_get_entry(mask); + if (irqproc) { + if (list_empty(&irqproc->list) == 0) + tasklet_schedule(&irqproc->tasklet); + } else { + irqproc = vpp_irqproc_get_entry(VPP_INT_MAX); + if (list_empty(&irqproc->list) == 0) { + struct vpp_proc_t *entry; + struct list_head *ptr; + + ptr = (&irqproc->list)->next; + entry = list_entry(ptr, + struct vpp_proc_t, list); + if (entry->type == mask) + tasklet_schedule( + &irqproc->tasklet); + } + } + int_sts &= ~mask; + } + } + break; +#ifdef WMT_FTBLK_SCL + case VPP_IRQ_SCL: /* SCL */ + int_sts = p_scl->get_sts(); + p_scl->clr_sts(int_sts); + vpp_dbg_show_val1(VPP_DBGLVL_INT, 0, "[VPP] SCL INT", int_sts); + break; +#endif +#ifdef WMT_FTBLK_GOVRH + case VPP_IRQ_GOVR: /* GOVR */ + case VPP_IRQ_GOVR2: + { + struct govrh_mod_t *govr; + + govr = (irq == VPP_IRQ_GOVR) ? p_govrh : p_govrh2; + int_sts = govr->get_sts(); + govr->clr_sts(int_sts); + vpp_dbg_show_val1(VPP_DBGLVL_INT, 0, "[VPP] GOVR INT", int_sts); + govr->underrun_cnt++; +#ifdef VPP_DBG_DIAG_NUM + vpp_dbg_show(VPP_DBGLVL_DIAG, 3, "GOVR MIF Err"); + vpp_dbg_diag_delay = 10; +#endif + } + break; +#endif + default: + DPRINT("*E* invalid vpp isr\n"); + break; + } + return IRQ_HANDLED; +} + +void vpp_wait_vsync(int no, int cnt) +{ + struct govrh_mod_t *govr; + + govr = vout_info_get_govr(no); + if (govr) { + if (govrh_get_MIF_enable(govr)) { + vpp_irqproc_work((govr->mod == VPP_MOD_GOVRH) ? + VPP_INT_GOVRH_VBIS : VPP_INT_GOVRH2_VBIS, + 0, 0, 100 * cnt, cnt); + if (vpp_check_dbg_level(VPP_DBGLVL_DISPFB)) + MSG("wait vsync(%d,%d)\n", no, cnt); + } + } +} + +/*----------------------- vpp ioctl --------------------------------------*/ +int vpp_common_ioctl(unsigned int cmd, unsigned long arg) +{ + struct vpp_mod_base_t *mod_p; + struct vpp_fb_base_t *mod_fb_p; + int retval = 0; + + switch (cmd) { + case VPPIO_VPPGET_INFO: + { + int i; + vpp_cap_t parm; + + parm.chip_id = vpp_get_chipid(); + parm.version = 0x01; + parm.resx_max = VPP_HD_MAX_RESX; + parm.resy_max = VPP_HD_MAX_RESY; + parm.pixel_clk = 400000000; + parm.module = 0x0; + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p) + parm.module |= (0x01 << i); + } + parm.option = VPP_CAP_DUAL_DISPLAY; + copy_to_user((void *)arg, (void *) &parm, sizeof(vpp_cap_t)); + } + break; + case VPPIO_VPPSET_INFO: + { + vpp_cap_t parm; + + copy_from_user((void *)&parm, (const void *)arg, + sizeof(vpp_cap_t)); + } + break; + case VPPIO_I2CSET_BYTE: + { + vpp_i2c_t parm; + unsigned int id; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_i2c_t)); + id = (parm.addr & 0x0000FF00) >> 8; + vpp_i2c_write(id, (parm.addr & 0xFF), parm.index, + (char *)&parm.val, 1); + } + break; + case VPPIO_I2CGET_BYTE: + { + vpp_i2c_t parm; + unsigned int id; + int len; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_i2c_t)); + id = (parm.addr & 0x0000FF00) >> 8; + len = parm.val; + { + unsigned char buf[len]; + + vpp_i2c_read(id, (parm.addr & 0xFF), parm.index, + buf, len); + parm.val = buf[0]; + } + copy_to_user((void *)arg, (void *) &parm, sizeof(vpp_i2c_t)); + } + break; + case VPPIO_MODULE_FBINFO: + { + vpp_mod_fbinfo_t parm; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_mod_fbinfo_t)); + + if (g_vpp.virtual_display) + parm.mod = (hdmi_get_plugin()) ? + VPP_MOD_GOVRH : VPP_MOD_GOVRH2; + mod_fb_p = vpp_mod_get_fb_base(parm.mod); + if (!mod_fb_p) + break; + mod_p = vpp_mod_get_base(parm.mod); + if (parm.read) { + parm.fb = mod_fb_p->fb; + switch (parm.mod) { + case VPP_MOD_GOVRH: + case VPP_MOD_GOVRH2: + govrh_get_framebuffer( + (struct govrh_mod_t *)mod_p, + &parm.fb); + break; + default: + break; + } + copy_to_user((void *)arg, (void *) &parm, + sizeof(vpp_mod_fbinfo_t)); + } else { + mod_fb_p->fb = parm.fb; + mod_fb_p->set_framebuf(&parm.fb); + } + } + break; +#ifdef CONFIG_VPP_STREAM_CAPTURE + case VPPIO_STREAM_ENABLE: + g_vpp.stream_enable = arg; + g_vpp.stream_mb_sync_flag = 0; + g_vpp.stream_mb_lock = 0; + g_vpp.stream_mb_index = 0xFF; + MSG("VPPIO_STREAM_ENABLE %d\n", g_vpp.stream_enable); + vpp_netlink_notify(WP_PID, DEVICE_STREAM, + (g_vpp.stream_enable) ? 1 : 0); + wmt_enable_mmfreq(WMT_MMFREQ_MIRACAST, g_vpp.stream_enable); + break; + case VPPIO_STREAM_GETFB: + { + vdo_framebuf_t fb; + + vpp_lock(); + if (g_vpp.stream_mb_index == 0xFF) { /* not avail */ + retval = -1; + vpp_unlock(); + break; + } + fb = vout_info[g_vpp.stream_fb]->fb; + fb.fb_h = vpp_calc_align(fb.img_h, 16); + copy_to_user((void *)arg, (void *) &fb, sizeof(vdo_framebuf_t)); + retval = vpp_mb_get(fb.y_addr); + vpp_unlock(); + } + break; + case VPPIO_STREAM_PUTFB: + { + vdo_framebuf_t fb; + copy_from_user((void *) &fb, (const void *)arg, + sizeof(vdo_framebuf_t)); + vpp_lock(); + vpp_mb_put(fb.y_addr); + vpp_unlock(); + } + break; +#endif + case VPPIO_MULTIVD_ENABLE: + wmt_enable_mmfreq(WMT_MMFREQ_MULTI_VD, arg); + break; + case VPPIO_MODSET_CSC: + { + struct vpp_mod_parm_t parm; + copy_from_user((void *) &parm, (const void *)arg, + sizeof(struct vpp_mod_parm_t)); + switch (parm.mod) { + case VPP_MOD_GOVRH: + p_govrh->csc_mode_force = parm.parm; + break; + case VPP_MOD_GOVRH2: + if (p_govrh2->csc_mode_force != parm.parm) + MSG("GOVRH2 CSC %d-->%d\n", + p_govrh2->csc_mode_force, parm.parm); + p_govrh2->csc_mode_force = parm.parm; + break; + default: + break; + } + } + break; + default: + retval = -ENOTTY; + break; + } + return retval; +} + +int vpp_vout_ioctl(unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + switch (cmd) { + case VPPIO_VOGET_INFO: + { + vpp_vout_info_t parm; + struct vout_info_t *info; + int fb_no, i, idx; + unsigned int status; + + memset(&parm, 0, sizeof(vpp_vout_info_t)); + for (fb_no = 0, idx = 0; ; fb_no++) { + info = vout_info_get_entry(fb_no); + if (!info) + break; + + for (i = 0; i < VPP_VOUT_NUM; i++, idx++) { + if (info->vout[i] == 0) + break; + parm.mode[idx] = vout_get_mode_adapter( + info->vout[i]); + status = info->vout[i]->status | + (fb_no << 8); + DBGMSG("GET_INFO(fb %d,mode %d,sts 0x%x)", + fb_no, parm.mode[idx], status); + DBGMSG("plug %d\n", + (status & VPP_VOUT_STS_PLUGIN) ? 1 : 0); + parm.status[idx] = status; + } + } + copy_to_user((void *)arg, (const void *) &parm, + sizeof(vpp_vout_info_t)); + } + break; + case VPPIO_VOUT_VMODE: + { + vpp_vout_vmode_t parm; + int i; + struct fb_videomode *vmode; + unsigned int resx, resy, fps; + unsigned int pre_resx, pre_resy, pre_fps; + int index, from_index; + int support; + unsigned int option, pre_option; +#ifdef CONFIG_WMT_EDID + struct edid_info_t *edid_info; +#endif + struct fb_videomode *edid_vmode; + vpp_vout_t mode; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_vout_vmode_t)); + from_index = parm.num; + parm.num = 0; + mode = parm.mode & 0xF; +#ifdef CONFIG_VPP_DEMO + parm.parm[parm.num].resx = 1920; + parm.parm[parm.num].resy = 1080; + parm.parm[parm.num].fps = 60; + parm.parm[parm.num].option = 0; + parm.num++; +#else +#ifdef CONFIG_WMT_EDID + { + struct vout_t *vo; + + vo = vout_get_entry_adapter(mode); + if (!vo) + goto vout_vmode_end; + + if (!(vo->status & VPP_VOUT_STS_PLUGIN)) { + DPRINT("*W* not plugin\n"); + goto vout_vmode_end; + } + + if (vout_get_edid(vo->num) == 0) { + DPRINT("*W* read EDID fail\n"); + goto vout_vmode_end; + } + if (edid_parse(vo->edid, &vo->edid_info) == 0) { + DPRINT("*W* parse EDID fail\n"); + goto vout_vmode_end; + } + edid_info = &vo->edid_info; + } +#endif + index = 0; + resx = resy = fps = option = 0; + pre_resx = pre_resy = pre_fps = pre_option = 0; + for (i = 0; ; i++) { + int ret = 0; + vmode = (struct fb_videomode *) &vpp_videomode[i]; + if (vmode->pixclock == 0) + break; + resx = vmode->xres; + resy = vmode->yres; + fps = vmode->refresh; + option = fps & EDID_TMR_FREQ; + option |= (vmode->vmode & FB_VMODE_INTERLACED) ? + EDID_TMR_INTERLACE : 0; + if ((pre_resx == resx) && (pre_resy == resy) && + (pre_fps == fps) && (pre_option == option)) + continue; + pre_resx = resx; + pre_resy = resy; + pre_fps = fps; + pre_option = option; + support = 0; +#ifdef CONFIG_WMT_EDID + if (ret = edid_find_support(edid_info, resx, resy, + option, &edid_vmode)) +#else + if (1) +#endif + support = 1; + + if (support) { + if (index >= from_index) { + parm.parm[parm.num].resx = resx; + parm.parm[parm.num].resy = resy; + parm.parm[parm.num].fps = fps; + parm.parm[parm.num].option = + vmode->vmode; +#ifdef CONFIG_WMT_EDID + if(ret == 3) + parm.parm[parm.num].option |= 0x80; +#endif + parm.num++; + } + index++; + if (parm.num >= VPP_VOUT_VMODE_NUM) + break; + } + } +#ifdef CONFIG_WMT_EDID +vout_vmode_end: +#endif +#endif +#if 0 + if (parm.num == 0) { /* if no EDID*/ + enum vout_tvformat_t tvformat = vout_get_tvformat(); + if (g_vpp.virtual_display || + (g_vpp.dual_display == 0)) { + if (mode == VPP_VOUT_DVI) { + switch (tvformat) { + case TV_PAL: + parm.parm[0].resx = 720; + parm.parm[0].resy = 576; + parm.parm[0].fps = 50; + parm.num = 1; + parm.parm[0].option = 0; + break; + case TV_NTSC: + parm.parm[0].resx = 720; + parm.parm[0].resy = 480; + parm.parm[0].fps = 60; + parm.num = 1; + parm.parm[0].option = 0; + break; + default: + break; + } + } + } + } +#endif + DBG_MSG("[VPP] get support vmode %d\n", parm.num); + copy_to_user((void *)arg, (const void *) &parm, + sizeof(vpp_vout_vmode_t)); + } + break; + case VPPIO_VOGET_EDID: + { + vpp_vout_edid_t parm; + char *edid; + struct vout_t *vo; + int size; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_vout_edid_t)); + size = 0; +#ifdef CONFIG_WMT_EDID + vo = vout_get_entry_adapter(parm.mode); + if (!vo) + goto vout_edid_end; + + if (!(vo->status & VPP_VOUT_STS_PLUGIN)) { + DBG_ERR("*W* not plugin\n"); + goto vout_edid_end; + } + + edid = vout_get_edid(vo->num); + if (edid == 0) { + DBG_ERR("*W* read EDID fail\n"); + goto vout_edid_end; + } + size = (edid[0x7E] + 1) * 128; + if (size > parm.size) + size = parm.size; + copy_to_user((void *) parm.buf, (void *) edid, size); +vout_edid_end: +#endif + parm.size = size; + copy_to_user((void *)arg, (const void *) &parm, + sizeof(vpp_vout_edid_t)); + } + break; + case VPPIO_VOGET_CP_INFO: + { + vpp_vout_cp_info_t parm; + int num; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_vout_cp_info_t)); + num = parm.num; + if (num >= VOUT_MODE_MAX) { + retval = -ENOTTY; + break; + } + memset(&parm, 0, sizeof(vpp_vout_cp_info_t)); + switch (num) { + case VOUT_HDMI: + if (!g_vpp.hdmi_certify_flag) { + if (g_vpp.hdmi_bksv[0] == 0) { + hdmi_get_bksv(&g_vpp.hdmi_bksv[0]); + DBG_MSG("get BKSV 0x%x 0x%x\n", + g_vpp.hdmi_bksv[0], + g_vpp.hdmi_bksv[1]); + } + } + case VOUT_DVO2HDMI: + parm.bksv[0] = g_vpp.hdmi_bksv[0]; + parm.bksv[1] = g_vpp.hdmi_bksv[1]; + break; + default: + parm.bksv[0] = parm.bksv[1] = 0; + break; + } + copy_to_user((void *)arg, (const void *) &parm, + sizeof(vpp_vout_cp_info_t)); + } + break; + case VPPIO_VOSET_CP_KEY: + if (g_vpp.hdmi_cp_p == 0) { + g_vpp.hdmi_cp_p = kmalloc(sizeof(vpp_vout_cp_key_t), + GFP_KERNEL); + } + if (g_vpp.hdmi_cp_p) { + copy_from_user((void *) g_vpp.hdmi_cp_p, + (const void *)arg, sizeof(vpp_vout_cp_key_t)); + if (hdmi_cp) + hdmi_cp->init(); + } + break; +#ifdef WMT_FTBLK_HDMI + case VPPIO_VOSET_AUDIO_PASSTHRU: + hdmi_regs1->aud_mode.b.sub_packet = (arg) ? 0xF : 0x0; + break; +#endif +#ifdef CONFIG_VPP_VIRTUAL_DISPLAY + case VPPIO_VOSET_VIRTUAL_FBDEV: + { + struct vout_info_t *info; + int i; + + g_vpp.fb0_bitblit = (arg) ? 0 : 1; + for (i = 1; ; i++) { + info = vout_info_get_entry(i); + if (!info) + break; + if (info->alloc_mode != VOUT_ALLOC_GE_OVERSCAN) + continue; + if (info->mb == 0) + continue; + MSG("fb%d mb free 0x%x\n", i, info->mb); + mb_free(info->mb); + info->mb = 0; + } + MSG("[VPP] virtual display %d\n", (int)arg); + } + break; +#endif + case VPPIO_VOGET_HDMI_3D: + { + struct vpp_vout_parm_s parm; + struct vout_t *vo; + + vo = vout_get_entry(VPP_VOUT_NUM_HDMI); + parm.arg = edid_get_hdmi_3d_mask(&vo->edid_info, hdmi_info.vic); + copy_to_user((void *)arg, (const void *) &parm, + sizeof(struct vpp_vout_parm_s)); + } + break; + default: + retval = -ENOTTY; + break; + } + return retval; +} + +int vpp_scl_ioctl(unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + switch (cmd) { + case VPPIO_SCL_SCALE_OVERLAP: + { + vpp_scale_overlap_t parm; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_scale_overlap_t)); + if (vpp_check_dbg_level(VPP_DBGLVL_FPS)) + vpp_dbg_timer(&p_scl->overlap_timer, 0, 1); + + p_scl->scale_sync = 1; + retval = scl_set_scale_overlap(&parm.src_fb, + &parm.src2_fb, &parm.dst_fb); + + if (vpp_check_dbg_level(VPP_DBGLVL_FPS)) + vpp_dbg_timer(&p_scl->overlap_timer, "overlap", 2); + } + break; + case VPPIO_SCL_SCALE_ASYNC: + case VPPIO_SCL_SCALE: + { + vpp_scale_t parm; + + p_scl->scale_sync = (cmd == VPPIO_SCL_SCALE) ? 1 : 0; + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_scale_t)); + if (vpp_check_dbg_level(VPP_DBGLVL_FPS)) + vpp_dbg_timer(&p_scl->scale_timer, 0, 1); + + vpp_set_NA12_hiprio(1); + retval = vpp_set_recursive_scale(&parm.src_fb, &parm.dst_fb); + vpp_set_NA12_hiprio(0); + + if (vpp_check_dbg_level(VPP_DBGLVL_FPS)) + vpp_dbg_timer(&p_scl->scale_timer, "scale", 2); + copy_to_user((void *)arg, (void *)&parm, sizeof(vpp_scale_t)); + } + break; + case VPPIO_SCL_SCALE_FINISH: + retval = p_scl->scale_finish(); + break; + case VPPIO_SCLSET_OVERLAP: + { + vpp_overlap_t parm; + + copy_from_user((void *) &parm, (const void *)arg, + sizeof(vpp_overlap_t)); + vpp_mod_set_clock(VPP_MOD_SCL, VPP_FLAG_ENABLE, 0); + scl_set_overlap(&parm); + vpp_mod_set_clock(VPP_MOD_SCL, VPP_FLAG_DISABLE, 0); + } + break; + default: + retval = -ENOTTY; + break; + } + return retval; +} + +static int wmt_vpp_open(struct inode *inode, struct file *filp) +{ + DBG_MSG("\n"); + return 0; +} + +static int wmt_vpp_release(struct inode *inode, struct file *filp) +{ + DBG_MSG("\n"); + return 0; +} + +static long wmt_vpp_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = -EINVAL; + int skip_mutex = 0; + +/* DBG_MSG("0x%x,0x%x\n", cmd, (int)arg); */ + + if (_IOC_TYPE(cmd) != VPPIO_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > VPPIO_MAX) + return -ENOTTY; + + /* check argument area */ + if (_IOC_DIR(cmd) & _IOC_READ) + ret = !access_ok(VERIFY_WRITE, + (void __user *) arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + ret = !access_ok(VERIFY_READ, + (void __user *) arg, _IOC_SIZE(cmd)); + else + ret = 0; + + if (ret) + return -EFAULT; + + if (vpp_check_dbg_level(VPP_DBGLVL_IOCTL)) { + switch (cmd) { + default: + DPRINT("[VPP] ioctl cmd 0x%x,arg 0x%x\n", + _IOC_NR(cmd), (int)arg); + break; + } + } + + switch (cmd) { + case VPPIO_STREAM_GETFB: /* block mode should wait vsync */ + skip_mutex = 1; + break; + default: + /* scale should wait complete */ + if ((_IOC_NR(cmd) >= VPPIO_SCL_BASE) && + (_IOC_NR(cmd) < VPPIO_MAX)) + skip_mutex = 1; + break; + } + + if (!skip_mutex) + down(&wmt_vpp_sem); + + switch (_IOC_NR(cmd)) { + case VPPIO_VPP_BASE ... (VPPIO_VOUT_BASE-1): + /* DBGMSG("VPP command ioctl\n"); */ + ret = vpp_common_ioctl(cmd, arg); + break; + case VPPIO_VOUT_BASE ... (VPPIO_SCL_BASE - 1): + ret = vpp_vout_ioctl(cmd, arg); + break; + case VPPIO_SCL_BASE ... (VPPIO_MAX-1): + /* DBGMSG("SCL ioctl\n"); */ + ret = vpp_scl_ioctl(cmd, arg); + break; + default: + DBG_ERR("*W* cmd 0x%x\n", cmd); + break; + } + + if (!skip_mutex) + up(&wmt_vpp_sem); + + if (vpp_check_dbg_level(VPP_DBGLVL_IOCTL)) { + switch (cmd) { + default: + DPRINT("[VPP] ioctl cmd 0x%x,ret 0x%x\n", + _IOC_NR(cmd), (int)ret); + break; + } + } + return ret; +} + +const struct file_operations wmt_vpp_fops = { + .owner = THIS_MODULE, + .open = wmt_vpp_open, + .release = wmt_vpp_release, + .unlocked_ioctl = wmt_vpp_ioctl, +}; + +static int wmt_vpp_probe(struct platform_device *dev) +{ + DBG_MSG("\n"); + + vpp_irqproc_init(); + vpp_netlink_init(); + vpp_init(); +#ifdef CONFIG_VPP_PROC + /* init system proc */ + if (vpp_proc_dir == 0) { + struct proc_dir_entry *res; + + vpp_proc_dir = proc_mkdir("driver/vpp", NULL); + res = create_proc_entry("sts", 0, vpp_proc_dir); + if (res) + res->read_proc = vpp_sts_read_proc; + res = create_proc_entry("reg", 0, vpp_proc_dir); + if (res) + res->read_proc = vpp_reg_read_proc; + vpp_table_header = register_sysctl_table(vpp_root_table); + } +#endif + + /* init interrupt service routine */ +#ifdef WMT_FTBLK_SCL + if (vpp_request_irq(VPP_IRQ_SCL, vpp_interrupt_routine, + SA_INTERRUPT, "scl", (void *)&g_vpp)) { + DPRINT("*E* request VPP ISR fail\n"); + return -1; + } +#endif + if (vpp_request_irq(VPP_IRQ_VPPM, vpp_interrupt_routine, + SA_INTERRUPT, "vpp", (void *)&g_vpp)) { + DPRINT("*E* request VPP ISR fail\n"); + return -1; + } +#ifdef WMT_FTBLK_GOVRH + if (vpp_request_irq(VPP_IRQ_GOVR, vpp_interrupt_routine, + SA_INTERRUPT, "govr", (void *)&g_vpp)) { + DPRINT("*E* request VPP ISR fail\n"); + return -1; + } + + if (vpp_request_irq(VPP_IRQ_GOVR2, vpp_interrupt_routine, + SA_INTERRUPT, "govr2", (void *)&g_vpp)) { + DPRINT("*E* request VPP ISR fail\n"); + return -1; + } +#endif + vpp_switch_state_init(); + return 0; +} + +static int wmt_vpp_remove(struct platform_device *dev) +{ + return 0; +} + +#ifdef CONFIG_PM +unsigned int wmt_vpp_vout_blank_mask; +static int wmt_vpp_suspend(struct device *dev) +{ + + struct vpp_mod_base_t *mod_p; + struct vout_t *vo; + int i; + + DPRINT("Enter wmt_vpp_suspend\n"); + + wmt_vpp_vout_blank_mask = 0; + for (i = 0; i <= VPP_VOUT_NUM; i++) { + vo = vout_get_entry(i); + if (vo && !(vo->status & VPP_VOUT_STS_BLANK)) + wmt_vpp_vout_blank_mask |= (0x1 << i); + vout_set_blank(i, VOUT_BLANK_POWERDOWN); + if (vo && vo->dev && vo->dev->suspend) + vo->dev->suspend(); + } + + if (vout_check_plugin(1)) + vpp_netlink_notify_plug(VPP_VOUT_ALL, 0); + else + wmt_set_mmfreq(0); + + /* disable module */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->suspend) + mod_p->suspend(0); + } +#ifdef WMT_FTBLK_HDMI + hdmi_suspend(0); +#endif + wmt_suspend_mmfreq(); +#ifdef WMT_FTBLK_LVDS + lvds_suspend(0); +#endif + /* disable tg */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->suspend) + mod_p->suspend(1); + } +#ifdef WMT_FTBLK_HDMI + hdmi_suspend(1); +#endif +#ifdef WMT_FTBLK_LVDS + lvds_suspend(1); +#endif + /* backup registers */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->suspend) + mod_p->suspend(2); + } +#ifdef WMT_FTBLK_HDMI + hdmi_suspend(2); +#endif +#ifdef WMT_FTBLK_LVDS + lvds_suspend(2); +#endif +#if 0 + if (lcd_get_lvds_id() == LCD_LVDS_1024x600) { + mdelay(5); + /* GPIO10 off 8ms -> clock -> off */ + outl(inl(GPIO_BASE_ADDR + 0xC0) & ~BIT10, + GPIO_BASE_ADDR + 0xC0); + } +#endif + return 0; +} + +static int wmt_vpp_freeze(struct device *dev) +{ + return 0; +} + +#ifdef CONFIG_VPP_SHENZHEN +extern int lcd_spi_resume(void); +#endif + +static int wmt_vpp_resume(struct device *dev) +{ + + struct vpp_mod_base_t *mod_p; + int i; + +#if 0 + if (lcd_get_lvds_id() == LCD_LVDS_1024x600) { + /* GPIO10 6ms -> clock r0.02.04 */ + outl(inl(GPIO_BASE_ADDR + 0x80) | BIT10, + GPIO_BASE_ADDR + 0x80); + outl(inl(GPIO_BASE_ADDR + 0xC0) | BIT10, + GPIO_BASE_ADDR + 0xC0); + } +#endif + + DPRINT("Enter wmt_vpp_resume\n"); + +#ifdef CONFIG_VPP_SHENZHEN + lcd_spi_resume(); +#endif + + /* restore registers */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->resume) + mod_p->resume(0); + } +#ifdef WMT_FTBLK_LVDS + lvds_resume(0); +#endif +#ifdef WMT_FTBLK_HDMI + hdmi_check_plugin(0); + hdmi_resume(0); +#endif + /* enable tg */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->resume) + mod_p->resume(1); + } +#ifdef WMT_FTBLK_LVDS + lvds_resume(1); +#endif +#ifdef WMT_FTBLK_HDMI + hdmi_resume(1); +#endif + /* wait */ + msleep(150); + + /* enable module */ + for (i = 0; i < VPP_MOD_MAX; i++) { + mod_p = vpp_mod_get_base(i); + if (mod_p && mod_p->resume) + mod_p->resume(2); + } +#ifdef WMT_FTBLK_LVDS + lvds_resume(2); +#endif + if (lcd_get_lvds_id() != LCD_LVDS_1024x600) { + for (i = 0; i < VPP_VOUT_NUM; i++) { + struct vout_t *vo; + + vo = vout_get_entry(i); + if (vo && vo->dev) { + if (lcd_get_type() == 0) /* DVI type */ + govrh_set_dvo_enable(vo->govr, 1); + vo->dev->init(vo); + vo->dev->set_mode(&vo->option[0]); + vo->inf->init(vo, 0); + } + + if (wmt_vpp_vout_blank_mask & (0x1 << i)) + vout_set_blank(i, VOUT_BLANK_UNBLANK); + if (vo && vo->dev && vo->dev->resume) + vo->dev->resume(); + } + } + wmt_resume_mmfreq(); + if (vout_check_plugin(0)) + vpp_netlink_notify_plug(VPP_VOUT_ALL, 1); + else + wmt_set_mmfreq(0); +#ifdef WMT_FTBLK_HDMI + hdmi_resume(2); +#endif + return 0; +} + +static int wmt_vpp_restore(struct device *dev) +{ + return 0; +} + +static void wmt_vpp_shutdown +( + struct platform_device *pDev /*!<; // a pointer struct device */ +) +{ + DPRINT("wmt_vpp_shutdown\n"); + hdmi_set_power_down(1); + lvds_set_power_down(1); +} + +#else +#define wmt_vpp_suspend NULL +#define wmt_vpp_resume NULL +#define wmt_vpp_shutdown NULL +#endif + +/******************************************************************** + device driver struct define +**********************************************************************/ +static struct dev_pm_ops wmt_vpp_pm_ops = { + .suspend = wmt_vpp_suspend, + .resume = wmt_vpp_resume, + .freeze = wmt_vpp_freeze, + .thaw = wmt_vpp_restore, + .restore = wmt_vpp_restore, +}; + +static struct platform_driver wmt_vpp_driver = { + .driver.name = DEVICE_NAME, /* equal to platform device name. */ +/* .bus = &platform_bus_type, */ + .probe = wmt_vpp_probe, + .remove = wmt_vpp_remove, + /* .suspend = wmt_vpp_suspend, */ + /* .resume = wmt_vpp_resume, */ + .shutdown = wmt_vpp_shutdown, + .driver.pm = &wmt_vpp_pm_ops +}; + +static void wmt_vpp_platform_release(struct device *device) +{ +} + +/******************************************************************** + platform device struct define +*********************************************************************/ +/* static u64 wmt_vpp_dma_mask = 0xffffffffUL; */ +static struct platform_device wmt_vpp_device = { + .name = DEVICE_NAME, + .id = 0, + .dev = { + .release = wmt_vpp_platform_release, +#if 0 + .dma_mask = &wmt_vpp_dma_mask, + .coherent_dma_mask = ~0, +#endif + }, + .num_resources = 0, /* ARRAY_SIZE(cipher_resources), */ + .resource = NULL, /* cipher_resources, */ +}; + +static int __init wmt_vpp_init(void) +{ + int ret; + dev_t dev_no; + + wmt_vpp_major = register_chrdev(0, DEVICE_NAME, &wmt_vpp_fops); + if (wmt_vpp_major < 0) { + DBG_ERR("get major failed\n"); + return -EFAULT; + } + + wmt_vpp_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(wmt_vpp_class)) { + ret = PTR_ERR(wmt_vpp_class); + DBG_ERR("Can't create class : %s !!\n", DEVICE_NAME); + return ret; + } + + dev_no = MKDEV(wmt_vpp_major, 0); + device_create(wmt_vpp_class, NULL, dev_no, NULL, DEVICE_NAME); + ret = platform_device_register(&wmt_vpp_device); + if (ret != 0) + return -ENODEV; + + ret = platform_driver_register(&wmt_vpp_driver); + if (ret != 0) { + platform_device_unregister(&wmt_vpp_device); + return -ENODEV; + } + return 0; +} + +static void __exit wmt_vpp_exit(void) +{ + dev_t dev_no; + + DBG_MSG("\n"); + + vout_exit(); +#ifdef CONFIG_VPP_PROC + unregister_sysctl_table(vpp_table_header); +#endif + platform_driver_unregister(&wmt_vpp_driver); + platform_device_unregister(&wmt_vpp_device); + dev_no = MKDEV(wmt_vpp_major, 0); + device_destroy(wmt_vpp_class, dev_no); + class_destroy(wmt_vpp_class); + unregister_chrdev(wmt_vpp_major, DEVICE_NAME); + return; +} + +module_init(wmt_vpp_init); +module_exit(wmt_vpp_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("WMT VPP driver"); +MODULE_AUTHOR("WMT TECH"); +MODULE_VERSION("1.0.0"); + |