From 06809f0306ae2b1e7acd54ade9a1d864503d817a Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Wed, 12 Aug 2015 09:10:54 +0800 Subject: [PATCH] hdmi:cec:update driver to match android HDMI CEC HAL. Android 5.x introduce HDMI CEC, so we need to porting cec hal and driver to make it work. Signed-off-by: Zheng Yang --- .../video/rockchip/hdmi/rockchip-hdmi-cec.c | 680 +++++------------- .../video/rockchip/hdmi/rockchip-hdmi-cec.h | 39 +- .../video/rockchip/hdmi/rockchip-hdmi-core.c | 2 + .../rockchip-hdmiv2/rockchip_hdmiv2_cec.c | 97 +-- 4 files changed, 220 insertions(+), 598 deletions(-) diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c b/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c index c7457320b0c1..68c7bf115152 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c @@ -6,30 +6,18 @@ #include #include #include -#include #include #include #include "rockchip-hdmi-cec.h" +#include "linux/ioctl.h" +#include "linux/pagemap.h" static struct cec_device *cec_dev; -struct input_dev *devinput; -static struct miscdevice mdev; - -int key_table[] = { - KEY_UP, - KEY_DOWN, - KEY_LEFT, - KEY_RIGHT, - KEY_REPLY, - KEY_BACK, - KEY_POWER, -}; - -static void cecmenucontrol(int uitemp); static int cecreadframe(struct cec_framedata *frame) { - if (frame == NULL || !cec_dev || cec_dev->readframe == NULL) + if (frame == NULL || !cec_dev || + cec_dev->readframe == NULL || !cec_dev->enable) return -1; else return cec_dev->readframe(cec_dev->hdmi, frame); @@ -43,403 +31,32 @@ static int cecsendframe(struct cec_framedata *frame) return cec_dev->sendframe(cec_dev->hdmi, frame); } -static int cecsendping(char logicaddress) -{ - struct cec_framedata cecframe; - - memset(&cecframe, 0, sizeof(struct cec_framedata)); - cecframe.srcdestaddr = logicaddress << 4 | logicaddress; - return cec_dev->sendframe(cec_dev->hdmi, &cecframe); -} - -/*static int CecSendMessage (char opCode, char dest) -{ - struct cec_framedata cecframe; - - cecframe.opcode = opCode; - cecframe.srcdestaddr = MAKE_SRCDEST(cec_dev->address_logic, dest); - cecframe.argcount = 0; - - return cecsendframe(&cecframe); -}*/ - - -/*static void CecSendFeatureAbort (struct cec_framedata *pcpi, char reason) -{ - struct cec_framedata cecframe; - - if ((pcpi->srcdestaddr & 0x0F) != CEC_LOGADDR_UNREGORBC) { - cecframe.opcode = CECOP_FEATURE_ABORT; - cecframe.srcdestaddr = MAKE_SRCDEST( cec_dev->address_logic, - ( pcpi->srcdestaddr & 0xF0) >> 4 ); - cecframe.args[0] = pcpi->opcode; - cecframe.args[1] = reason; - cecframe.argcount = 2; - cecsendframe(&cecframe); - } -}*/ - -static void cecsendimageview(void) -{ - struct cec_framedata cecframe; - - cecframe.opcode = CECOP_IMAGE_VIEW_ON; - cecframe.srcdestaddr = MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_TV); - cecframe.argcount = 0; - cecsendframe(&cecframe); -} - -static void cecsendactivesource(void) -{ - struct cec_framedata cecframe; - - cecframe.opcode = CECOP_ACTIVE_SOURCE; - cecframe.srcdestaddr = MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_UNREGORBC); - cecframe.args[0] = (cec_dev->address_phy & 0xFF00) >> 8; - cecframe.args[1] = (cec_dev->address_phy & 0x00FF); - cecframe.argcount = 2; - cecsendframe(&cecframe); -} - -static void cechandleinactivesource(struct cec_framedata *pcpi) -{ -} - -static void cechandlefeatureabort(struct cec_framedata *pcpi) -{ -} - -static bool validatececmessage(struct cec_framedata *pcpi) -{ - char parametercount = 0; - bool countok = true; - - /* Determine required parameter count */ - - switch (pcpi->opcode) { - case CECOP_IMAGE_VIEW_ON: - case CECOP_TEXT_VIEW_ON: - case CECOP_STANDBY: - case CECOP_GIVE_PHYSICAL_ADDRESS: - case CECOP_GIVE_DEVICE_POWER_STATUS: - case CECOP_GET_MENU_LANGUAGE: - case CECOP_GET_CEC_VERSION: - parametercount = 0; - break; - case CECOP_REPORT_POWER_STATUS: /* power status*/ - case CECOP_CEC_VERSION: /* cec version*/ - parametercount = 1; - break; - case CECOP_INACTIVE_SOURCE: /* physical address*/ - case CECOP_FEATURE_ABORT: - case CECOP_ACTIVE_SOURCE: /* physical address*/ - parametercount = 2; - break; - case CECOP_REPORT_PHYSICAL_ADDRESS: - case CECOP_DEVICE_VENDOR_ID: /* vendor id*/ - parametercount = 3; - break; - case CECOP_SET_OSD_NAME: /* osd name (1-14 bytes)*/ - case CECOP_SET_OSD_STRING: - parametercount = 1; /* must have a minimum of 1 operands*/ - break; - case CECOP_ABORT: - break; - case CECOP_ARC_INITIATE: - break; - case CECOP_ARC_REPORT_INITIATED: - break; - case CECOP_ARC_REPORT_TERMINATED: - break; - case CECOP_ARC_REQUEST_INITIATION: - break; - case CECOP_ARC_REQUEST_TERMINATION: - break; - case CECOP_ARC_TERMINATE: - break; - default: - break; - } - - /* Test for correct parameter count. */ - - if (pcpi->argcount < parametercount) - countok = false; - - return countok; -} - -static bool cecrxmsghandlerlast(struct cec_framedata *pcpi) -{ - bool isdirectaddressed; - struct cec_framedata cecframe; - - isdirectaddressed = !((pcpi->srcdestaddr & 0x0F) == - CEC_LOGADDR_UNREGORBC); - pr_info("isDirectAddressed %d\n", (int)isdirectaddressed); - if (validatececmessage(pcpi)) { - /* If invalid message, ignore it, but treat it as handled */ - if (isdirectaddressed) { - switch (pcpi->opcode) { - case CECOP_USER_CONTROL_PRESSED: - cecmenucontrol(pcpi->args[0]); - break; - - case CECOP_VENDOR_REMOTE_BUTTON_DOWN: - cecmenucontrol(pcpi->args[0]); - break; - case CECOP_FEATURE_ABORT: - cechandlefeatureabort(pcpi); - break; - - case CECOP_GIVE_OSD_NAME: - cecframe.opcode = CECOP_SET_OSD_NAME; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_TV); - cecframe.args[0] = 'r'; - cecframe.args[1] = 'k'; - cecframe.args[2] = '-'; - cecframe.args[3] = 'b'; - cecframe.args[4] = 'o'; - cecframe.args[5] = 'x'; - cecframe.argcount = 6; - cecsendframe(&cecframe); - break; - - case CECOP_VENDOR_COMMAND_WITH_ID: - - if (pcpi->args[2] == 00) { - cecframe.opcode = CECOP_SET_OSD_NAME; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_TV); - cecframe.args[0] = '1'; - cecframe.args[1] = '1'; - cecframe.args[2] = '1'; - cecframe.args[3] = '1'; - cecframe.args[4] = '1'; - cecframe.args[5] = '1'; - cecframe.argcount = 6; - cecsendframe(&cecframe); - } - break; - case CECOP_IMAGE_VIEW_ON: - case CECOP_TEXT_VIEW_ON: - /* In our case, respond the same to both these messages*/ - break; - - case CECOP_GIVE_DEVICE_VENDOR_ID: - cecframe.opcode = CECOP_DEVICE_VENDOR_ID; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_UNREGORBC); - cecframe.args[0] = 0x1; - cecframe.args[1] = 0x2; - cecframe.args[2] = 0x3; - cecframe.argcount = 3; - cecsendframe(&cecframe); - break; - - case CECOP_STANDBY: /* Direct and Broadcast*/ - /* Setting this here will let the main task know */ - /* (via SI_CecGetPowerState) and at the same time */ - /* prevent us from broadcasting a STANDBY message */ - /* of our own when the main task responds by */ - /* calling SI_CecSetPowerState( STANDBY ); */ - cec_dev->powerstatus = CEC_POWERSTATUS_STANDBY; - break; - - case CECOP_INACTIVE_SOURCE: - cechandleinactivesource(pcpi); - break; - - case CECOP_GIVE_PHYSICAL_ADDRESS: - - cecframe.opcode = CECOP_REPORT_PHYSICAL_ADDRESS; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_UNREGORBC); - cecframe.args[0] = (cec_dev->address_phy&0xFF00)>>8; - cecframe.args[1] = (cec_dev->address_phy&0x00FF); - cecframe.args[2] = cec_dev->address_logic; - cecframe.argcount = 3; - cecsendframe(&cecframe); - break; - - case CECOP_GIVE_DEVICE_POWER_STATUS: - /* TV responds with power status. */ - - cecframe.opcode = CECOP_REPORT_POWER_STATUS; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - (pcpi->srcdestaddr & 0xF0) >> 4); - cec_dev->powerstatus = 0x00; - cecframe.args[0] = cec_dev->powerstatus; - cecframe.argcount = 1; - cecsendframe(&cecframe); - break; - - case CECOP_GET_MENU_LANGUAGE: - /* TV Responds with a Set Menu language command. */ - - cecframe.opcode = CECOP_SET_MENU_LANGUAGE; - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_UNREGORBC); - cecframe.args[0] = 'e'; - cecframe.args[1] = 'n'; - cecframe.args[2] = 'g'; - cecframe.argcount = 3; - cecsendframe(&cecframe); - break; - - case CECOP_GET_CEC_VERSION: - /* TV responds to this request with it's CEC version support.*/ - - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_TV); - cecframe.opcode = CECOP_CEC_VERSION; - cecframe.args[0] = 0x05; /* Report CEC1.4b*/ - cecframe.argcount = 1; - cecsendframe(&cecframe); - break; - - case CECOP_REPORT_POWER_STATUS: - /*Someone sent us their power state. - - l_sourcePowerStatus = pcpi->args[0]; - - let NEW SOURCE task know about it. - - if ( l_cecTaskState.task == SI_CECTASK_NEWSOURCE ) - { - l_cecTaskState.cpiState = CPI_RESPONSE; - }*/ - break; - - /* Do not reply to directly addressed 'Broadcast' msgs. */ - case CECOP_REQUEST_ACTIVE_SOURCE: - cecsendactivesource(); - break; - - case CECOP_ACTIVE_SOURCE: - case CECOP_REPORT_PHYSICAL_ADDRESS: - case CECOP_ROUTING_CHANGE: - case CECOP_ROUTING_INFORMATION: - case CECOP_SET_STREAM_PATH: - case CECOP_SET_MENU_LANGUAGE: - case CECOP_DEVICE_VENDOR_ID: - break; - - case CECOP_ABORT: - break; - default: - /*CecSendFeatureAbort(pcpi, CECAR_UNRECOG_OPCODE);*/ - break; - } - } else { - /* Respond to broadcast messages. */ - switch (pcpi->opcode) { - case CECOP_STANDBY: - /* Setting this here will let the main task know */ - /* (via SI_CecGetPowerState) and at the same time */ - /* prevent us from broadcasting a STANDBY message */ - /* of our own when the main task responds by */ - /* calling SI_CecSetPowerState( STANDBY ); */ - cec_dev->powerstatus = CEC_POWERSTATUS_STANDBY; - input_event(devinput, EV_KEY, KEY_POWER, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_POWER, 0); - input_sync(devinput); - break; - - case CECOP_ACTIVE_SOURCE: - /*CecHandleActiveSource( pcpi );*/ - break; - - case CECOP_REPORT_PHYSICAL_ADDRESS: - /*CecHandleReportPhysicalAddress( pcpi );*/ - cecframe.srcdestaddr = - MAKE_SRCDEST(cec_dev->address_logic, - CEC_LOGADDR_UNREGORBC); - cecframe.opcode = CECOP_CEC_VERSION; - cecframe.args[0] = 0x05; /* CEC1.4b*/ - cecframe.argcount = 1; - cecsendframe(&cecframe); - break; - - /* Do not reply to 'Broadcast' msgs that we don't need.*/ - case CECOP_REQUEST_ACTIVE_SOURCE: - cecsendactivesource(); - break; - case CECOP_ROUTING_CHANGE: - case CECOP_ROUTING_INFORMATION: - case CECOP_SET_STREAM_PATH: - case CECOP_SET_MENU_LANGUAGE: - break; - } - } - } - - return 0; -} - -static void cecenumeration(void) -{ - char logicaddress[3] = {CEC_LOGADDR_PLAYBACK1, - CEC_LOGADDR_PLAYBACK2, - CEC_LOGADDR_PLAYBACK3}; - int i; - int trynum; - int rtvalue; - int availablecnt; - - if (!cec_dev) - return; - - for (i = 0; i < 3; i++) { - rtvalue = 0; - availablecnt = 0; - for (trynum = 0; trynum < 3; trynum++) { - rtvalue = cecsendping(logicaddress[i]); - if (rtvalue == 1) { - availablecnt++; - CECDBG("availablecnt: %d\n", availablecnt); - } - mdelay(5); - } - if (availablecnt > 1) { - cec_dev->address_logic = logicaddress[i]; - CECDBG("logic address is 0x%x\n", - cec_dev->address_logic); - break; - } - } - if (i == 3) - cec_dev->address_logic = CEC_LOGADDR_UNREGORBC; - cec_dev->setceclogicaddr(cec_dev->hdmi, cec_dev->address_logic); - cecsendimageview(); - cecsendactivesource(); -} - static void cecworkfunc(struct work_struct *work) { struct cec_delayed_work *cec_w = container_of(work, struct cec_delayed_work, work.work); - struct cec_framedata cecframe; + struct cecframelist *list_node; switch (cec_w->event) { case EVENT_ENUMERATE: - cecenumeration(); break; case EVENT_RX_FRAME: - memset(&cecframe, 0, sizeof(struct cec_framedata)); - cecreadframe(&cecframe); - cecrxmsghandlerlast(&cecframe); + list_node = kmalloc(sizeof(*list_node), GFP_KERNEL); + if (list_node == NULL) { + pr_err("HDMI CEC: list kmalloc fail! "); + return; + } + cecreadframe(&list_node->cecframe); + if (cec_dev->enable) { + mutex_lock(&cec_dev->cec_lock); + list_add_tail(&(list_node->framelist), + &cec_dev->ceclist); + sysfs_notify(&cec_dev->device.this_device->kobj, + NULL, "stat"); + mutex_unlock(&cec_dev->cec_lock); + } else { + kfree(list_node); + } break; default: break; @@ -471,112 +88,155 @@ void rockchip_hdmi_cec_submit_work(int event, int delay, void *data) void rockchip_hdmi_cec_set_pa(int devpa) { - if (cec_dev) + struct list_head *pos, *n; + + if (cec_dev) { cec_dev->address_phy = devpa; - cecenumeration(); + pr_info("%s %x\n", __func__, devpa); + /*when hdmi hpd , ceclist will be reset*/ + mutex_lock(&cec_dev->cec_lock); + if (!list_empty(&cec_dev->ceclist)) { + list_for_each_safe(pos, n, &cec_dev->ceclist) { + list_del(pos); + kfree(pos); + } + } + INIT_LIST_HEAD(&cec_dev->ceclist); + sysfs_notify(&cec_dev->device.this_device->kobj, NULL, "stat"); + mutex_unlock(&cec_dev->cec_lock); + } } -static int cec_input_device_init(void) +static ssize_t cec_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) { - int err, i; + return snprintf(buf, PAGE_SIZE, "%d\n", cec_dev->enable); +} - devinput = input_allocate_device(); - if (!devinput) - return -ENOMEM; - devinput->name = "hdmi_cec_key"; - /*devinput->dev.parent = &client->dev;*/ - devinput->phys = "hdmi_cec_key/input0"; - devinput->id.bustype = BUS_HOST; - devinput->id.vendor = 0x0001; - devinput->id.product = 0x0001; - devinput->id.version = 0x0100; - err = input_register_device(devinput); - if (err < 0) { - input_free_device(devinput); - CECDBG("%s input device error", __func__); - return err; - } - for (i = 0; i < (sizeof(key_table)/sizeof(int)); i++) - input_set_capability(devinput, EV_KEY, key_table[i]); - return 0; +static ssize_t cec_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + ret = kstrtoint(buf, 0, &(cec_dev->enable)); + return count; } -static void cecmenucontrol(int uitemp) +static ssize_t cec_phy_show(struct device *dev, + struct device_attribute *attr, char *buf) { - switch (uitemp) { - case S_CEC_MAKESURE: /*make sure*/ - CECDBG("CEC UIcommand makesure\n"); - input_event(devinput, EV_KEY, KEY_REPLY, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_REPLY, 0); - input_sync(devinput); - break; - case S_CEC_UP: /*up*/ - CECDBG("CEC UIcommand up\n"); - input_event(devinput, EV_KEY, KEY_UP, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_UP, 0); - input_sync(devinput); - break; - case S_CEC_DOWN: /*down*/ - CECDBG("CEC UIcommand down\n"); - input_event(devinput, EV_KEY, KEY_DOWN, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_DOWN, 0); - input_sync(devinput); - break; - case S_CEC_LEFT: /*left*/ - CECDBG("CEC UIcommand left\n"); - input_event(devinput, EV_KEY, KEY_LEFT , 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_LEFT , 0); - input_sync(devinput); - break; - case S_CEC_RIGHT: /*right*/ - CECDBG("CEC UIcommand right\n"); - input_event(devinput, EV_KEY, KEY_RIGHT, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_RIGHT, 0); - input_sync(devinput); - break; - case S_CEC_BACK: /*back*/ - CECDBG("CEC UIcommand back\n"); - input_event(devinput, EV_KEY, KEY_BACK, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_BACK, 0); - input_sync(devinput); - break; - case S_CEC_VENDORBACK: - CECDBG("CEC UIcommand vendor back\n"); - input_event(devinput, EV_KEY, KEY_BACK, 1); - input_sync(devinput); - input_event(devinput, EV_KEY, KEY_BACK, 0); - input_sync(devinput); - break; - } + return snprintf(buf, PAGE_SIZE, "0x%x\n", cec_dev->address_phy); } +static ssize_t cec_phy_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + ret = kstrtoint(buf, 0, &(cec_dev->address_phy)); + return count; +} -static ssize_t cec_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t cec_logic_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%s\n", cec_dev->cecval); + return snprintf(buf, PAGE_SIZE, "0x%02x\n", cec_dev->address_logic); } -static ssize_t cec_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t cec_logic_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + + ret = kstrtoint(buf, 0, &(cec_dev->address_logic)); + return count; +} + +static ssize_t cec_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int stat; + + mutex_lock(&cec_dev->cec_lock); + if (!cec_dev->address_phy) + stat = 0; + else if (list_empty(&cec_dev->ceclist)) + stat = 1; + else + stat = 2; + mutex_unlock(&cec_dev->cec_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", stat); +} + +static struct device_attribute cec_attrs[] = { + __ATTR(logic, 0666, cec_logic_show, cec_logic_store), + __ATTR(phy, 0666, cec_phy_show, cec_phy_store), + __ATTR(enable, 0666, cec_enable_show, cec_enable_store), + __ATTR(stat, S_IRUGO, cec_state_show, NULL), +}; + +static long cec_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; + void __user *argp; + struct cec_framedata cecsendtemp; + struct cecframelist *listemp; + + argp = (void __user *)arg; + switch (cmd) { + case HDMI_IOCTL_CECSETLA: + ret = copy_from_user(&cec_dev->address_logic, + argp, sizeof(int)); + if (cec_dev->setceclogicaddr) + cec_dev->setceclogicaddr(cec_dev->hdmi, + cec_dev->address_logic); + break; + case HDMI_IOCTL_CECSEND: + ret = copy_from_user(&cecsendtemp, argp, + sizeof(struct cec_framedata)); + ret = cecsendframe(&cecsendtemp); + cecsendtemp.returnval = ret; + ret = copy_to_user(argp, &cecsendtemp, + sizeof(struct cec_framedata)); + break; + case HDMI_IOCTL_CECENAB: + ret = copy_from_user(&cec_dev->enable, argp, sizeof(int)); + break; + case HDMI_IOCTL_CECPHY: + ret = copy_to_user(argp, &(cec_dev->address_phy), sizeof(int)); + break; + case HDMI_IOCTL_CECLOGIC: + ret = copy_to_user(argp, &(cec_dev->address_logic), + sizeof(int)); + break; + case HDMI_IOCTL_CECREAD: + mutex_lock(&cec_dev->cec_lock); + if (!list_empty(&cec_dev->ceclist)) { + listemp = list_entry(cec_dev->ceclist.next, + struct cecframelist, framelist); + ret = copy_to_user(argp, &listemp->cecframe, + sizeof(struct cec_framedata)); + list_del(&listemp->framelist); + kfree(listemp); + } + mutex_unlock(&cec_dev->cec_lock); + break; + case HDMI_IOCTL_CECCLEARLA: + break; - ret = sscanf(buf, "%s", cec_dev->cecval); - return strnlen(buf, PAGE_SIZE); + default: + break; + } + return 0; } -static struct device_attribute cec_control_attr = { - .attr = {.name = "cec", .mode = 0666}, - .show = cec_show, - .store = cec_store, +static const struct file_operations cec_fops = { + .owner = THIS_MODULE, + .compat_ioctl = cec_ioctl, + .unlocked_ioctl = cec_ioctl, }; int rockchip_hdmi_cec_init(struct hdmi *hdmi, @@ -586,21 +246,18 @@ int rockchip_hdmi_cec_init(struct hdmi *hdmi, struct cec_framedata *), void (*setceclogicaddr)(struct hdmi *, int)) { - int ret; - static int cecmicsdevflag = 1; + int ret, i; - mdev.minor = MISC_DYNAMIC_MINOR; - mdev.name = "cec"; - mdev.mode = 0666; cec_dev = kmalloc(sizeof(*cec_dev), GFP_KERNEL); if (!cec_dev) { pr_err("HDMI CEC: kmalloc fail!"); return -ENOMEM; } memset(cec_dev, 0, sizeof(struct cec_device)); + mutex_init(&cec_dev->cec_lock); + INIT_LIST_HEAD(&cec_dev->ceclist); cec_dev->hdmi = hdmi; - cec_dev->cecval[0] = '1'; - cec_dev->cecval[1] = '\0'; + cec_dev->enable = 1; cec_dev->sendframe = sendframe; cec_dev->readframe = readframe; cec_dev->setceclogicaddr = setceclogicaddr; @@ -609,25 +266,26 @@ int rockchip_hdmi_cec_init(struct hdmi *hdmi, pr_err("HDMI CEC: create workqueue failed.\n"); return -1; } - if (cecmicsdevflag) { - cec_input_device_init(); - if (misc_register(&mdev)) { + cec_dev->device.minor = MISC_DYNAMIC_MINOR; + cec_dev->device.name = "cec"; + cec_dev->device.mode = 0666; + cec_dev->device.fops = &cec_fops; + if (misc_register(&cec_dev->device)) { pr_err("CEC: Could not add cec misc driver\n"); goto error; } - - ret = device_create_file(mdev.this_device, &cec_control_attr); - if (ret) { - pr_err("CEC: Could not add sys file enable\n"); - goto error1; - } - cecmicsdevflag = 0; + for (i = 0; i < ARRAY_SIZE(cec_attrs); i++) { + ret = device_create_file(cec_dev->device.this_device, + &cec_attrs[i]); + if (ret) { + pr_err("CEC: Could not add sys file\n"); + goto error1; + } } return 0; error1: - misc_deregister(&mdev); + misc_deregister(&cec_dev->device); error: - ret = -EINVAL; - return ret; + return -EINVAL; } diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.h b/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.h index 9847d06c7d46..4a55841a4c78 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.h +++ b/drivers/video/rockchip/hdmi/rockchip-hdmi-cec.h @@ -3,7 +3,7 @@ #include "rockchip-hdmi.h" #include - +#include enum { CEC_LOGADDR_TV = 0x00, CEC_LOGADDR_RECDEV1 = 0x01, @@ -133,7 +133,7 @@ struct cec_framedata { char opcode; char args[MAX_CMD_SIZE]; char argcount; - char nextframeargcount; + char returnval; }; struct cec_delayed_work { @@ -142,39 +142,44 @@ struct cec_delayed_work { void *data; }; +struct cecframelist { + struct list_head framelist; + struct cec_framedata cecframe; +}; + struct cec_device { struct workqueue_struct *workqueue; struct hdmi *hdmi; + struct miscdevice device; int address_phy; int address_logic; int powerstatus; - char cecval[32]; + int enable; + struct list_head ceclist; + struct mutex cec_lock; /* mutex for hdmicec operation*/ int (*sendframe)(struct hdmi *, struct cec_framedata *); int (*readframe)(struct hdmi *, struct cec_framedata *); void (*setceclogicaddr)(struct hdmi *, int); }; +#define DEBUG #ifdef DEBUG #define CECDBG(format, ...) \ pr_info(format, ## __VA_ARGS__) #else #define CECDBG(format, ...) #endif - -/*==================================== -//used for cec key control direction OK and back -====================================*/ -enum { - S_CEC_MAKESURE = 0x0, - S_CEC_UP = 0x1, - S_CEC_DOWN = 0x2, - S_CEC_LEFT = 0x3, - S_CEC_RIGHT = 0x4, - S_CEC_BACK = 0x0d, - S_CEC_VENDORBACK = 0x91, -}; - +/* for HAL ioctl*/ +#define HDMI_CEC_MAGIC 'N' +#define HDMI_IOCTL_CECSEND _IOW(HDMI_CEC_MAGIC, 0, struct cec_framedata) +#define HDMI_IOCTL_CECENAB _IOW(HDMI_CEC_MAGIC, 1, int) +#define HDMI_IOCTL_CECPHY _IOR(HDMI_CEC_MAGIC, 2, int) +#define HDMI_IOCTL_CECLOGIC _IOR(HDMI_CEC_MAGIC, 3, int) +#define HDMI_IOCTL_CECREAD _IOR(HDMI_CEC_MAGIC, 4, struct cec_framedata) +#define HDMI_IOCTL_CECSETLA _IOW(HDMI_CEC_MAGIC, 5, int) +#define HDMI_IOCTL_CECCLEARLA _IOW(HDMI_CEC_MAGIC, 6, int) +/*for HAL ioctl end*/ int rockchip_hdmi_cec_init(struct hdmi *hdmi, int (*sendframe)(struct hdmi *, struct cec_framedata *), diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c index 604d392b2885..286fdec3a998 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c @@ -255,6 +255,8 @@ static void hdmi_wq_remove(struct hdmi *hdmi) DBG("%s\n", __func__); if (hdmi->ops->remove) hdmi->ops->remove(hdmi); + if (hdmi->property->feature & SUPPORT_CEC) + rockchip_hdmi_cec_set_pa(0); if (hdmi->hotplug == HDMI_HPD_ACTIVED) { screen.type = SCREEN_HDMI; rk_fb_switch_screen(&screen, 0, hdmi->lcdc->id); diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_cec.c b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_cec.c index 60c23bbfe56b..bda139bee932 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_cec.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_cec.c @@ -29,6 +29,7 @@ static int rockchip_hdmiv2_cec_readframe(struct hdmi *hdmi, data[i] = hdmi_readl(hdmi_dev, CEC_RX_DATA0 + i); CECDBG("%02x\n", data[i]); } + frame->argcount = count - 2; hdmi_writel(hdmi_dev, CEC_LOCK, 0x0); return 0; } @@ -51,10 +52,8 @@ static int rockchip_hdmiv2_cec_sendframe(struct hdmi *hdmi, { struct hdmi_dev *hdmi_dev = hdmi->property->priv; int i, interrupt; - int retrycnt = 0; - int pingretry = 0, pingflg = 0; - CECDBG("TX srcDestAddr %02x opcode %02x ", + CECDBG("TX srcdestaddr %02x opcode %02x ", frame->srcdestaddr, frame->opcode); if (frame->argcount) { CECDBG("args:"); @@ -62,76 +61,34 @@ static int rockchip_hdmiv2_cec_sendframe(struct hdmi *hdmi, CECDBG("%02x ", frame->args[i]); } CECDBG("\n"); - while (retrycnt < 3) { - if (retrycnt) { - hdmi_msk_reg(hdmi_dev, CEC_CTRL, m_CEC_FRAME_TYPE, - v_CEC_FRAME_TYPE(0)); - } - CECDBG("reTryCnt: %d\n", retrycnt); - - if ((frame->srcdestaddr & 0x0f) == - ((frame->srcdestaddr >> 4) & 0x0f)) { - /*it is a ping command*/ - pingflg = 1; - if (pingretry >= 3) - break; - CECDBG("PingRetry: %d\n", pingretry); - - hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr); - hdmi_writel(hdmi_dev, CEC_TX_CNT, 1); - } else { - hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr); - hdmi_writel(hdmi_dev, CEC_TX_DATA0 + 1, frame->opcode); - for (i = 0; i < frame->argcount; i++) - hdmi_writel(hdmi_dev, - CEC_TX_DATA0 + 2 + i, - frame->args[i]); - hdmi_writel(hdmi_dev, CEC_TX_CNT, - frame->argcount + 2); - } - /*Start TX*/ - hdmi_msk_reg(hdmi_dev, CEC_CTRL, m_CEC_SEND, v_CEC_SEND(1)); - i = 60; - while (i--) { - usleep_range(900, 1000); - interrupt = hdmi_readl(hdmi_dev, IH_CEC_STAT0); - if (interrupt & (m_ERR_INITIATOR | m_ARB_LOST | - m_NACK | m_DONE)) { - hdmi_writel(hdmi_dev, IH_CEC_STAT0, - interrupt & (m_ERR_INITIATOR | - m_ARB_LOST | m_NACK | m_DONE)); - break; - } - } - - if ((interrupt & m_DONE)) { - if (retrycnt > 1) - hdmi_msk_reg(hdmi_dev, CEC_CTRL, - m_CEC_FRAME_TYPE, - v_CEC_FRAME_TYPE(2)); + if ((frame->srcdestaddr & 0x0f) == ((frame->srcdestaddr >> 4) & 0x0f)) { + /*it is a ping command*/ + hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr); + hdmi_writel(hdmi_dev, CEC_TX_CNT, 1); + } else { + hdmi_writel(hdmi_dev, CEC_TX_DATA0, frame->srcdestaddr); + hdmi_writel(hdmi_dev, CEC_TX_DATA0 + 1, frame->opcode); + for (i = 0; i < frame->argcount; i++) + hdmi_writel(hdmi_dev, + CEC_TX_DATA0 + 2 + i, frame->args[i]); + hdmi_writel(hdmi_dev, CEC_TX_CNT, frame->argcount + 2); + } + /*Start TX*/ + hdmi_msk_reg(hdmi_dev, CEC_CTRL, m_CEC_SEND, v_CEC_SEND(1)); + i = 400; + /* time = 2.4(ms)*(1 + 16)(head + param)*11(bit)*/ + /*11bit = start bit(4.5ms) + data bit(2.4ms) */ + while (i--) { + usleep_range(900, 1000); + interrupt = hdmi_readl(hdmi_dev, IH_CEC_STAT0); + if (interrupt & (m_ERR_INITIATOR | m_ARB_LOST | + m_NACK | m_DONE)) { + hdmi_writel(hdmi_dev, IH_CEC_STAT0, + interrupt & (m_ERR_INITIATOR | + m_ARB_LOST | m_NACK | m_DONE)); break; - } else { - retrycnt++; - } - - if (pingflg == 1) { - if (!(interrupt & (m_DONE | m_NACK))) { - pingretry++; - } else { - /*got ack or no nack, finish ping retry action*/ - if (retrycnt > 1) - hdmi_msk_reg(hdmi_dev, CEC_CTRL, - m_CEC_FRAME_TYPE, - v_CEC_FRAME_TYPE(2)); - break; - } } } - - if (retrycnt >= 3) - CECDBG("send cec frame retry timeout !\n"); - if (pingretry >= 3) - CECDBG("send cec frame pingretry timeout !\n"); CECDBG("%s interrupt 0x%02x\n", __func__, interrupt); if (interrupt & m_DONE) return 0; -- 2.34.1