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