Simulate HDMI CEC by GPIO

来源:互联网 发布:matlab交易程序源码 编辑:程序博客网 时间:2024/05/21 06:19

Simulate HDMI CEC by GPIO

Use the gpio tosimulate the function of HDMI CEC.

 

分为两部分介绍:

HDMI CEC 的协议标准

Rockchip 使用GPIO 模拟CEC的软件


1,HDMI CEC的协议标准

1.1   具体的CEC标准在“HDMI1.4b  Spec”的217页.

Hdmi 1.4spec的一个下载地址:

http://download.csdn.net/download/jasonwan23/4882713

 

1.2  CEC的硬件要求

接27k ohms 上拉到3.3v。

 

1.3  CEC的bit 时序

1.3.1       Start Bit Timing


Start bit总长度4.5ms,其中低电平3.7ms,高电平0.8ms。容错时间是前后0.2ms。

 

1.3.2       Data Bit Timing



Logic“0”:Start bit总长度2.4ms,其中低电平1.5ms,高电平0.9ms。容错时间是前后0.2ms。

Logic“1”:Start bit总长度2.4ms,其中低电平0.6ms,高电平1.8ms。容错时间是前后0.2ms。

注意:

start bit、data bit0、data bit1,在上面的波形图中,高电平之后拉低。

实际当中,此拉低动作由下一码元去拉低,而非本次码元自己拉低(需要释放CEC到高电平)。

Start bit+1+0的持续的波形图如下(最后的拉低为下一码元的动作):

 

1.4  CEC的数据格式

1.4.1       Cec 数据的构成和长度

cec发送data都是由frame构成的。

每一个frame都是由startbit和一个或多个Block组成。

HeaderBlock和每个Data Block的大小都是 10 bit (8bit data + 1bit EOM + 1bit ACK)。

总长度是受限制的,最多只能传16个Block(包括HeaderBlock)。

 

1.4.2       Header/Data Block description


Header Block和每个Data Block的大小都是 10 bit (8bit data + 1bit EOM + 1bit ACK)。

高位在前,传输的时候从高位往地位开始传送。

static int GPIO_CecSendByte(char value,char EOM) { for(i = 7; i>= 0; i--)cec_send_bit((value >> i) & 0x1);cec_send_bit(EOM);returncec_read_ack(); }


1.4.3       EOM (End of Message)

logic“1”表示后面还有Block。

logic“0”表示后面没有Block。

 

1.4.4       ACK (Acknowledge)

A,定向通信(有具体某个设备的destination):

1,发送端应该set 1(NAK)

2,接收端应该set 0(ACK),表示接受成功

 

B,广播通信(destination为广播地址)

1,发送端应该set 1(NAK)

2,接收端set 0(ACK) 表示拒绝接受该广播。

3,接收端set 1(NAK) 表示接受该广播。

 

注意:

即便是发送端,在readACK阶段也需要先发送NACK(logic1)出去给接收端。

NAK logic“1”,在timing上,是0.6ms的低电平。而ACK是logic“0”,是1.5ms的低电平。

发送端在读ACK时候,先发出logic1,会先拉低0.6ms,然后再释放CEC,等待高电平,读出低电平的持续时间。

如果释放CEC的时候,由于上拉特性,应该自动回到高电平。此时读出的低电平时间是0.6ms,判断为logic1,即NAK

如果释放cec的时候,由于接收端有回应,接收端拉低,使低电平保持到1.5ms,然后才由接收端释放cec,自动回到高电平(发送端已经在0.6ms的时候释放cec)。此时读出的低电平时间是1.5ms,判断为logic0,即ACK

static int cec_read_ack(void){                structtimeval  ts_start, ts_end;                unsignedint time;                               do_gettimeofday(&ts_start);                gpio_set_value(GPIOCec.gpio,GPIO_LOW);/*EOM发送完是高电平,此时要先拉低进低电平*/                udelay(600);                gpio_direction_input(GPIOCec.gpio);/*发送端持续拉低0.6ms后释放cec,即发送logic 1*/                udelay(100);                while(gpio_get_value(GPIOCec.gpio)== 0);/*等待回到高电平*/                do_gettimeofday(&ts_end);                time= GPIO_CecComputePeriod(&ts_start, &ts_end);/*计算低电平持续时间*/                if(time> 1300 && time < 1700) {                                udelay(900);                                return0;/*延时掉logic0 后续的高电平时间*/                }                else{                                udelay(1800);                                return1; /*延时掉logic1 后续的高电平时间*/                }} 

 

1.4.5       Header Block Details


这里的initator、destination指的是发送端和接收端的逻辑地址(LA)。

 

不同类型设备的LA在spec里的定义:

   CEC_LOGADDR_TV          = 0x00,CEC_LOGADDR_PLAYBACK1   = 0x04,    // DVD1 in Spev v1.3CEC_LOGADDR_UNREGORBC   = 0x0F/*广播地址*/

填充Header Block里的LA地址:

#defineMAKE_SRCDEST( src, dest) (( src << 4) | dest )GPIOCec.address_logic = CEC_LOGADDR_PLAYBACK1;/*需要polling到可用的LA*/cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, CEC_LOGADDR_TV);

 

1.5   Logicaddress 和Physical address

PA是从电视的edid里拿出来的,LA是设备自己发message polling得到的。

PA:在edid的VSDB的第4和第5字节,PA =((data4 << 8) | data5);

 

LA :发送端将Header Block里的initator、destination都填上CEC_LOGADDR_PLAYBACK1,发出去。看看有没有收到ACK,没有收到就采用该地址作为自己的LA。如果有收到ACK,表示该LA已经被其他设备使用。改用CEC_LOGADDR_PLAYBACK2再polling。。。

 

广播地址LA: CEC_LOGADDR_UNREGORBC   = 0x0F/*广播地址*/

接收端收到广播,无需回应ACK。如果回ACK,反而表示拒绝该广播。

 

1,Gpio模拟CEC 软件

 

Github上,完整的Rockchip使用gpio模拟cec的代码:

https://github.com/virajkanwade/rk3188_android_kernel/blob/e6afb80688d7f5a3628dce8d733f653abd7f4a53/drivers/video/rockchip/hdmi/softcec/gpio-cec.c

 

 

下载下来的部分RK代码和在MTK平台上使用的部分代码:

 

2.1   软件结构

 

2.2   CEC软件在mtk平台上的修改

1.2.1       使用pinctrl操作gpio。

1.2.2       加入local_irq_disable()防止发送时候被中断打断。

1.2.3       使用udelay替代usleep_range。

1.2.4       修改部分ACK\NAK错误。

1.2.5       由于平台限制,RX的eint无法实现,RX未验证。

1.2.6      mtk平台测试  gpio-cec.c

#include <linux/kernel.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/interrupt.h>#include <linux/irq.h>//#include <mach/gpio.h>#include <linux/gpio.h>#include <linux/of_gpio.h>#include "gpio-cec.h" GPIO_Cec_t GPIOCec;static void GPIOCecWorkFunc(struct work_struct *work);static void GPIO_CecStartRead(void);static char LA_Player[3] = { CEC_LOGADDR_PLAYBACK1, CEC_LOGADDR_PLAYBACK2, CEC_LOGADDR_PLAYBACK3 };size_t hdmi_gpio_cec_log = hdmi_gpio_cec_log_all;struct platform_device *hdmitx_pdev = NULL;struct pinctrl *pinctrl;struct pinctrl_state *pins_cec_default;struct pinctrl_state *pinctrl_hdmi_dtsi_soft_cec_pin_in;struct pinctrl_state *pinctrl_hdmi_dtsi_soft_cec_pin_out_high;struct pinctrl_state *pinctrl_hdmi_dtsi_soft_cec_pin_out_low;struct pinctrl_state *pinctrl_hdmi_dtsi_sda_out_high;struct pinctrl_state *pinctrl_hdmi_dtsi_sda_out_low;struct pinctrl_state *pinctrl_hdmi_dtsi_sda;struct pinctrl_state *pinctrl_hdmi_dtsi_sda_in;struct pinctrl_state *pinctrl_hdmi_dtsi_sck_out_high;struct pinctrl_state *pinctrl_hdmi_dtsi_sck_out_low;struct pinctrl_state *pinctrl_hdmi_dtsi_sck;static inline unsigned int GPIO_CecComputePeriod(struct timeval *pre_time, struct timeval *cur_time){if(pre_time->tv_sec == 0 && pre_time->tv_usec == 0) {HDMI_GPIO_CEC_LOG_DBG("%s tv_sec == 0 && pre_time->tv_usec == 0\n", __FUNCTION__);return 0;} elsereturn (cur_time->tv_sec - pre_time->tv_sec)*1000000 + (cur_time->tv_usec - pre_time->tv_usec);}static void GPIO_CecSubmitWork(int event, int delay, void *data){struct GPIO_Cec_delayed_work *work;HDMI_GPIO_CEC_LOG_DBG("%s event %04x delay %d\n", __FUNCTION__, event, delay);work = kmalloc(sizeof(struct GPIO_Cec_delayed_work), GFP_ATOMIC);if (work) {INIT_DELAYED_WORK(&work->work, GPIOCecWorkFunc);work->event = event;work->data = data;queue_delayed_work(GPIOCec.workqueue,   &work->work,   msecs_to_jiffies(delay));} else {HDMI_GPIO_CEC_LOG_DBG("GPIO CEC: Cannot allocate memory to "    "create work\n");;}}int cpu_irq_disable_times = 0;int is_cpu_irq_disable = 0;static void cec_local_irq_enable(unsigned int enable){if (enable == 1 && cpu_irq_disable_times == 0)return;if (enable == 0) {cpu_irq_disable_times = cpu_irq_disable_times + 1;} else {cpu_irq_disable_times = cpu_irq_disable_times - 1;}if (cpu_irq_disable_times == 1 && enable == 0) {local_irq_disable();is_cpu_irq_disable = 1;} else if (cpu_irq_disable_times == 0 && enable == 1) {local_irq_enable();is_cpu_irq_disable = 0;}}#if GPIO_CEC_DISABLE_LOCAL_IRQstatic void cec_udelay(unsigned long u){cec_local_irq_enable(0);udelay(u);cec_local_irq_enable(1);}static void cec_send_bit(char bit){//struct timevalts_start, ts_end;//unsigned int time_low, time_high;if (is_cpu_irq_disable == 1) {HDMI_GPIO_CEC_LOG_DBG("[ERROR]cec_send_bit is_cpu_irq_disable=1\n");}GPIO_CecPinSet(SDA_PINCTRL_MODE_OUT_LOW);//chunhuiGPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_LOW);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_LOW);//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_LOW);//chunhuiif(bit == BIT_0)cec_udelay(BIT_0_LOWLEVEL_PERIOD_NOR);else if(bit == BIT_1)cec_udelay(BIT_1_LOWLEVEL_PERIOD_NOR);else {//do_gettimeofday(&ts_start);cec_udelay(BIT_START_LOWLEVEL_PERIOD_NOR);}//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);//chunhui//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//chunhuiif(bit == BIT_0)cec_udelay(BIT_0_HIGHLEVEL_PERIOD_NOR - BIT_0_LOWLEVEL_PERIOD_NOR);else if(bit == BIT_1)cec_udelay(BIT_1_HIGHLEVEL_PERIOD_NOR - BIT_1_LOWLEVEL_PERIOD_NOR);else {//do_gettimeofday(&ts_end);//time_low = GPIO_CecComputePeriod(&ts_start, &ts_end);//do_gettimeofday(&ts_start);cec_udelay(BIT_START_HIGHLEVEL_PERIOD_NOR - BIT_START_LOWLEVEL_PERIOD_NOR);//do_gettimeofday(&ts_end);//time_high = GPIO_CecComputePeriod(&ts_start, &ts_end);//HDMI_GPIO_CEC_LOG_DBG("START,time_low=%d,time_high=%d\n", time_low, time_high);}GPIO_CecPinSet(SDA_PINCTRL_MODE_OUT_HIGH);//chunhuiGPIO_CecPinSet(SDA_PINCTRL_MODE);//chunhui}#elsestatic void cec_send_bit(char bit){#if GPIO_CEC_USE_HRTIMERstruct timevalts_start, ts_end;unsigned int time_low, time_high;gpio_set_value(GPIOCec.gpio, GPIO_LOW);//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_LOW);//chunhuiif(bit == BIT_0)usleep_range(BIT_0_LOWLEVEL_PERIOD_MIN, BIT_0_LOWLEVEL_PERIOD_MAX);else if(bit == BIT_1)usleep_range(BIT_1_LOWLEVEL_PERIOD_MIN, BIT_1_LOWLEVEL_PERIOD_MAX);else {do_gettimeofday(&ts_start);usleep_range(BIT_START_LOWLEVEL_PERIOD_MIN, BIT_START_LOWLEVEL_PERIOD_MAX);}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//chunhuiif(bit == BIT_0)usleep_range(BIT_0_HIGHLEVEL_PERIOD_MIN - BIT_0_LOWLEVEL_PERIOD_MIN, BIT_0_HIGHLEVEL_PERIOD_MAX - BIT_0_LOWLEVEL_PERIOD_MAX);else if(bit == BIT_1)usleep_range(BIT_1_HIGHLEVEL_PERIOD_MIN - BIT_1_LOWLEVEL_PERIOD_MIN, BIT_1_HIGHLEVEL_PERIOD_MAX - BIT_1_LOWLEVEL_PERIOD_MAX);else {do_gettimeofday(&ts_end);time_low = GPIO_CecComputePeriod(&ts_start, &ts_end);do_gettimeofday(&ts_start);usleep_range(BIT_START_HIGHLEVEL_PERIOD_MIN - BIT_START_LOWLEVEL_PERIOD_MIN, BIT_START_HIGHLEVEL_PERIOD_MAX - BIT_START_LOWLEVEL_PERIOD_MAX);do_gettimeofday(&ts_end);time_high = GPIO_CecComputePeriod(&ts_start, &ts_end);HDMI_GPIO_CEC_LOG_DBG("START,time_low=%d,time_high=%d\n", time_low, time_high);}#elsestruct timeval  ts_start, ts_end;unsigned int time = 0 ,count = 0, last_time;gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if( (( bit == BIT_1) && (time > BIT_1_LOWLEVEL_PERIOD_NOR)) || (( bit == BIT_0) && (time > BIT_0_LOWLEVEL_PERIOD_NOR)) ||(( bit == BIT_START) && (time > BIT_START_LOWLEVEL_PERIOD_NOR)) ){//HDMI_GPIO_CEC_LOG_DBG(" 0 level is %d %d lasttiem %d\n", time, count, last_time);break;}}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);count = 0;while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if( (( bit == BIT_1) && (time > BIT_1_HIGHLEVEL_PERIOD_NOR)) || (( bit == BIT_0) && (time > BIT_0_HIGHLEVEL_PERIOD_NOR)) ||(( bit == BIT_START) && (time > BIT_START_HIGHLEVEL_PERIOD_NOR))){//HDMI_GPIO_CEC_LOG_DBG(" 1 level is %d %d lastime %d\n", time, count, last_time);break;}}#endif}#endif#define READ_ACK_UDELAY (BIT_1_LOWLEVEL_PERIOD_NOR)static int cec_read_ack(void){struct timeval  ts_start, ts_end;unsigned int time;int over_times = 0;///gpio_set_value(GPIOCec.gpio, GPIO_LOW);GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_LOW);//chunhuido_gettimeofday(&ts_start);//udelay(600);cec_udelay(READ_ACK_UDELAY);//GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);//chunhui///////gpio_direction_input(GPIOCec.gpio);GPIO_CecPinSet(CEC_PINCTRL_MODE_INPUT);//chunhui//udelay(250);cec_udelay(100);while(gpio_get_value(GPIOCec.gpio) == 0) {over_times ++;if (over_times >= 6000/*INT_MAX*/) {over_times = 0;//HDMI_GPIO_CEC_LOG_DBG("ack?\n");do_gettimeofday(&ts_end);time = GPIO_CecComputePeriod(&ts_start, &ts_end);if(time > 1000000) {HDMI_GPIO_CEC_LOG_DBG("ack?-----------time > 1000000\n");break;}}}do_gettimeofday(&ts_end);time = GPIO_CecComputePeriod(&ts_start, &ts_end);if(time > 850 && time < 1700) {//udelay(900);cec_udelay(900);return 0;} else if(time > 300 && time < 820) {//udelay(1800);cec_udelay(1800);return 1;} else {HDMI_GPIO_CEC_LOG_DBG("----ack error\n");HDMI_GPIO_CEC_LOG_DBG("ack low level time is %d\n", time);return 1;}}static int GPIO_CecSendByte(char value, char EOM){int i;int ack;//HDMI_GPIO_CEC_LOG_DYNAMIC("%s ,%02x, %d\n", __FUNCTION__, value, EOM);cec_local_irq_enable(0);//gpio_direction_output(GPIOCec.gpio, GPIO_HIGH);GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);//chunhui//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//chunhuifor(i = 7; i >= 0; i--) {cec_send_bit((value >> i) & 0x1);}cec_send_bit(EOM);ack = cec_read_ack();cec_local_irq_enable(1);return ack;}static int GPIO_CecSendFrame(CEC_FrameData_t *Frame){///int i, ack, trytimes = 5, isDirectAddressed = !((Frame->srcDestAddr & 0x0F ) == CEC_LOGADDR_UNREGORBC );;int i, ack, trytimes = 1, isDirectAddressed = !((Frame->srcDestAddr & 0x0F ) == CEC_LOGADDR_UNREGORBC );;HDMI_GPIO_CEC_FUNC();HDMI_GPIO_CEC_LOG_DBG("TX srcDestAddr %02x opcode %02x \n", Frame->srcDestAddr, Frame->opcode);if(Frame->argCount) {HDMI_GPIO_CEC_LOG_DBG("args:\n");for(i = 0; i < Frame->argCount; i++) {HDMI_GPIO_CEC_LOG_DBG("%02x \n", Frame->args[i]);}}HDMI_GPIO_CEC_LOG_DBG("GPIO_CecSendFrame start\n");disable_irq(GPIOCec.irq);free_irq(GPIOCec.irq, NULL);cec_local_irq_enable(0);//chunhuistart:if(trytimes == 0)goto out;trytimes--;msleep(17);//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhuicec_send_bit(BIT_START);ack = GPIO_CecSendByte(Frame->srcDestAddr, 0);if(isDirectAddressed && (ack == 1) ) {ack = ack + 0x10; goto start;}if(Frame->argCount == 0)ack = GPIO_CecSendByte(Frame->opcode, 1);elseack = GPIO_CecSendByte(Frame->opcode, 0);if(isDirectAddressed && (ack == 1) ) {ack = ack + 0x20; goto start;}for(i = 0; i < Frame->argCount; i++) {if(i == (Frame->argCount - 1))ack = GPIO_CecSendByte(Frame->args[i], 1);elseack = GPIO_CecSendByte(Frame->args[i], 0);if(isDirectAddressed && (ack == 1) ) {ack = ack + 0x30; goto start;}}out:cec_local_irq_enable(1);//chunhuiGPIO_CecStartRead();return ack;}/*Function : static int GPIO_Cec_Ping(char LA)polling the LocalAddr for self.if there was someone had this LA, the tx would receive ACK.therefor, if not an ACK, the tx could keep this LA(device type).*/static int GPIO_Cec_Ping(char LA){int ack = CEC_ACK;//, trytimes = 5;HDMI_GPIO_CEC_FUNC();HDMI_GPIO_CEC_LOG_DBG("Ping LA %02x\n", LA);disable_irq(GPIOCec.irq);free_irq(GPIOCec.irq, NULL);//gpio_direction_output(GPIOCec.gpio, GPIO_DIR_OUT);//chunhui///while(ack == CEC_ACK) {msleep(17);cec_send_bit(BIT_START);ack = GPIO_CecSendByte(LA << 4 | LA, 1);HDMI_GPIO_CEC_LOG_DBG(" ack is %d\n", ack);//trytimes--;//if(trytimes == 0) {//HDMI_GPIO_CEC_LOG_DBG("time out\n");//break;//}//}GPIO_CecStartRead();return ack;}static int CecSendMessage ( char opCode, char dest ){CEC_FrameData_t cecFrame;HDMI_GPIO_CEC_FUNC();    cecFrame.opcode        = opCode;    cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, dest );    cecFrame.argCount      = 0;    return GPIO_CecSendFrame( &cecFrame );}static void CecSendFeatureAbort ( CEC_FrameData_t *pCpi, char reason ){    CEC_FrameData_t cecFrame;HDMI_GPIO_CEC_FUNC();    if (( pCpi->srcDestAddr & 0x0F) != CEC_LOGADDR_UNREGORBC )    {        cecFrame.opcode        = CECOP_FEATURE_ABORT;        cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, (pCpi->srcDestAddr & 0xF0) >> 4 );        cecFrame.args[0]       = pCpi->opcode;        cecFrame.args[1]       = reason;        cecFrame.argCount      = 2;        GPIO_CecSendFrame( &cecFrame );    }}static int my_CecSendFeatureAbort (void){    CEC_FrameData_t cecFrame;int ret = 0;HDMI_GPIO_CEC_FUNC();        cecFrame.opcode        = CECOP_FEATURE_ABORT;        //cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, (pCpi->srcDestAddr & 0xF0) >> 4 );cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, CEC_LOGADDR_TV);cecFrame.args[0]       = CECOP_SET_MENU_LANGUAGE;        cecFrame.args[1]       = CECAR_UNRECOG_OPCODE;        cecFrame.argCount      = 2;        GPIO_CecSendFrame( &cecFrame );return ret;}static int my_CecBroadcastPhyAddr (void){    CEC_FrameData_t cecFrame;int ret = 0;HDMI_GPIO_CEC_FUNC();cecFrame.opcode    = CECOP_REPORT_PHYSICAL_ADDRESS;cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, CEC_LOGADDR_UNREGORBC );cecFrame.args[0]   = (GPIOCec.address_phy&0xFF00)>>8;  // [Physical Address]cecFrame.args[1]   = (GPIOCec.address_phy&0x00FF);   // [Physical Address]cecFrame.args[2]   = CEC_LOGADDR_PLAYBACK1;//2011.08.03 CEC_LOGADDR_TV;   // [Device Type] = 0 = TVcecFrame.argCount   = 3;ret = GPIO_CecSendFrame( &cecFrame );return ret;}static void CecHandleInactiveSource ( CEC_FrameData_t *pCpi ){//    byte la;////    la = (pCpi->srcDestAddr >> 4) & 0x0F;//    if ( la == l_activeSrcLogical )    // The active source has deserted us!//    {//        l_activeSrcLogical  = CEC_LOGADDR_TV;//        l_activeSrcPhysical = 0x0000;//    }////    l_portSelect = 0xFF;    // Tell main process to choose another port.}static void CecHandleFeatureAbort( CEC_FrameData_t *pCpi ){   }static int CecSendActiveSource(void){CEC_FrameData_t    cecFrame;HDMI_GPIO_CEC_FUNC();cecFrame.opcode        = CECOP_ACTIVE_SOURCE;cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, CEC_LOGADDR_UNREGORBC);cecFrame.args[0]       = (GPIOCec.address_phy & 0xFF00) >> 8;        // [Physical Address]cecFrame.args[1]       = (GPIOCec.address_phy & 0x00FF);             // [Physical Address]cecFrame.argCount      = 2;return GPIO_CecSendFrame( &cecFrame );}static void GPIO_StartActiveSource(void){int i;HDMI_GPIO_CEC_FUNC();// GPIO simulate CEC timing may be not correct, so we try more times.//send image view on firstfor(i = 0; i < 1; i++) {if(CecSendMessage(CECOP_IMAGE_VIEW_ON,CEC_LOGADDR_TV) == 0) {CecSendActiveSource();}}}//char my_cec_log[300] = {0};int my_CecSendMessage(int type){int ret;HDMI_GPIO_CEC_FUNC();GPIOCec.address_logic = LA_Player[0];    switch (type)    {case CECOP_IMAGE_VIEW_ON:ret = CecSendMessage(CECOP_IMAGE_VIEW_ON,CEC_LOGADDR_TV);break;//case CECOP_REPORT_PHYSICAL_ADDRESS://ret = CecSendMessage(CECOP_REPORT_PHYSICAL_ADDRESS,CEC_LOGADDR_TV);//break;case CECOP_FEATURE_ABORT:ret = my_CecSendFeatureAbort();break;case CECOP_ACTIVE_SOURCE:ret = CecSendActiveSource();break;case CECOP_REPORT_PHYSICAL_ADDRESS:ret = my_CecBroadcastPhyAddr();break;case CECOP_GIVE_PHYSICAL_ADDRESS:ret = CecSendMessage(CECOP_GIVE_PHYSICAL_ADDRESS,CEC_LOGADDR_TV);break;case CECOP_GET_CEC_VERSION:ret = CecSendMessage(CECOP_GET_CEC_VERSION,CEC_LOGADDR_TV);break;case CECOP_GET_MENU_LANGUAGE:ret = CecSendMessage(CECOP_GET_MENU_LANGUAGE,CEC_LOGADDR_TV);break;case 0xdd:ret = GPIO_Cec_Ping(CEC_LOGADDR_TV);break;default:ret = CecSendMessage(CECOP_IMAGE_VIEW_ON,CEC_LOGADDR_TV);break;    }if (ret && 0xf0) {HDMI_GPIO_CEC_LOG_DBG("ACK ret && 0xf0 %02x,ret=%x\n", (ret && 0xf0), ret);}//sprintf(my_cec_log,"ACK ret && 0xf0 %02x,ret=%x\n", (ret && 0xf0), ret);return ret;}EXPORT_SYMBOL(my_CecSendMessage);static int GPIO_Cec_Enumerate(void){int i;HDMI_GPIO_CEC_FUNC();for(i = 0; i < 3; i++) {if(GPIO_Cec_Ping(LA_Player[i]) == CEC_NAK) {GPIOCec.address_logic = LA_Player[i];break;}}if(i == 3)return -1;// Broadcast our physical address.//GPIO_CecSendMessage(CECOP_GET_MENU_LANGUAGE,CEC_LOGADDR_TV);msleep(100);GPIO_StartActiveSource();return 0;}static void GPIO_CecSendRXACK(void){disable_irq(GPIOCec.irq);free_irq(GPIOCec.irq, NULL);gpio_direction_output(GPIOCec.gpio, GPIO_LOW);udelay(1300);gpio_direction_input(GPIOCec.gpio);GPIO_CecStartRead();}static bool ValidateCecMessage ( CEC_FrameData_t *pCpi ){    char parameterCount = 0;    bool    countOK = true;    /* Determine required parameter count   */HDMI_GPIO_CEC_FUNC();    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:               // feature opcode / abort reason        case CECOP_ACTIVE_SOURCE:               // physical address            parameterCount = 2;            break;        case CECOP_REPORT_PHYSICAL_ADDRESS:     // physical address / device type        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:              // 1 + x   display control / osd string (1-13 bytes)            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;    }HDMI_GPIO_CEC_LOG_DBG("countOK=%02x\n", countOK);    return( countOK );}static bool GPIO_CecRxMsgHandlerLast ( CEC_FrameData_t *pCpi ){    boolisDirectAddressed;    CEC_FrameData_tcecFrame;HDMI_GPIO_CEC_FUNC();    isDirectAddressed = !((pCpi->srcDestAddr & 0x0F ) == CEC_LOGADDR_UNREGORBC );    if ( ValidateCecMessage( pCpi ))            // If invalid message, ignore it, but treat it as handled    {        if ( isDirectAddressed )        {        HDMI_GPIO_CEC_LOG_DBG("[hdmi GPIO_CecRxMsgHandlerLast]pCpi->opcode=%02x\n", pCpi->opcode);            switch ( pCpi->opcode )            {                case CECOP_FEATURE_ABORT:                    CecHandleFeatureAbort( pCpi );                    break;                case CECOP_IMAGE_VIEW_ON:       // In our case, respond the same to both these messages                case CECOP_TEXT_VIEW_ON:                    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 );          */                    GPIOCec.powerstatus = CEC_POWERSTATUS_STANDBY;                    break;                case CECOP_INACTIVE_SOURCE:                    CecHandleInactiveSource( pCpi );                    break;                case CECOP_GIVE_PHYSICAL_ADDRESS:                    /* TV responds by broadcasting its Physical Address: 0.0.0.0   */                    cecFrame.opcode        = CECOP_REPORT_PHYSICAL_ADDRESS;                    cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, CEC_LOGADDR_UNREGORBC );                    cecFrame.args[0]       = (GPIOCec.address_phy&0xFF00)>>8;             // [Physical Address]                    cecFrame.args[1]       = (GPIOCec.address_phy&0x00FF);             // [Physical Address]                    cecFrame.args[2]       = CEC_LOGADDR_PLAYBACK1;//2011.08.03 CEC_LOGADDR_TV;   // [Device Type] = 0 = TV                    cecFrame.argCount      = 3;                    GPIO_CecSendFrame( &cecFrame );                    break;                case CECOP_GIVE_DEVICE_POWER_STATUS:                    /* TV responds with power status.   */                    cecFrame.opcode        = CECOP_REPORT_POWER_STATUS;                    cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, (pCpi->srcDestAddr & 0xF0) >> 4 );                    cecFrame.args[0]       = GPIOCec.powerstatus;                    cecFrame.argCount      = 1;                    GPIO_CecSendFrame( &cecFrame );                    break;                case CECOP_GET_MENU_LANGUAGE:                    /* TV Responds with a Set Menu language command.    */                    cecFrame.opcode         = CECOP_SET_MENU_LANGUAGE;                    cecFrame.srcDestAddr    = CEC_LOGADDR_UNREGORBC;                    cecFrame.args[0]        = 'e';     // [language code see iso/fdis 639-2]                    cecFrame.args[1]        = 'n';     // [language code see iso/fdis 639-2]                    cecFrame.args[2]        = 'g';     // [language code see iso/fdis 639-2]                    cecFrame.argCount       = 3;                    GPIO_CecSendFrame( &cecFrame );                    break;                case CECOP_GET_CEC_VERSION:                    /* TV responds to this request with it's CEC version support.   */                    cecFrame.srcDestAddr   = MAKE_SRCDEST( GPIOCec.address_logic, (pCpi->srcDestAddr & 0xF0) >> 4 );                    cecFrame.opcode        = CECOP_CEC_VERSION;                    cecFrame.args[0]       = 0x04;       // Report CEC1.3a                    cecFrame.argCount      = 1;                    GPIO_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_ACTIVE_SOURCE:                case CECOP_REPORT_PHYSICAL_ADDRESS:     // A physical address was broadcast -- ignore it.                case CECOP_REQUEST_ACTIVE_SOURCE:       // We are not a source, so ignore this one.                case CECOP_ROUTING_CHANGE:              // We are not a downstream switch, so ignore this one.                case CECOP_ROUTING_INFORMATION:         // We are not a downstream switch, so ignore this one.                case CECOP_SET_STREAM_PATH:             // We are not a source, so ignore this one.                case CECOP_SET_MENU_LANGUAGE:           // As a TV, we can ignore this message                case CECOP_DEVICE_VENDOR_ID:                    break;                case CECOP_ABORT:       // Send Feature Abort for all unsupported features.                default:                    CecSendFeatureAbort( pCpi, CECAR_UNRECOG_OPCODE );                    break;            }        }        /* Respond to broadcast messages.   */        else        {            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 );          */                    GPIOCec.powerstatus = CEC_POWERSTATUS_STANDBY;                    break;                case CECOP_ACTIVE_SOURCE://                    CecHandleActiveSource( pCpi );                    break;                case CECOP_REPORT_PHYSICAL_ADDRESS://                    CecHandleReportPhysicalAddress( pCpi );                    break;                /* Do not reply to 'Broadcast' msgs that we don't need.  */                case CECOP_REQUEST_ACTIVE_SOURCE:       // We are not a source, so ignore this one.//                SI_StartActiveSource(0,0);//2011.08.03break;                case CECOP_ROUTING_CHANGE:              // We are not a downstream switch, so ignore this one.                case CECOP_ROUTING_INFORMATION:         // We are not a downstream switch, so ignore this one.                case CECOP_SET_STREAM_PATH:             // We are not a source, so ignore this one.                case CECOP_SET_MENU_LANGUAGE:           // As a TV, we can ignore this message                    break;            }        }    }    return 0;}static void GPIOCecWorkFunc(struct work_struct *work){struct GPIO_Cec_delayed_work *cec_w =container_of(work, struct GPIO_Cec_delayed_work, work.work);CEC_FrameData_t cecFrame;int i;HDMI_GPIO_CEC_FUNC();switch(cec_w->event){case EVENT_RX_SENDACK:GPIO_CecSendRXACK();break;case EVENT_ENUMERATE:GPIO_Cec_Enumerate();break;case EVENT_RX_FRAME:memset(&cecFrame, 0, sizeof(CEC_FrameData_t));cecFrame.srcDestAddr = GPIOCec.RxFiFo[0];HDMI_GPIO_CEC_LOG_DBG("RX srcDestAddr %02x \n", cecFrame.srcDestAddr);if(GPIOCec.RxCount > 1) {cecFrame.opcode = GPIOCec.RxFiFo[1];HDMI_GPIO_CEC_LOG_DBG("opcode %02x \n", cecFrame.opcode);cecFrame.argCount = GPIOCec.RxCount - 2;if(cecFrame.argCount) {HDMI_GPIO_CEC_LOG_DBG("args: \n");for(i = 0; i < cecFrame.argCount; i++) {cecFrame.args[i] = GPIOCec.RxFiFo[i + 2];HDMI_GPIO_CEC_LOG_DBG("%02x \n", cecFrame.args[i]);}}}HDMI_GPIO_CEC_LOG_DBG("EVENT_RX_FRAME \n");GPIO_CecRxMsgHandlerLast(&cecFrame);break;default:break;}if(cec_w->data)kfree(cec_w->data);kfree(cec_w);}#if 1static int GPIO_CecDetectBit(unsigned lowlevel, unsigned highlevel){if( lowlevel > BIT_START_LOWLEVEL_PERIOD_MIN && lowlevel < BIT_START_LOWLEVEL_PERIOD_MAX &&highlevel > BIT_START_HIGHLEVEL_PERIOD_MIN &&highlevel < BIT_START_HIGHLEVEL_PERIOD_MAX )return BIT_START;else if (lowlevel > BIT_0_LOWLEVEL_PERIOD_MIN && lowlevel < BIT_0_LOWLEVEL_PERIOD_MAX &&highlevel > BIT_0_HIGHLEVEL_PERIOD_MIN &&highlevel < BIT_0_HIGHLEVEL_PERIOD_MAX)return BIT_0;else if (lowlevel > BIT_1_LOWLEVEL_PERIOD_MIN && lowlevel < BIT_1_LOWLEVEL_PERIOD_MAX &&highlevel > BIT_1_HIGHLEVEL_PERIOD_MIN &&highlevel < BIT_1_HIGHLEVEL_PERIOD_MAX)return BIT_1;elsereturn BIT_UNKOWN;}#endif#include <mach/eint.h>#if 1static irqreturn_t GPIO_CecDetectIrq(int irq, void *dev_id){char rxbit;struct timeval  ts;unsigned int period;HDMI_GPIO_CEC_LOG_IRQ("in\n");do_gettimeofday(&ts);period = GPIO_CecComputePeriod(&GPIOCec.time_pre, &ts);if(GPIOCec.trigger == IRQF_TRIGGER_FALLING) {GPIOCec.period_highlevel = period;GPIOCec.time_pre = ts;GPIOCec.trigger = IRQF_TRIGGER_RISING;}else {GPIOCec.period_lowlevel = period;GPIOCec.trigger = IRQF_TRIGGER_FALLING;}irq_set_irq_type(GPIOCec.irq, GPIOCec.trigger);if(GPIOCec.period_highlevel && GPIOCec.period_lowlevel) {rxbit = GPIO_CecDetectBit(GPIOCec.period_lowlevel, GPIOCec.period_highlevel);HDMI_GPIO_CEC_LOG_IRQ("low %uus high %uus bit is %d\n", GPIOCec.period_lowlevel, GPIOCec.period_highlevel, rxbit);if(GPIOCec.state == RX_RECEIVING) {GPIOCec.rxbitcount++;if(GPIOCec.rxbitcount < 9) {if(rxbit == BIT_0 || rxbit == BIT_1)GPIOCec.rxdata |= rxbit << (8 - GPIOCec.rxbitcount);else {HDMI_GPIO_CEC_LOG_DBG("recevied incorrect bit %d no%d low %d high %d\n", rxbit, GPIOCec.rxbitcount, GPIOCec.period_lowlevel, GPIOCec.period_highlevel);    GPIOCec.rxdata = 0;    GPIOCec.rxbitcount = 0;    GPIOCec.state = RX_LISTENING;}}else if(GPIOCec.rxbitcount == 9) {HDMI_GPIO_CEC_LOG_IRQ("Rx Data %02x\n", GPIOCec.rxdata);GPIOCec.RxFiFo[GPIOCec.RxCount++] = GPIOCec.rxdata;GPIOCec.rxdata = 0;GPIOCec.period_lowlevel = 0;    GPIOCec.period_highlevel = 0;if((GPIOCec.RxFiFo[0] & 0x0F) == GPIOCec.address_logic) {HDMI_GPIO_CEC_LOG_IRQ("Need to Send ACK %d\n", GPIOCec.trigger);GPIO_CecSubmitWork(EVENT_RX_SENDACK, 0, NULL);//return IRQ_HANDLED;}if(rxbit == 1) {HDMI_GPIO_CEC_LOG_IRQ("it is last frame data\n");GPIOCec.state = RX_LISTENING;GPIOCec.rxbitcount = 0;GPIO_CecSubmitWork(EVENT_RX_FRAME, 0, NULL);} elseHDMI_GPIO_CEC_LOG_IRQ("there is another data later\n");}elseGPIOCec.rxbitcount = 0;}else if(rxbit == BIT_START) {GPIOCec.state = RX_RECEIVING;GPIOCec.RxCount = 0;}GPIOCec.period_highlevel = 0;GPIOCec.period_lowlevel = 0;}    return IRQ_HANDLED;}#endifstatic void GPIO_CecStartRead(void){int rc;GPIOCec.trigger = IRQF_TRIGGER_FALLING;GPIOCec.rxbitcount = 0;    GPIOCec.time_pre.tv_sec = 0;    GPIOCec.time_pre.tv_usec = 0;    GPIOCec.period_lowlevel = 0;    GPIOCec.period_highlevel = 0;GPIO_CecPinSet(CEC_PINCTRL_MODE_INPUT);//gpio_set_debounce(GPIOCec.gpio, 30);#if 1    rc = request_irq(GPIOCec.irq, GPIO_CecDetectIrq, GPIOCec.trigger, "mtk_soft_cec", NULL);if (rc < 0) {HDMI_GPIO_CEC_LOG_DBG("request_irq error\n");}#elsemt_eint_registration(18, EINTF_TRIGGER_FALLING, GPIO_CecDetectIrq, 1);#endif}void GPIO_CecEnumerate(void){HDMI_GPIO_CEC_FUNC();GPIO_CecSubmitWork(EVENT_ENUMERATE, 0, NULL);}void GPIO_CecSetDevicePA(int devPa){HDMI_GPIO_CEC_FUNC();GPIOCec.address_phy = devPa;HDMI_GPIO_CEC_LOG_DBG("devPa=%x\n", devPa);}#if 0void GPIO_CecDeviceTreeProbe(struct platform_device *pdev){struct device_node *np_softcec;np_softcec = of_find_compatible_node(NULL, NULL, "mediatek,hdmitx-softcec");hdmi_softcec_gpio_pin = of_get_named_gpio(np_softcec, "hdmi_softcec_gpio_pin", 0);hdmi_softcec_gpio_irqnum = irq_of_parse_and_map(np_softcec, 0);GPIO_CecInit(hdmi_softcec_gpio_pin, hdmi_softcec_gpio_irqnum);}void GPIO_CecPinctrl(struct platform_device *pdev){int ret = 0;struct pinctrl *pinctrl;struct pinctrl_state *pins_status;pinctrl = devm_pinctrl_get(&pdev->dev);if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);dev_err(&pdev->dev, "hdmi HPD pin, failure of setting\n");} else {pins_status = pinctrl_lookup_state(pinctrl, "hdmi_hpd");if (IS_ERR(pins_status)) {ret = PTR_ERR(pins_status);dev_err(&pdev->dev, "cannot find hdmi HPD pinctrl default");} else {pinctrl_select_state(pinctrl, pins_status);}}}#endifvoid GPIO_CecPinSet_init(void){//struct pinctrl_state *pins_cec_default;int ret = 0;struct platform_device *pdev = hdmitx_pdev;//HDMI_GPIO_CEC_LOG_DYNAMIC("GPIO_CecPinSet in, mode=%d\n", pin_mode);if(pdev == NULL) {HDMI_GPIO_CEC_LOG_DBG("hdmitx_pdev == NULL\n");return;}pinctrl = devm_pinctrl_get(&(pdev->dev));if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);HDMI_GPIO_CEC_LOG_DBG("GPIO_CecPinSet, faile of setting\n");} else {pins_cec_default = pinctrl_lookup_state(pinctrl, "default");if (IS_ERR(pins_cec_default)) {ret = PTR_ERR(pins_cec_default);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pins_cec_default");}pinctrl_hdmi_dtsi_soft_cec_pin_in = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_in");if (IS_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_in)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_in);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_soft_cec_pin_in");}pinctrl_hdmi_dtsi_soft_cec_pin_out_high = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_out_high");if (IS_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_out_high)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_out_high);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_soft_cec_pin_out_high");}pinctrl_hdmi_dtsi_soft_cec_pin_out_low = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_out_low");if (IS_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_out_low)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_soft_cec_pin_out_low);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_soft_cec_pin_out_low");}pinctrl_hdmi_dtsi_sda_out_high = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda_out_high");if (IS_ERR(pinctrl_hdmi_dtsi_sda_out_high)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sda_out_high);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sda_out_high");}pinctrl_hdmi_dtsi_sda_out_low = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda_out_low");if (IS_ERR(pinctrl_hdmi_dtsi_sda_out_low)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sda_out_low);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sda_out_low");}pinctrl_hdmi_dtsi_sda = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda");if (IS_ERR(pinctrl_hdmi_dtsi_sda)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sda);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sda");}pinctrl_hdmi_dtsi_sda_in = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda_in");if (IS_ERR(pinctrl_hdmi_dtsi_sda_in)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sda_in);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sda_in");}pinctrl_hdmi_dtsi_sck_out_high = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck_out_high");if (IS_ERR(pinctrl_hdmi_dtsi_sck_out_high)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sck_out_high);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sck_out_high");}pinctrl_hdmi_dtsi_sck_out_low = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck_out_low");if (IS_ERR(pinctrl_hdmi_dtsi_sck_out_low)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sck_out_low);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sck_out_low");}pinctrl_hdmi_dtsi_sck = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck");if (IS_ERR(pinctrl_hdmi_dtsi_sck)) {ret = PTR_ERR(pinctrl_hdmi_dtsi_sck);HDMI_GPIO_CEC_LOG_DBG("cannot find pinctrl- pinctrl_hdmi_dtsi_sck");}}}int GPIO_CecInit(int gpio, unsigned int irq_num){//int rc;static int init_times = 0;HDMI_GPIO_CEC_FUNC();init_times = init_times + 1;HDMI_GPIO_CEC_LOG_DBG("init_times=%d,gpio=%d,irq_num=%d\n", init_times, gpio, irq_num);if(gpio == -1) {HDMI_GPIO_CEC_LOG_DBG("GPIO: Invalid GPIO\n");return -1;}//rc = gpio_request(gpio, "cec gpio");//if(rc < 0) {   //     HDMI_GPIO_CEC_LOG_DBG("fail to request cec gpio\n");    //    return -1;   // }    memset(&GPIOCec, 0, sizeof(GPIO_Cec_t));    GPIOCec.workqueue = create_singlethread_workqueue("mtk_soft_cec");if (GPIOCec.workqueue == NULL) {HDMI_GPIO_CEC_LOG_DBG("GPIO CEC: create workqueue failed.\n"); return -1;}    GPIOCec.gpio = gpio;    //gpio_pull_updown(GPIOCec.gpio, PullDisable);        //GPIOCec.irq = gpio_to_irq(GPIOCec.gpio);    GPIOCec.irq = irq_num;    GPIOCec.state = RX_LISTENING;GPIO_CecPinSet_init();    GPIO_CecStartRead();     return 0;}void GPIO_Cec_enable(unsigned char u1EnCec){#ifdef MTK_HDMI_CEC_GPIO_KERNEL_DISABLE_CECHWhdmi_CECMWSetEnableCEC(0);#endif//GPIO_CecSetDevicePA();//GPIO_CecInit();}void GPIO_CecPinDefaultInit(struct platform_device *pdev){int ret = 0;struct pinctrl *pinctrl;struct pinctrl_state *pins_cec_default;HDMI_GPIO_CEC_LOG_DBG("GPIO_CecPinDefaultInit in\n");if(pdev == NULL) {HDMI_GPIO_CEC_LOG_DBG("pdev == NULL\n");return;}pinctrl = devm_pinctrl_get(&(pdev->dev));if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);dev_err(&(pdev->dev), "hdmi_dtsi_soft_cec_pin_default, failure of setting\n");} else {pins_cec_default = pinctrl_lookup_state(pinctrl, "default");if (IS_ERR(pins_cec_default)) {ret = PTR_ERR(pins_cec_default);dev_err(&(pdev->dev), "cannot find hdmi_dtsi_soft_cec_pin_default pinctrl default");} else {pinctrl_select_state(pinctrl, pins_cec_default);}}HDMI_GPIO_CEC_LOG_DBG("GPIO_CecPinDefaultInit done\n");}#if 0void GPIO_CecPinSet(int pin_mode){int ret = 0, need_enable_irq = 0;int cpu_irq_disable_times_tmp;struct pinctrl *pinctrl;struct pinctrl_state *pins_cec_default;struct platform_device *pdev = hdmitx_pdev;//HDMI_GPIO_CEC_LOG_DYNAMIC("GPIO_CecPinSet in, mode=%d\n", pin_mode);if(pdev == NULL) {HDMI_GPIO_CEC_LOG_DBG("hdmitx_pdev == NULL\n");return;}if(is_cpu_irq_disable == 1) {local_irq_enable();is_cpu_irq_disable = 0;need_enable_irq = 1;cpu_irq_disable_times_tmp = cpu_irq_disable_times;}pinctrl = devm_pinctrl_get(&(pdev->dev));if (IS_ERR(pinctrl)) {ret = PTR_ERR(pinctrl);dev_err(&(pdev->dev), "GPIO_CecPinSet, faile of setting\n");} else {switch (pin_mode) {case CEC_PINCTRL_MODE_DEF:pins_cec_default = pinctrl_lookup_state(pinctrl, "default");break;case CEC_PINCTRL_MODE_INPUT:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_in");break;case CEC_PINCTRL_MODE_OUT_HIGH:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_out_high");break;case CEC_PINCTRL_MODE_OUT_LOW:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_soft_cec_pin_out_low");break;case SDA_PINCTRL_MODE_OUT_HIGH:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda_out_high");break;case SDA_PINCTRL_MODE_OUT_LOW:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda_out_low");break;case SDA_PINCTRL_MODE:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sda");break;case SCL_PINCTRL_MODE_OUT_HIGH:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck_out_high");break;case SCL_PINCTRL_MODE_OUT_LOW:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck_out_low");break;case SCL_PINCTRL_MODE:pins_cec_default = pinctrl_lookup_state(pinctrl, "hdmi_dtsi_sck");break;default :pins_cec_default = pinctrl_lookup_state(pinctrl, "default");break;}if (IS_ERR(pins_cec_default)) {ret = PTR_ERR(pins_cec_default);dev_err(&(pdev->dev), "cannot find pinctrl");} else {pinctrl_select_state(pinctrl, pins_cec_default);}}if(need_enable_irq == 1 && is_cpu_irq_disable == 1) {cpu_irq_disable_times = cpu_irq_disable_times_tmp;local_irq_disable();is_cpu_irq_disable = 1;need_enable_irq = 0;}//HDMI_GPIO_CEC_LOG_DYNAMIC("GPIO_CecPinSet done,mode=%d\n", pin_mode);}#endifvoid GPIO_CecPinSet(int pin_mode){switch (pin_mode) {case CEC_PINCTRL_MODE_DEF:pinctrl_select_state(pinctrl, pins_cec_default);break;case CEC_PINCTRL_MODE_INPUT:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_soft_cec_pin_in);break;case CEC_PINCTRL_MODE_OUT_HIGH:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_soft_cec_pin_out_high);break;case CEC_PINCTRL_MODE_OUT_LOW:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_soft_cec_pin_out_low);break;case SDA_PINCTRL_MODE_OUT_HIGH:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sda_out_high);break;case SDA_PINCTRL_MODE_OUT_LOW:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sda_out_low);break;case SDA_PINCTRL_MODE:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sda);break;case SDA_PINCTRL_MODE_INPUT:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sda_in);break;case SCL_PINCTRL_MODE_OUT_HIGH:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sck_out_high);break;case SCL_PINCTRL_MODE_OUT_LOW:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sck_out_low);break;case SCL_PINCTRL_MODE:pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sck);break;default :pinctrl_select_state(pinctrl, pins_cec_default);pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sck);pinctrl_select_state(pinctrl, pinctrl_hdmi_dtsi_sda);break;}//HDMI_GPIO_CEC_LOG_DYNAMIC("GPIO_CecPinSet done,mode=%d\n", pin_mode);}void GPIO_CecPinGet(void){int input_val = 0;if (GPIOCec.gpio == 0) {HDMI_GPIO_CEC_LOG_DBG("GPIO_CecPinGet gpio null\n");return;}gpio_direction_input(GPIOCec.gpio);input_val = gpio_get_value(GPIOCec.gpio);HDMI_GPIO_CEC_LOG_DBG("GPIO_CecPinGet done,input_val=%d\n", input_val);}struct my_time_t{s64 last_nsecs;u64last_xtime_sec;u64last_xtime_nsec;s64 now_nsecs;u64now_xtime_sec;u64now_xtime_nsec;cycle_t last_cycle;cycle_t now_cycle;};void GPIO_CecSetLogLever(int  log_lever){hdmi_gpio_cec_log = log_lever;}EXPORT_SYMBOL(GPIO_CecSetLogLever);extern void my_do_gettimeofday(struct timeval *tv);extern struct my_time_t my_time_tmp;extern struct my_time_t my_time_tmp1;extern struct my_time_t my_time_tmp2;extern char ns_log_buf[100];char log_buf[500] = {0};#if GPIO_CEC_USE_HRTIMERchar * GPIO_CecSendBit(char bit_val){struct timevalts_start, ts_end;struct timeval tsspec_start, tsspec_end;unsigned int time;unsigned int time1=0,time1_before=0;unsigned int time2=0,time2_before=0;unsigned int my_time;int gpio_read = 0;GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);do_gettimeofday(&ts_start);my_do_gettimeofday(&tsspec_start);//local_irq_disable();cec_local_irq_enable(0);if (bit_val == 4) {gpio_set_value(GPIOCec.gpio, GPIO_LOW);//usleep_range(100, 200);udelay(200);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//usleep_range(5000, 6000);udelay(500);} else if (bit_val == 5) {/*0*///gpio_set_value(GPIOCec.gpio, GPIO_LOW);//usleep_range(1400, 1500);udelay(400);//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);//usleep_range(800, 900);//udelay(900);} else if (bit_val == 6) {/*1*/gpio_set_value(GPIOCec.gpio, GPIO_LOW);usleep_range(500, 600);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(1700, 1900);} else if (bit_val == 7) {/*0 1*/gpio_set_value(GPIOCec.gpio, GPIO_LOW);usleep_range(1400, 1600);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(800, 1000);gpio_set_value(GPIOCec.gpio, GPIO_LOW);usleep_range(500, 600);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(1700, 1900);} else if (bit_val == 8) {/*only delay*///gpio_set_value(GPIOCec.gpio, GPIO_LOW);usleep_range(1400, 1500);//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(450, 500);//gpio_set_value(GPIOCec.gpio, GPIO_LOW);usleep_range(550, 600);//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(1950, 2000);} else if (bit_val == 9) {/*only delay*/udelay(1000);udelay(500);udelay(100);udelay(400);} else if (bit_val == 10) {/*only delay*///gpio_set_value(GPIOCec.gpio, GPIO_LOW);my_do_gettimeofday(&ts_start);while(1) {my_do_gettimeofday(&ts_end);time1 = GPIO_CecComputePeriod(&ts_start, &ts_end);if(time1 > 300) { if (time1 > 400) {my_time_tmp1.last_nsecs = my_time_tmp.last_nsecs;my_time_tmp1.last_xtime_nsec = my_time_tmp.last_xtime_nsec;my_time_tmp1.last_xtime_sec = my_time_tmp.last_xtime_sec;my_time_tmp1.last_cycle = my_time_tmp.last_cycle;my_time_tmp1.now_nsecs = my_time_tmp.now_nsecs;my_time_tmp1.now_xtime_nsec = my_time_tmp.now_xtime_nsec;my_time_tmp1.now_xtime_sec = my_time_tmp.now_xtime_sec;my_time_tmp1.now_cycle = my_time_tmp.now_cycle;}break; }time1_before = time1;}//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);my_do_gettimeofday(&ts_start);while(1) {my_do_gettimeofday(&ts_end);time2 = GPIO_CecComputePeriod(&ts_start, &ts_end);if(time2 > 700) { if(time2 > 800) {my_time_tmp2.last_nsecs = my_time_tmp.last_nsecs;my_time_tmp2.last_xtime_nsec = my_time_tmp.last_xtime_nsec;my_time_tmp2.last_xtime_sec = my_time_tmp.last_xtime_sec;my_time_tmp2.last_cycle = my_time_tmp.last_cycle;my_time_tmp2.now_nsecs = my_time_tmp.now_nsecs;my_time_tmp2.now_xtime_nsec = my_time_tmp.now_xtime_nsec;my_time_tmp2.now_xtime_sec = my_time_tmp.now_xtime_sec;my_time_tmp2.now_cycle = my_time_tmp.now_cycle;}break; }time2_before = time2;}} else if (bit_val == 11) {/*only delay*/gpio_direction_input(GPIOCec.gpio);GPIO_CecPinSet(CEC_PINCTRL_MODE_INPUT);udelay(40);gpio_read = gpio_get_value(GPIOCec.gpio);udelay(400);GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);} else {cec_send_bit(bit_val);}my_do_gettimeofday(&tsspec_end);//local_irq_enable();cec_local_irq_enable(1);do_gettimeofday(&ts_end);gpio_set_value(GPIOCec.gpio, GPIO_LOW);time = GPIO_CecComputePeriod(&ts_start, &ts_end);my_time = GPIO_CecComputePeriod(&tsspec_start, &tsspec_end);usleep_range(5000, 6000);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);HDMI_GPIO_CEC_LOG_DBG("GPIO_CecSendBit,GPIO_CEC_USE_HRTIMER gpio_read=%d,%s,bit_val=%d,time=%d,time1_before=%d,time2_before=%d,time1=%d,time2=%d, my_time=%d\n,  \nmy_time_tmp1.last_nsecs=%lld,last_xtime_nsec=%llu,last_xtime_sec=%llu,last_cycle=%llu,now_nsecs=%lld,now_xtime_nsec=%llu,now_xtime_sec=%llu,now_cycle=%llu,.  \nmy_time_tmp2.last_nsecs=%lld,last_xtime_nsec=%llu,last_xtime_sec=%llu,last_cycle=%llu,now_nsecs=%lld,now_xtime_nsec=%llu,now_xtime_sec=%llu,now_cycle=%llu,\n",gpio_read,ns_log_buf, bit_val, time, time1_before, time2_before, time1, time2, my_time, my_time_tmp1.last_nsecs,my_time_tmp1.last_xtime_nsec,my_time_tmp1.last_xtime_sec,my_time_tmp1.last_cycle,my_time_tmp1.now_nsecs,my_time_tmp1.now_xtime_nsec,my_time_tmp1.now_xtime_sec,my_time_tmp1.now_cycle,  my_time_tmp2.last_nsecs,my_time_tmp2.last_xtime_nsec,my_time_tmp2.last_xtime_sec,my_time_tmp2.last_cycle,my_time_tmp2.now_nsecs,my_time_tmp2.now_xtime_nsec,my_time_tmp2.now_xtime_sec,my_time_tmp2.now_cycle);sprintf(log_buf,"GPIO_CecSendBit,GPIO_CEC_USE_HRTIMER gpio_read=%d,%s,bit_val=%d,time=%d,time1_before=%d,time2_before=%d,time1=%d,time2=%d, my_time=%d\n,  \nmy_time_tmp1.last_nsecs=%lld,last_xtime_nsec=%llu,last_xtime_sec=%llu,last_cycle=%llu,now_nsecs=%lld,now_xtime_nsec=%llu,now_xtime_sec=%llu,now_cycle=%llu,.  \nmy_time_tmp2.last_nsecs=%lld,last_xtime_nsec=%llu,last_xtime_sec=%llu,last_cycle=%llu,now_nsecs=%lld,now_xtime_nsec=%llu,now_xtime_sec=%llu,now_cycle=%llu,\n",gpio_read,ns_log_buf, bit_val, time, time1_before, time2_before, time1, time2, my_time, my_time_tmp1.last_nsecs,my_time_tmp1.last_xtime_nsec,my_time_tmp1.last_xtime_sec,my_time_tmp1.last_cycle,my_time_tmp1.now_nsecs,my_time_tmp1.now_xtime_nsec,my_time_tmp1.now_xtime_sec,my_time_tmp1.now_cycle,  my_time_tmp2.last_nsecs,my_time_tmp2.last_xtime_nsec,my_time_tmp2.last_xtime_sec,my_time_tmp2.last_cycle,my_time_tmp2.now_nsecs,my_time_tmp2.now_xtime_nsec,my_time_tmp2.now_xtime_sec,my_time_tmp2.now_cycle);return log_buf;}#elsechar * GPIO_CecSendBit(char bit_val){struct timevalts_start0 ,ts_start, ts_end;unsigned int time = 0 ,count = 0, last_time;unsigned int res_time1 = 0, res_time2 = 0, res_time3 = 0, res_time4 = 0;GPIO_CecPinSet(CEC_PINCTRL_MODE_OUT_HIGH);do_gettimeofday(&ts_start0);if (bit_val == 4) {gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 100) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);usleep_range(5000, 6000);} else if (bit_val == 5) {/*0*/gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1500) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 900) { break; }}} else if (bit_val == 6) {/*1*/gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 600) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1900) { break; }}} else if (bit_val == 7) {/*0 1*/gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1500) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 900) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 600) { break; }}gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1900) { break; }}} else if (bit_val == 8) {/*only delay*/do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1500) { res_time1 = time - 1500; break; }}//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 900) { res_time2 = time - 900; break; }}//gpio_set_value(GPIOCec.gpio, GPIO_LOW);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 600) { res_time3 = time - 600; break; }}//gpio_set_value(GPIOCec.gpio, GPIO_HIGH);do_gettimeofday(&ts_start);while(1) {do_gettimeofday(&ts_end);last_time = time;time = GPIO_CecComputePeriod(&ts_start, &ts_end);count++;if(time > 1900) { res_time4 = time - 1900; break; }}} else {cec_send_bit(bit_val);}do_gettimeofday(&ts_end);gpio_set_value(GPIOCec.gpio, GPIO_LOW);time = GPIO_CecComputePeriod(&ts_start0, &ts_end);usleep_range(5000, 6000);gpio_set_value(GPIOCec.gpio, GPIO_HIGH);HDMI_GPIO_CEC_LOG_DBG("GPIO_CecSendBit,dealy bit_val=%d,res_time [1]%d,[2]%d,[3]%d,[4]%d ,time_onebit=%d\n", bit_val, res_time1, res_time2, res_time3, res_time4, time);return log_buf;}#endif

1.2.7      mtk平台测试  gpio-cec.h

#ifndef __hdmigpiocec_h__#define __hdmigpiocec_h__#include <linux/platform_device.h>#include <linux/types.h>typedef enum{CEC_PINCTRL_MODE_DEF = 0x00,CEC_PINCTRL_MODE_INPUT,CEC_PINCTRL_MODE_OUT_HIGH,CEC_PINCTRL_MODE_OUT_LOW,SDA_PINCTRL_MODE_OUT_HIGH,SDA_PINCTRL_MODE_OUT_LOW,SDA_PINCTRL_MODE,SDA_PINCTRL_MODE_INPUT,SCL_PINCTRL_MODE_OUT_HIGH,SCL_PINCTRL_MODE_OUT_LOW,SCL_PINCTRL_MODE,CEC_PINCTRL_MODE_NUM,} CEC_PIN_CTRL_MODE_t;typedef enum{    CEC_LOGADDR_TV          = 0x00,    CEC_LOGADDR_RECDEV1     = 0x01,    CEC_LOGADDR_RECDEV2     = 0x02,    CEC_LOGADDR_TUNER1      = 0x03,     // STB1 in Spev v1.3    CEC_LOGADDR_PLAYBACK1   = 0x04,     // DVD1 in Spev v1.3    CEC_LOGADDR_AUDSYS      = 0x05,    CEC_LOGADDR_TUNER2      = 0x06,     // STB2 in Spec v1.3    CEC_LOGADDR_TUNER3      = 0x07,     // STB3 in Spec v1.3    CEC_LOGADDR_PLAYBACK2   = 0x08,     // DVD2 in Spec v1.3    CEC_LOGADDR_RECDEV3     = 0x09,    CEC_LOGADDR_TUNER4      = 0x0A,     // RES1 in Spec v1.3    CEC_LOGADDR_PLAYBACK3   = 0x0B,     // RES2 in Spec v1.3    CEC_LOGADDR_RES3        = 0x0C,    CEC_LOGADDR_RES4        = 0x0D,    CEC_LOGADDR_FREEUSE     = 0x0E,    CEC_LOGADDR_UNREGORBC   = 0x0F} CEC_LOG_ADDR_t;typedef enum                    // CEC Messages{    CECOP_FEATURE_ABORT             = 0x00,    CECOP_IMAGE_VIEW_ON             = 0x04,    CECOP_TUNER_STEP_INCREMENT      = 0x05,     // N/A    CECOP_TUNER_STEP_DECREMENT      = 0x06,     // N/A    CECOP_TUNER_DEVICE_STATUS       = 0x07,     // N/A    CECOP_GIVE_TUNER_DEVICE_STATUS  = 0x08,     // N/A    CECOP_RECORD_ON                 = 0x09,     // N/A    CECOP_RECORD_STATUS             = 0x0A,     // N/A    CECOP_RECORD_OFF                = 0x0B,     // N/A    CECOP_TEXT_VIEW_ON              = 0x0D,    CECOP_RECORD_TV_SCREEN          = 0x0F,     // N/A    CECOP_GIVE_DECK_STATUS          = 0x1A,    CECOP_DECK_STATUS               = 0x1B,    CECOP_SET_MENU_LANGUAGE         = 0x32,    CECOP_CLEAR_ANALOGUE_TIMER      = 0x33,     // Spec 1.3A    CECOP_SET_ANALOGUE_TIMER        = 0x34,     // Spec 1.3A    CECOP_TIMER_STATUS              = 0x35,     // Spec 1.3A    CECOP_STANDBY                   = 0x36,    CECOP_PLAY                      = 0x41,    CECOP_DECK_CONTROL              = 0x42,    CECOP_TIMER_CLEARED_STATUS      = 0x43,     // Spec 1.3A    CECOP_USER_CONTROL_PRESSED      = 0x44,    CECOP_USER_CONTROL_RELEASED     = 0x45,    CECOP_GIVE_OSD_NAME             = 0x46,    CECOP_SET_OSD_NAME              = 0x47,    CECOP_SET_OSD_STRING            = 0x64,    CECOP_SET_TIMER_PROGRAM_TITLE   = 0x67,     // Spec 1.3A    CECOP_SYSTEM_AUDIO_MODE_REQUEST = 0x70,     // Spec 1.3A    CECOP_GIVE_AUDIO_STATUS         = 0x71,     // Spec 1.3A    CECOP_SET_SYSTEM_AUDIO_MODE     = 0x72,     // Spec 1.3A    CECOP_REPORT_AUDIO_STATUS       = 0x7A,     // Spec 1.3A    CECOP_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D, // Spec 1.3A    CECOP_SYSTEM_AUDIO_MODE_STATUS  = 0x7E,     // Spec 1.3A    CECOP_ROUTING_CHANGE            = 0x80,    CECOP_ROUTING_INFORMATION       = 0x81,    CECOP_ACTIVE_SOURCE             = 0x82,    CECOP_GIVE_PHYSICAL_ADDRESS     = 0x83,    CECOP_REPORT_PHYSICAL_ADDRESS   = 0x84,    CECOP_REQUEST_ACTIVE_SOURCE     = 0x85,    CECOP_SET_STREAM_PATH           = 0x86,    CECOP_DEVICE_VENDOR_ID          = 0x87,    CECOP_VENDOR_COMMAND            = 0x89,    CECOP_VENDOR_REMOTE_BUTTON_DOWN = 0x8A,    CECOP_VENDOR_REMOTE_BUTTON_UP   = 0x8B,    CECOP_GIVE_DEVICE_VENDOR_ID     = 0x8C,    CECOP_MENU_REQUEST              = 0x8D,    CECOP_MENU_STATUS               = 0x8E,    CECOP_GIVE_DEVICE_POWER_STATUS  = 0x8F,    CECOP_REPORT_POWER_STATUS       = 0x90,    CECOP_GET_MENU_LANGUAGE         = 0x91,    CECOP_SELECT_ANALOGUE_SERVICE   = 0x92,     // Spec 1.3A    N/A    CECOP_SELECT_DIGITAL_SERVICE    = 0x93,     //              N/A    CECOP_SET_DIGITAL_TIMER         = 0x97,     // Spec 1.3A    CECOP_CLEAR_DIGITAL_TIMER       = 0x99,     // Spec 1.3A    CECOP_SET_AUDIO_RATE            = 0x9A,     // Spec 1.3A    CECOP_INACTIVE_SOURCE           = 0x9D,     // Spec 1.3A    CECOP_CEC_VERSION               = 0x9E,     // Spec 1.3A    CECOP_GET_CEC_VERSION           = 0x9F,     // Spec 1.3A    CECOP_VENDOR_COMMAND_WITH_ID    = 0xA0,     // Spec 1.3A    CECOP_CLEAR_EXTERNAL_TIMER      = 0xA1,     // Spec 1.3A    CECOP_SET_EXTERNAL_TIMER        = 0xA2,     // Spec 1.3A    CDCOP_HEADER                    = 0xF8,    CECOP_ABORT                     = 0xFF,    CECOP_REPORT_SHORT_AUDIO    = 0xA3,     // Spec 1.4    CECOP_REQUEST_SHORT_AUDIO    = 0xA4,     // Spec 1.4    CECOP_ARC_INITIATE              = 0xC0,    CECOP_ARC_REPORT_INITIATED      = 0xC1,    CECOP_ARC_REPORT_TERMINATED     = 0xC2,    CECOP_ARC_REQUEST_INITIATION    = 0xC3,    CECOP_ARC_REQUEST_TERMINATION   = 0xC4,    CECOP_ARC_TERMINATE             = 0xC5,      } CEC_OPCODE_t;typedef enum                        // Operands for <Feature Abort> Opcode{    CECAR_UNRECOG_OPCODE            = 0x00,    CECAR_NOT_CORRECT_MODE,    CECAR_CANT_PROVIDE_SOURCE,    CECAR_INVALID_OPERAND,    CECAR_REFUSED} CEC_ABORT_REASON_t;    enum                        // Operands for <Power Status> Opcode{    CEC_POWERSTATUS_ON              = 0x00,    CEC_POWERSTATUS_STANDBY         = 0x01,    CEC_POWERSTATUS_STANDBY_TO_ON   = 0x02,    CEC_POWERSTATUS_ON_TO_STANDBY   = 0x03,};    enum {BIT_UNKOWN = -1,BIT_0 = 0,BIT_1 = 1,BIT_START = 2,};enum {RX_LISTENING = 0,RX_RECEIVING = 1,RX_ACKNEEDED = 2,};enum {EVENT_RX_SENDACK,EVENT_RX_FRAME,EVENT_ENUMERATE,TASK_TX,};#define BIT_START_LOWLEVEL_PERIOD_MIN3500#define BIT_START_LOWLEVEL_PERIOD_NOR3700#define BIT_START_LOWLEVEL_PERIOD_MAX3900#define BIT_START_HIGHLEVEL_PERIOD_MIN4300#define BIT_START_HIGHLEVEL_PERIOD_NOR4500#define BIT_START_HIGHLEVEL_PERIOD_MAX4700#define BIT_0_LOWLEVEL_PERIOD_MIN1300#define BIT_0_LOWLEVEL_PERIOD_NOR1500#define BIT_0_LOWLEVEL_PERIOD_MAX1700#define BIT_0_HIGHLEVEL_PERIOD_MIN2050#define BIT_0_HIGHLEVEL_PERIOD_NOR2400#define BIT_0_HIGHLEVEL_PERIOD_MAX2750#define BIT_1_LOWLEVEL_PERIOD_MIN400#define BIT_1_LOWLEVEL_PERIOD_NOR600#define BIT_1_LOWLEVEL_PERIOD_MAX800#define BIT_1_HIGHLEVEL_PERIOD_MIN2050#define BIT_1_HIGHLEVEL_PERIOD_NOR2400#define BIT_1_HIGHLEVEL_PERIOD_MAX2750#define GPIO_CEC_USE_HRTIMER (1)#define GPIO_CEC_DISABLE_LOCAL_IRQ (1)#ifndef GPIO_HIGH#define GPIO_HIGH (1)#endif#ifndef GPIO_LOW#define GPIO_LOW (0)#endif#ifndef PullDisable#define PullDisable (0)#endif#ifndef CEC_NAK//#define CEC_NAK (1)#define CEC_NAK (0)#define CEC_ACK(!CEC_NAK)#endif#ifndef INT_MAX#define INT_MAX ((int)(~0U>>1))#endif#define MAKE_SRCDEST( src, dest)    (( src << 4) | dest )#define MAX_CMD_SIZE 16typedef struct{    char srcDestAddr;            // Source in upper nybble, dest in lower nybble    char opcode;    char args[ MAX_CMD_SIZE ];    char argCount;   char nextFrameArgCount;} CEC_FrameData_t;struct GPIO_Cec_delayed_work {struct delayed_work work;int event;void *data;};typedef struct{int gpio;int irq;int trigger;struct workqueue_struct *workqueue;struct timeval  time_pre;unsigned int period_lowlevel;unsigned int period_highlevel;char rxdata;int rxbitcount;char RxFiFo[MAX_CMD_SIZE + 2];int  RxCount;int state;int task;int address_phy;int address_logic;int powerstatus;} GPIO_Cec_t;#ifndef DEBUG#define DEBUG#endif#define hdmi_gpio_cec_log_irq(0x01)#define hdmi_gpio_cec_log_dbg(0x02)#define hdmi_gpio_cec_log_dynamic (0x04)#define hdmi_gpio_cec_log_all (hdmi_gpio_cec_log_dbg | hdmi_gpio_cec_log_irq)extern size_t hdmi_gpio_cec_log;#define HDMI_GPIO_CEC_FUNC()\    do { \        if (1) {printk("[HDMI_GPIO_CEC] %s\n", __func__); } \    } while (0)#define HDMI_GPIO_CEC_LOG_IRQ(fmt, arg...) \do { \if (hdmi_gpio_cec_log & hdmi_gpio_cec_log_irq) \printk("[HDMI_GPIO_CEC_IRQ]"); printk(fmt, ##arg); \} while (0)#define HDMI_GPIO_CEC_LOG_DBG(fmt, arg...) \do { \if (hdmi_gpio_cec_log & hdmi_gpio_cec_log_dbg) \printk("[HDMI_GPIO_CEC_DBG]"); printk(fmt, ##arg); \} while (0)#define HDMI_GPIO_CEC_LOG_DYNAMIC(fmt, arg...) \do { \if (hdmi_gpio_cec_log & hdmi_gpio_cec_log_dynamic) \printk("[HDMI_GPIO_CEC_LOG_DYNAMIC]"); printk(fmt, ##arg); \} while (0)#ifdef DEBUG#define CECDBG(format, ...) \printk(KERN_INFO format, ## __VA_ARGS__)#else#define CECDBG(format, ...)#endifextern void GPIO_CecEnumerate(void);extern void GPIO_CecSetDevicePA(int devPa);extern int GPIO_CecInit(int gpio, unsigned int irq_num);extern void GPIO_Cec_enable(unsigned char u1EnCec);extern void GPIO_CecPinDefaultInit(struct platform_device *pdev);extern void GPIO_CecPinSet(int pin_mode);extern void GPIO_CecPinGet(void);extern char * GPIO_CecSendBit(char bit_val);extern  GPIO_Cec_t GPIOCec;extern int hdmi_softcec_gpio_pin;extern unsigned int hdmi_softcec_gpio_irqnum;extern struct platform_device *hdmitx_pdev;#endif

1.2.8      mtk平台测试 Makefile

## Makefile for RockChip Soft CEC##obj-$(CONFIG_MTK_HDMI_SOFT_CEC) += gpio-cec.oinclude $(srctree)/drivers/misc/mediatek/Makefile.customobj-y += gpio-cec.o



0 0
原创粉丝点击