1#!/usr/bin/python 2 3# Copyright 2014 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7# Reference[1]: IT680x example code: 8# https://drive.google.com/corp/drive/u/0/folders/0B8Lcp5hqbjaqaE5WdDA5alVWOXc 9 10# Reference[2]: IT6803 Programming Guide: 11# https://docs.google.com/viewer?a=v&pid=sites&srcid=\ 12# Y2hyb21pdW0ub3JnfGRldnxneDoyNGVmNGFiMDE4ZWJiZDM2 13 14# This code is a library for using IT680X chip in chameleon. 15 16import sys 17import util 18from time import sleep 19 20usage = """\ 21Usage: 22 it6803 -- print command usage 23 it6803 cec_reg_print -- print all cec registers value 24 it6803 cec_msg_receive -- print receiving cec message 25 it6803 cec_msg {cmd} -- send cec message 26""" 27 28QUEUE_SIZE = 3 29q_head = 0 30q_tail = 0 31regTxOutState = 3 32 33logicalAddr = 0 34initiatorAddr = 0x0F 35cecTxState = 0 36 37txCmdBuf = [0x00] * 19 38rxCecBuf = [0x00] * 19 39queue = [[0x00 for i in range(19)] for j in range(QUEUE_SIZE)] 40 41# Chameleon register address 42I2C_HDMI = 0x48 43I2C_CEC = 0x4A 44 45# Chameleon CEC control registers 46# (name starts with REG is register addr, followings are values for this reg) 47REG06 = 0x06 48REG_EMPTY = 0x00 49REG07 = 0x07 50ENABLE_CEC_INTERRUPT_PIN = 0x40 51 52REG08 = 0x08 53FIRE_FRAME = 0x80 54DEBUG_CEC_CLEAR = 0x40 55CEC_SCHMITT_TRIGGER = 0x08 56CEC_INTERRUPT = 0x01 57 58REG09 = 0x09 59REGION_SELECT = 0x40 60INITAITOR_RX_CEC = 0x20 61ACKNOWLEDGE = 0x01 62 63REG_MIN_BIT = 0x0B 64REG_TIME_UNIT = 0x0C 65 66REG0F = 0x0F 67IO_PULL_UP = 0x50 68 69REG_TARG_ADDR = 0x22 70REG_MSCOUNT_L = 0x45 71REG_MSCOUNT_M = 0x46 72REG_MSCOUNT_H = 0x47 73REF_INT_STATUS= 0x4C 74 75def main(cmdline): 76 """ Main function. """ 77 args = [''] * 4 78 for i, x in enumerate(cmdline): 79 args[i] = x 80 cmd = args[1] 81 82 if cmd == '': cmd = 'help' 83 fname = 'cmd_' + cmd 84 85 cec_open() 86 if fname in globals(): 87 if args[2] == '': 88 globals()[fname]() 89 else: 90 globals()[fname](args[2]) 91 else: 92 print 'Unknown command', cmd 93 cec_close() 94 95 96def cmd_help(): 97 """ Print help message. """ 98 print usage 99 100 101def cec_open(): 102 """ Enable cec port. """ 103 # enable IT6803 CEC port: enable cec clock and assign slave addr 104 i2cset(I2C_HDMI, 0x0E, 0xFF) 105 i2cset(I2C_HDMI, 0x86, 0x95) 106 107def cec_close(): 108 """ Close cec port. """ 109 # disable cec slave addr 110 i2cset(I2C_HDMI, 0x86, 0x94) 111 112 113def cec_init(): 114 """ Initialize cec port in chameleon. """ 115 # initial CEC register. From reference[1] Ln480 116 117 # enable it680x cec 118 i2cset(I2C_CEC, 0xF8, 0xC3) 119 i2cset(I2C_CEC, 0xF8, 0xA5) 120 q_head = 0 121 q_tail = 0 122 regTxOutState = 3 123 124 # get 100ms timer, according to ref [1,2] 125 i2cset(I2C_CEC, REG09, ACKNOWLEDGE) 126 sleep(0.099) 127 i2cset(I2C_CEC, REG09, REG_EMPTY) 128 high = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_H, 1)[0] * 0x10000 129 mid = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_M, 1)[0] * 0x100 130 low = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_L, 1)[0] 131 tus = (high + mid + low) / 1000 132 # print tus 133 134 # CEC configuration 135 i2cset(I2C_CEC, REG09, INITAITOR_RX_CEC | REGION_SELECT) 136 i2cset(I2C_CEC, REG_MIN_BIT, 0x14) 137 i2cset(I2C_CEC, REG_TIME_UNIT, tus) 138 i2cset(I2C_CEC, REG_TARG_ADDR, logicalAddr) 139 i2cset(I2C_CEC, REG08, CEC_SCHMITT_TRIGGER) 140 uc = util.i2c_read(0, I2C_CEC, REG09, 1)[0] 141 # i2cset(I2C_CEC, REG09, uc|0x02) 142 # cec_clr_int 143 i2cset(I2C_CEC, REG08, CEC_INTERRUPT|DEBUG_CEC_CLEAR|CEC_SCHMITT_TRIGGER) 144 i2cset(I2C_CEC, REG08, CEC_SCHMITT_TRIGGER|DEBUG_CEC_CLEAR) 145 # print 'logicalAddr: {}, TimeUnit: {}'.format(logicalAddr,tus) 146 147 # Enable CEC interrupt pin 148 reg07_val = util.i2c_read(0, I2C_CEC, REG07, 1)[0] 149 i2cset(I2C_CEC, REG07, reg07_val | ENABLE_CEC_INTERRUPT_PIN) 150 151 # Enable ALL interrupt mask 152 i2cset(I2C_CEC, REG06, REG_EMPTY) 153 154 # IO pull up enable 155 i2cset(I2C_CEC, REG0F, IO_PULL_UP) 156 157def cec_msg_receive(): 158 """ Read message received. """ 159 # 0x3F means all interrupts are on 160 cecInt = cec_reg_read(REF_INT_STATUS) & 0x3F 161 if 0 != (cecInt & 0x10): 162 if not cec_msg_read(): 163 raise Exception('Queue is full!') 164 ## TODO check interrupt register Status 165 i2c_cec_set(REF_INT_STATUS, cecInt) 166 # Decode received message 167 return cec_decode() 168 169 170def cmd_cec_msg(message): 171 """ parent function for a cec message. """ 172 cec_init() 173 fname = 'cec_msg_' + message 174 globals()[fname]() 175 cec_transmit() 176 177def cec_msg_standby(): 178 """ Send a stand by message. """ 179 # F = boardcast, 0x36 = stand by message 180 cec_cmd_set(0xF, 0x36, None, None) 181 # other operations need more assignments 182 183def cec_msg_viewon(): 184 """ Send a view on message. """ 185 # 0 = TV, 0x04 = image on 186 cec_cmd_set(0x0, 0x04, None, None) 187 188def cec_msg_poweron(): 189 """ Make a power on cec message. """ 190 global initiatorAddr 191 # 0x90 = power status message 192 cec_cmd_set(initiatorAddr, 0x90, 0x00, None) 193 194def cec_msg_poweroff(): 195 """ Make a power off cec message. """ 196 global initiatorAddr 197 # 0x90 = power status message 198 cec_cmd_set(initiatorAddr, 0x90, 0x01, None) 199 200def cec_reg_read(offset): 201 """ read it6803's register value from i2c line. """ 202 return util.i2c_read(0, I2C_CEC, offset, 1)[0] 203 204def cec_cmd_set(follower, txCmd, operand1, operand2): 205 """ Compose a cec message. """ 206 # print 'follower: {}, cmd: {}'.format(follower, txCmd) 207 # TODO set variables 208 txCmdBuf[0] = 2 209 txCmdBuf[1] = (logicalAddr<<4) + follower 210 txCmdBuf[2] = txCmd 211 txCmdBuf[3] = 0 212 txCmdBuf[4] = 0 213 if operand1 is not None: 214 txCmdBuf[3] = operand1 215 txCmdBuf[0] = 3 216 if operand2 is not None: 217 txCmdBuf[4] = operand2 218 txCmdBuf[0] = 4 219 # print txCmdBuf 220 return 221 222def cec_transmit(): 223 """ File a cec message out. """ 224 # Assume the state is cecTransfer 225 # Set values from 0x10 to 0x23 226 i2c_cec_set(0x23, txCmdBuf[0]) 227 for i in range (0, txCmdBuf[0]): 228 i2c_cec_set(0x10+i, txCmdBuf[i+1]) 229 230 # Fire command 231 i2c_cec_set(REG08, FIRE_FRAME | CEC_SCHMITT_TRIGGER | DEBUG_CEC_CLEAR) 232 i2c_cec_set(REG08, CEC_SCHMITT_TRIGGER | DEBUG_CEC_CLEAR) 233 return 234 235def cec_msg_read(): 236 """ Read incoming cec messages from memory. """ 237 global q_head, q_tail 238 if (q_head % QUEUE_SIZE) != (q_tail % QUEUE_SIZE): 239 return False 240 q_tail += 1 241 i = q_tail % QUEUE_SIZE 242 # 0x30 is starting point for receiving message 243 data = util.i2c_read(0, I2C_CEC, 0x30, 19) 244 for j in range(1, 19): 245 queue[i][j] = data[j-1] 246 queue[i][0] = data[18] 247 return True 248 249def cec_decode(): 250 """ Process incoming cec message. """ 251 global q_head, q_tail, initiatorAddr 252 if (q_head % QUEUE_SIZE) == (q_tail % QUEUE_SIZE): 253 # Queue is empty 254 return 255 q_head += 1 256 rxCecBuf = queue[q_head % QUEUE_SIZE] 257 #print rxCecBuf 258 259 if (rxCecBuf[0] == 1): 260 if logicalAddr == (rxCecBuf[1] & 0x0F): 261 # eReportPhysicalAddress 262 return 263 # Validate message 264 initiatorAddr = (rxCecBuf[1] >> 4) & 0x0F 265 followerAddr = rxCecBuf[1] & 0x0F 266 print 'Initiator: {} Follower: {}'.format(initiatorAddr, followerAddr) 267 268 if (rxCecBuf[2] == 0x04): 269 print 'received image-view-on' 270 elif (rxCecBuf[2] == 0x36): 271 print 'received standby' 272 else: 273 print 'other command: {}'.format(rxCecBuf[2]) 274 return rxCecBuf[2] 275 276def i2cset(addr, offset, value): 277 """ set some register value via i2c line. """ 278 util.i2c_write(0, addr, offset, [value]) 279 280def i2c_cec_set(offset, value): 281 """ set it6803's register value via i2c line. """ 282 i2cset(I2C_CEC, offset, value) 283 284if __name__ == '__main__': 285 main(sys.argv) 286