hdmi:cec:update driver to match android HDMI CEC HAL.
authorZheng Yang <zhengyang@rock-chips.com>
Wed, 12 Aug 2015 01:10:54 +0000 (09:10 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Wed, 12 Aug 2015 01:10:54 +0000 (09:10 +0800)
Android 5.x introduce HDMI CEC, so we need to porting
cec hal and driver to make it work.

Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
drivers/video/rockchip/hdmi/rockchip-hdmi-cec.c
drivers/video/rockchip/hdmi/rockchip-hdmi-cec.h
drivers/video/rockchip/hdmi/rockchip-hdmi-core.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_cec.c

index c7457320b0c1b94dff2dcd2a1b12b7ff362c11cb..68c7bf11515289f29c72c66e448f5718bc5c2704 100644 (file)
@@ -6,30 +6,18 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/miscdevice.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
 #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;
 }
index 9847d06c7d463e2077693933601170a5f16952f6..4a55841a4c78d1ecc0247857bd4c95106ba6caca 100644 (file)
@@ -3,7 +3,7 @@
 #include "rockchip-hdmi.h"
 
 #include <linux/input.h>
-
+#include <linux/miscdevice.h>
 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 *),
index 604d392b2885776dd439334e003c264ac9e50454..286fdec3a998c5e5566026a86a07bc4a32bd5d31 100644 (file)
@@ -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);
index 60c23bbfe56b08a60ec16a941c7f7caa62c7c6db..bda139bee932da6a57dfcb864e4d83532b86821c 100644 (file)
@@ -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;