Merge branch 'develop-3.10-next' of 10.10.10.29:rk/kernel into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmi-cec.c
1 #include <linux/kernel.h>
2 #include <linux/slab.h>
3 #include <linux/workqueue.h>
4 #include <linux/delay.h>
5 #include <linux/module.h>
6 #include <linux/kernel.h>
7 #include <linux/errno.h>
8 #include <linux/string.h>
9 #include <linux/miscdevice.h>
10 #include <linux/workqueue.h>
11 #include <linux/firmware.h>
12 #include "rockchip-hdmi-cec.h"
13
14 static struct cec_device *cec_dev;
15 struct input_dev *devinput;
16 static struct miscdevice mdev;
17
18 int key_table[] = {
19         KEY_UP,
20         KEY_DOWN,
21         KEY_LEFT,
22         KEY_RIGHT,
23         KEY_REPLY,
24         KEY_BACK,
25         KEY_POWER,
26 };
27
28 static void cecmenucontrol(int uitemp);
29
30 static int cecreadframe(struct cec_framedata *frame)
31 {
32         if (frame == NULL || !cec_dev || cec_dev->readframe == NULL)
33                 return -1;
34         else
35                 return cec_dev->readframe(cec_dev->hdmi, frame);
36 }
37
38 static int cecsendframe(struct cec_framedata *frame)
39 {
40         if (frame == NULL || !cec_dev || cec_dev->readframe == NULL)
41                 return -1;
42         else
43                 return cec_dev->sendframe(cec_dev->hdmi, frame);
44 }
45
46 static int cecsendping(char logicaddress)
47 {
48         struct cec_framedata cecframe;
49
50         memset(&cecframe, 0, sizeof(struct cec_framedata));
51         cecframe.srcdestaddr = logicaddress << 4 | logicaddress;
52         return cec_dev->sendframe(cec_dev->hdmi, &cecframe);
53 }
54
55 /*static int CecSendMessage (char opCode, char dest)
56 {
57         struct cec_framedata cecframe;
58
59         cecframe.opcode        = opCode;
60         cecframe.srcdestaddr   = MAKE_SRCDEST(cec_dev->address_logic, dest);
61         cecframe.argcount      = 0;
62
63         return cecsendframe(&cecframe);
64 }*/
65
66
67 /*static void CecSendFeatureAbort (struct cec_framedata *pcpi, char reason)
68 {
69         struct cec_framedata cecframe;
70
71         if ((pcpi->srcdestaddr & 0x0F) != CEC_LOGADDR_UNREGORBC) {
72                 cecframe.opcode        = CECOP_FEATURE_ABORT;
73                 cecframe.srcdestaddr   = MAKE_SRCDEST( cec_dev->address_logic,
74                                         ( pcpi->srcdestaddr & 0xF0) >> 4 );
75                 cecframe.args[0]       = pcpi->opcode;
76                 cecframe.args[1]       = reason;
77                 cecframe.argcount      = 2;
78                 cecsendframe(&cecframe);
79         }
80 }*/
81
82 static void cecsendimageview(void)
83 {
84          struct cec_framedata cecframe;
85
86          cecframe.opcode        = CECOP_IMAGE_VIEW_ON;
87          cecframe.srcdestaddr   = MAKE_SRCDEST(cec_dev->address_logic,
88                                                CEC_LOGADDR_UNREGORBC);
89          cecframe.argcount      = 0;
90          cecsendframe(&cecframe);
91 }
92
93 static void cecsendactivesource(void)
94 {
95         struct cec_framedata cecframe;
96
97         cecframe.opcode        = CECOP_ACTIVE_SOURCE;
98         cecframe.srcdestaddr   = MAKE_SRCDEST(cec_dev->address_logic,
99                                               CEC_LOGADDR_UNREGORBC);
100         cecframe.args[0]       = (cec_dev->address_phy & 0xFF00) >> 8;
101         cecframe.args[1]       = (cec_dev->address_phy & 0x00FF);
102         cecframe.argcount      = 2;
103         cecsendframe(&cecframe);
104 }
105
106 static void cechandleinactivesource(struct cec_framedata *pcpi)
107 {
108 }
109
110 static void cechandlefeatureabort(struct cec_framedata *pcpi)
111 {
112 }
113
114 static bool validatececmessage(struct cec_framedata *pcpi)
115 {
116         char parametercount = 0;
117         bool    countok = true;
118
119         /* Determine required parameter count   */
120
121         switch (pcpi->opcode) {
122         case CECOP_IMAGE_VIEW_ON:
123         case CECOP_TEXT_VIEW_ON:
124         case CECOP_STANDBY:
125         case CECOP_GIVE_PHYSICAL_ADDRESS:
126         case CECOP_GIVE_DEVICE_POWER_STATUS:
127         case CECOP_GET_MENU_LANGUAGE:
128         case CECOP_GET_CEC_VERSION:
129                 parametercount = 0;
130                 break;
131         case CECOP_REPORT_POWER_STATUS:         /* power status*/
132         case CECOP_CEC_VERSION:                 /* cec version*/
133                 parametercount = 1;
134                 break;
135         case CECOP_INACTIVE_SOURCE:             /* physical address*/
136         case CECOP_FEATURE_ABORT:
137         case CECOP_ACTIVE_SOURCE:               /* physical address*/
138                 parametercount = 2;
139                 break;
140         case CECOP_REPORT_PHYSICAL_ADDRESS:
141         case CECOP_DEVICE_VENDOR_ID:            /* vendor id*/
142                 parametercount = 3;
143                 break;
144         case CECOP_SET_OSD_NAME:                /* osd name (1-14 bytes)*/
145         case CECOP_SET_OSD_STRING:
146                 parametercount = 1;    /* must have a minimum of 1 operands*/
147                 break;
148         case CECOP_ABORT:
149                 break;
150         case CECOP_ARC_INITIATE:
151                 break;
152         case CECOP_ARC_REPORT_INITIATED:
153                 break;
154         case CECOP_ARC_REPORT_TERMINATED:
155                 break;
156         case CECOP_ARC_REQUEST_INITIATION:
157                 break;
158         case CECOP_ARC_REQUEST_TERMINATION:
159                 break;
160         case CECOP_ARC_TERMINATE:
161                 break;
162         default:
163                 break;
164         }
165
166         /* Test for correct parameter count.    */
167
168         if (pcpi->argcount < parametercount)
169                 countok = false;
170
171         return countok;
172 }
173
174 static bool cecrxmsghandlerlast(struct cec_framedata *pcpi)
175 {
176         bool                    isdirectaddressed;
177         struct cec_framedata    cecframe;
178
179         isdirectaddressed = !((pcpi->srcdestaddr & 0x0F) ==
180                               CEC_LOGADDR_UNREGORBC);
181         pr_info("isDirectAddressed %d\n", (int)isdirectaddressed);
182         if (validatececmessage(pcpi)) {
183                 /* If invalid message, ignore it, but treat it as handled */
184         if (isdirectaddressed) {
185                 switch (pcpi->opcode) {
186                 case CECOP_USER_CONTROL_PRESSED:
187                         cecmenucontrol(pcpi->args[0]);
188                         break;
189
190                 case CECOP_VENDOR_REMOTE_BUTTON_DOWN:
191                         cecmenucontrol(pcpi->args[0]);
192                         break;
193                 case CECOP_FEATURE_ABORT:
194                         cechandlefeatureabort(pcpi);
195                         break;
196
197                 case CECOP_GIVE_OSD_NAME:
198                         cecframe.opcode        = CECOP_SET_OSD_NAME;
199                         cecframe.srcdestaddr =
200                                 MAKE_SRCDEST(cec_dev->address_logic,
201                                              CEC_LOGADDR_TV);
202                         cecframe.args[0]  = 'r';
203                         cecframe.args[1]  = 'k';
204                         cecframe.args[2]  = '-';
205                         cecframe.args[3]  = 'b';
206                         cecframe.args[4]  = 'o';
207                         cecframe.args[5]  = 'x';
208                         cecframe.argcount      = 6;
209                         cecsendframe(&cecframe);
210                         break;
211
212                 case CECOP_VENDOR_COMMAND_WITH_ID:
213
214                 if (pcpi->args[2] == 00) {
215                         cecframe.opcode        = CECOP_SET_OSD_NAME;
216                         cecframe.srcdestaddr =
217                                 MAKE_SRCDEST(cec_dev->address_logic,
218                                              CEC_LOGADDR_TV);
219                         cecframe.args[0]  = '1';
220                         cecframe.args[1]  = '1';
221                         cecframe.args[2]  = '1';
222                         cecframe.args[3]  = '1';
223                         cecframe.args[4]  = '1';
224                         cecframe.args[5]  = '1';
225                         cecframe.argcount      = 6;
226                         cecsendframe(&cecframe);
227                         }
228                         break;
229                 case CECOP_IMAGE_VIEW_ON:
230                 case CECOP_TEXT_VIEW_ON:
231                 /* In our case, respond the same to both these messages*/
232                     break;
233
234                 case CECOP_GIVE_DEVICE_VENDOR_ID:
235                         cecframe.opcode        = CECOP_DEVICE_VENDOR_ID;
236                         cecframe.srcdestaddr   =
237                                 MAKE_SRCDEST(cec_dev->address_logic,
238                                              CEC_LOGADDR_UNREGORBC);
239                         cecframe.args[0]       = 0x1;
240                         cecframe.args[1]       = 0x2;
241                         cecframe.args[2]       = 0x3;
242                         cecframe.argcount      = 3;
243                         cecsendframe(&cecframe);
244                         break;
245
246                 case CECOP_STANDBY:             /* Direct and Broadcast*/
247                 /* Setting this here will let the main task know    */
248                 /* (via SI_CecGetPowerState) and at the same time   */
249                 /* prevent us from broadcasting a STANDBY message   */
250                 /* of our own when the main task responds by        */
251                 /* calling SI_CecSetPowerState( STANDBY );          */
252                         cec_dev->powerstatus = CEC_POWERSTATUS_STANDBY;
253                         break;
254
255                 case CECOP_INACTIVE_SOURCE:
256                         cechandleinactivesource(pcpi);
257                         break;
258
259                 case CECOP_GIVE_PHYSICAL_ADDRESS:
260
261                         cecframe.opcode        = CECOP_REPORT_PHYSICAL_ADDRESS;
262                         cecframe.srcdestaddr   =
263                                 MAKE_SRCDEST(cec_dev->address_logic,
264                                              CEC_LOGADDR_UNREGORBC);
265                         cecframe.args[0]   = (cec_dev->address_phy&0xFF00)>>8;
266                         cecframe.args[1]       = (cec_dev->address_phy&0x00FF);
267                         cecframe.args[2]       = cec_dev->address_logic;
268                         cecframe.argcount      = 3;
269                         cecsendframe(&cecframe);
270                         break;
271
272                 case CECOP_GIVE_DEVICE_POWER_STATUS:
273                 /* TV responds with power status.   */
274
275                         cecframe.opcode        = CECOP_REPORT_POWER_STATUS;
276                         cecframe.srcdestaddr   =
277                                 MAKE_SRCDEST(cec_dev->address_logic,
278                                              (pcpi->srcdestaddr & 0xF0) >> 4);
279                         cec_dev->powerstatus =  0x00;
280                         cecframe.args[0]       = cec_dev->powerstatus;
281                         cecframe.argcount      = 1;
282                         cecsendframe(&cecframe);
283                         break;
284
285                 case CECOP_GET_MENU_LANGUAGE:
286                 /* TV Responds with a Set Menu language command.    */
287
288                         cecframe.opcode         = CECOP_SET_MENU_LANGUAGE;
289                         cecframe.srcdestaddr    =
290                                 MAKE_SRCDEST(cec_dev->address_logic,
291                                              CEC_LOGADDR_UNREGORBC);
292                         cecframe.args[0]        = 'e';
293                         cecframe.args[1]        = 'n';
294                         cecframe.args[2]        = 'g';
295                         cecframe.argcount       = 3;
296                         cecsendframe(&cecframe);
297                         break;
298
299                 case CECOP_GET_CEC_VERSION:
300                 /* TV responds to this request with it's CEC version support.*/
301
302                         cecframe.srcdestaddr   =
303                                 MAKE_SRCDEST(cec_dev->address_logic,
304                                              CEC_LOGADDR_TV);
305                         cecframe.opcode        = CECOP_CEC_VERSION;
306                         cecframe.args[0]       = 0x05;       /* Report CEC1.4b*/
307                         cecframe.argcount      = 1;
308                         cecsendframe(&cecframe);
309                         break;
310
311                 case CECOP_REPORT_POWER_STATUS:
312                 /*Someone sent us their power state.
313
314                         l_sourcePowerStatus = pcpi->args[0];
315
316                         let NEW SOURCE task know about it.
317
318                         if ( l_cecTaskState.task == SI_CECTASK_NEWSOURCE )
319                         {
320                         l_cecTaskState.cpiState = CPI_RESPONSE;
321                         }*/
322                          break;
323
324                 /* Do not reply to directly addressed 'Broadcast' msgs.  */
325                 case CECOP_REQUEST_ACTIVE_SOURCE:
326                         cecsendactivesource();
327                         break;
328
329                 case CECOP_ACTIVE_SOURCE:
330                 case CECOP_REPORT_PHYSICAL_ADDRESS:
331                 case CECOP_ROUTING_CHANGE:
332                 case CECOP_ROUTING_INFORMATION:
333                 case CECOP_SET_STREAM_PATH:
334                 case CECOP_SET_MENU_LANGUAGE:
335                 case CECOP_DEVICE_VENDOR_ID:
336                         break;
337
338                 case CECOP_ABORT:
339                         break;
340                 default:
341                 /*CecSendFeatureAbort(pcpi, CECAR_UNRECOG_OPCODE);*/
342                         break;
343                         }
344                 } else {
345                         /* Respond to broadcast messages.   */
346                         switch (pcpi->opcode) {
347                         case CECOP_STANDBY:
348                         /* Setting this here will let the main task know    */
349                         /* (via SI_CecGetPowerState) and at the same time   */
350                         /* prevent us from broadcasting a STANDBY message   */
351                         /* of our own when the main task responds by        */
352                         /* calling SI_CecSetPowerState( STANDBY );          */
353                                 cec_dev->powerstatus = CEC_POWERSTATUS_STANDBY;
354                                 input_event(devinput, EV_KEY, KEY_POWER, 1);
355                                 input_sync(devinput);
356                                 input_event(devinput, EV_KEY, KEY_POWER, 0);
357                                 input_sync(devinput);
358                                 break;
359
360                         case CECOP_ACTIVE_SOURCE:
361                                 /*CecHandleActiveSource( pcpi );*/
362                                 break;
363
364                         case CECOP_REPORT_PHYSICAL_ADDRESS:
365                                 /*CecHandleReportPhysicalAddress( pcpi );*/
366                                 cecframe.srcdestaddr   =
367                                         MAKE_SRCDEST(cec_dev->address_logic,
368                                                      CEC_LOGADDR_UNREGORBC);
369                                 cecframe.opcode        = CECOP_CEC_VERSION;
370                                 cecframe.args[0]       = 0x05; /* CEC1.4b*/
371                                 cecframe.argcount      = 1;
372                                 cecsendframe(&cecframe);
373                                 break;
374
375                 /* Do not reply to 'Broadcast' msgs that we don't need.*/
376                         case CECOP_REQUEST_ACTIVE_SOURCE:
377                                 cecsendactivesource();
378                                 break;
379                         case CECOP_ROUTING_CHANGE:
380                         case CECOP_ROUTING_INFORMATION:
381                         case CECOP_SET_STREAM_PATH:
382                         case CECOP_SET_MENU_LANGUAGE:
383                                 break;
384                         }
385                 }
386         }
387
388         return 0;
389 }
390
391 static void cecenumeration(void)
392 {
393         char logicaddress[3] = {CEC_LOGADDR_PLAYBACK1,
394                                 CEC_LOGADDR_PLAYBACK2,
395                                 CEC_LOGADDR_PLAYBACK3};
396         int i;
397
398         if (!cec_dev)
399                 return;
400
401         for (i = 0; i < 3; i++) {
402                 if (cecsendping(logicaddress[i])) {
403                         cec_dev->address_logic = logicaddress[i];
404                         CECDBG("Logic Address is 0x%x\n",
405                                cec_dev->address_logic);
406                         break;
407                 }
408         }
409         if (i == 3)
410                 cec_dev->address_logic = CEC_LOGADDR_UNREGORBC;
411         cec_dev->setceclogicaddr(cec_dev->hdmi, cec_dev->address_logic);
412         cecsendimageview();
413         cecsendactivesource();
414 }
415
416 static void cecworkfunc(struct work_struct *work)
417 {
418         struct cec_delayed_work *cec_w =
419                 container_of(work, struct cec_delayed_work, work.work);
420         struct cec_framedata cecframe;
421
422         switch (cec_w->event) {
423         case EVENT_ENUMERATE:
424                 cecenumeration();
425                 break;
426         case EVENT_RX_FRAME:
427                 memset(&cecframe, 0, sizeof(struct cec_framedata));
428                 cecreadframe(&cecframe);
429                 cecrxmsghandlerlast(&cecframe);
430                 break;
431         default:
432                 break;
433         }
434
435         kfree(cec_w->data);
436         kfree(cec_w);
437 }
438
439 void rockchip_hdmi_cec_submit_work(int event, int delay, void *data)
440 {
441         struct cec_delayed_work *work;
442
443         CECDBG("%s event %04x delay %d\n", __func__, event, delay);
444
445         work = kmalloc(sizeof(*work), GFP_ATOMIC);
446
447         if (work) {
448                 INIT_DELAYED_WORK(&work->work, cecworkfunc);
449                 work->event = event;
450                 work->data = data;
451                 queue_delayed_work(cec_dev->workqueue,
452                                    &work->work,
453                                    msecs_to_jiffies(delay));
454         } else {
455                 CECDBG(KERN_WARNING "CEC: Cannot allocate memory\n");
456         }
457 }
458
459 void rockchip_hdmi_cec_set_pa(int devpa)
460 {
461         if (cec_dev)
462                 cec_dev->address_phy = devpa;
463         cecenumeration();
464 }
465
466 static int cec_input_device_init(void)
467 {
468         int err, i;
469
470         devinput = input_allocate_device();
471          if (!devinput)
472                 return -ENOMEM;
473         devinput->name = "hdmi_cec_key";
474         /*devinput->dev.parent = &client->dev;*/
475         devinput->phys = "hdmi_cec_key/input0";
476         devinput->id.bustype = BUS_HOST;
477         devinput->id.vendor = 0x0001;
478         devinput->id.product = 0x0001;
479         devinput->id.version = 0x0100;
480         err = input_register_device(devinput);
481         if (err < 0) {
482                 input_free_device(devinput);
483                 CECDBG("%s input device error", __func__);
484                 return err;
485         }
486         for (i = 0; i < (sizeof(key_table)/sizeof(int)); i++)
487                 input_set_capability(devinput, EV_KEY, key_table[i]);
488         return 0;
489 }
490
491 static void cecmenucontrol(int uitemp)
492 {
493         switch (uitemp) {
494         case S_CEC_MAKESURE:  /*make sure*/
495                 CECDBG("CEC UIcommand  makesure\n");
496                 input_event(devinput, EV_KEY, KEY_REPLY, 1);
497                 input_sync(devinput);
498                 input_event(devinput, EV_KEY, KEY_REPLY, 0);
499                 input_sync(devinput);
500                 break;
501         case S_CEC_UP:  /*up*/
502                 CECDBG("CEC UIcommand  up\n");
503                 input_event(devinput, EV_KEY, KEY_UP, 1);
504                 input_sync(devinput);
505                 input_event(devinput, EV_KEY, KEY_UP, 0);
506                 input_sync(devinput);
507                 break;
508         case S_CEC_DOWN:  /*down*/
509                 CECDBG("CEC UIcommand  down\n");
510                 input_event(devinput, EV_KEY, KEY_DOWN, 1);
511                 input_sync(devinput);
512                 input_event(devinput, EV_KEY, KEY_DOWN, 0);
513                 input_sync(devinput);
514                 break;
515         case S_CEC_LEFT:  /*left*/
516                 CECDBG("CEC UIcommand  left\n");
517                 input_event(devinput, EV_KEY, KEY_LEFT , 1);
518                 input_sync(devinput);
519                 input_event(devinput, EV_KEY, KEY_LEFT , 0);
520                 input_sync(devinput);
521                 break;
522         case S_CEC_RIGHT:  /*right*/
523                 CECDBG("CEC UIcommand  right\n");
524                 input_event(devinput, EV_KEY, KEY_RIGHT, 1);
525                 input_sync(devinput);
526                 input_event(devinput, EV_KEY, KEY_RIGHT, 0);
527                 input_sync(devinput);
528                 break;
529         case S_CEC_BACK:  /*back*/
530                 CECDBG("CEC UIcommand  back\n");
531                 input_event(devinput, EV_KEY, KEY_BACK, 1);
532                 input_sync(devinput);
533                 input_event(devinput, EV_KEY, KEY_BACK, 0);
534                 input_sync(devinput);
535                 break;
536         case S_CEC_VENDORBACK:
537                 CECDBG("CEC UIcommand  vendor back\n");
538                 input_event(devinput, EV_KEY, KEY_BACK, 1);
539                 input_sync(devinput);
540                 input_event(devinput, EV_KEY, KEY_BACK, 0);
541                 input_sync(devinput);
542                 break;
543         }
544 }
545
546
547 static ssize_t  cec_show(struct device *dev,
548                          struct device_attribute *attr, char *buf)
549 {
550         return snprintf(buf, PAGE_SIZE, "%s\n", cec_dev->cecval);
551 }
552
553 static ssize_t cec_store(struct device *dev,
554                          struct device_attribute *attr,
555                          const char *buf, size_t count)
556 {
557         int ret;
558
559         ret = sscanf(buf, "%s", cec_dev->cecval);
560         return strnlen(buf, PAGE_SIZE);
561 }
562
563 static struct device_attribute cec_control_attr = {
564         .attr = {.name = "cec", .mode = 0666},
565         .show = cec_show,
566         .store = cec_store,
567 };
568
569 int rockchip_hdmi_cec_init(struct hdmi *hdmi,
570                            int (*sendframe)(struct hdmi *,
571                                             struct cec_framedata *),
572                            int (*readframe)(struct hdmi *,
573                                             struct cec_framedata *),
574                            void (*setceclogicaddr)(struct hdmi *, int))
575 {
576         int ret;
577         static int cecmicsdevflag = 1;
578
579         mdev.minor = MISC_DYNAMIC_MINOR;
580         mdev.name = "cec";
581         mdev.mode = 0666;
582         cec_dev = kmalloc(sizeof(*cec_dev), GFP_KERNEL);
583         if (!cec_dev) {
584                 pr_err("HDMI CEC: kmalloc fail!");
585                 return -ENOMEM;
586         }
587         memset(cec_dev, 0, sizeof(struct cec_device));
588         cec_dev->hdmi = hdmi;
589         cec_dev->cecval[0] = '1';
590         cec_dev->cecval[1] = '\0';
591         cec_dev->sendframe = sendframe;
592         cec_dev->readframe = readframe;
593         cec_dev->setceclogicaddr = setceclogicaddr;
594         cec_dev->workqueue = create_singlethread_workqueue("hdmi-cec");
595         if (cec_dev->workqueue == NULL) {
596                 pr_err("HDMI CEC: create workqueue failed.\n");
597                 return -1;
598         }
599         if (cecmicsdevflag) {
600                 cec_input_device_init();
601         if (misc_register(&mdev)) {
602                 pr_err("CEC: Could not add cec misc driver\n");
603                 goto error;
604         }
605
606         ret = device_create_file(mdev.this_device, &cec_control_attr);
607         if (ret) {
608                 pr_err("CEC: Could not add sys file enable\n");
609         goto error1;
610         }
611         cecmicsdevflag = 0;
612         }
613         return 0;
614
615 error1:
616                 misc_deregister(&mdev);
617 error:
618                 ret = -EINVAL;
619         return ret;
620 }