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
- Simulate HDMI CEC by GPIO
- HDMI 之 CEC
- HDMI之CEC通道
- HDMI CEC HDCP
- HDMI之CEC通道
- HDMI之CEC通道
- HDMI中的CEC
- HDMI-CEC Control Service
- HDMI的CEC功能
- HDMI-CEC 控制服务
- Android HDMI CEC控制服务
- HDMI 接口及CEC信号
- gpio simulate i2c
- HDMI-CEC Control Service (Android TV 二)
- Android Tv HDMI-CEC框架层移植
- HDMI-CEC 在LG电视上的研究
- HDMI的cec功能——借CEC信号让使用者可控制HDMI接口上所连接的装置
- How to simulate a Form POST request by using WinInet
- 超级简单的方法,也不用写什么判断浏览器高度、宽度啥的。
- opencv相机标定
- stm32位带操作
- Qt5+OpenCV软件打包
- (11)Java多线程之Timer
- Simulate HDMI CEC by GPIO
- WPF TreeView large data performance
- JAVA基础【9.1】《Java核心技术1》集合
- 移动端如何清除输入框内阴影
- POJ 3278 Catch That Cow
- AsyncDisplayKit2.0教程(上)
- linux 多行注释批操作
- 使用ExceptionHandler进行Spring mvc 异常处理
- 用flask开发个人博客(40)—— Flask中三种测试方法