| #!/usr/bin/python |
| |
| # Copyright 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Reference[1]: IT680x example code: |
| # https://drive.google.com/corp/drive/u/0/folders/0B8Lcp5hqbjaqaE5WdDA5alVWOXc |
| |
| # Reference[2]: IT6803 Programming Guide: |
| # https://docs.google.com/viewer?a=v&pid=sites&srcid=\ |
| # Y2hyb21pdW0ub3JnfGRldnxneDoyNGVmNGFiMDE4ZWJiZDM2 |
| |
| # This code is a library for using IT680X chip in chameleon. |
| |
| import sys |
| import util |
| from time import sleep |
| |
| usage = """\ |
| Usage: |
| it6803 -- print command usage |
| it6803 cec_reg_print -- print all cec registers value |
| it6803 cec_msg_receive -- print receiving cec message |
| it6803 cec_msg {cmd} -- send cec message |
| """ |
| |
| QUEUE_SIZE = 3 |
| q_head = 0 |
| q_tail = 0 |
| regTxOutState = 3 |
| |
| logicalAddr = 0 |
| initiatorAddr = 0x0F |
| cecTxState = 0 |
| |
| txCmdBuf = [0x00] * 19 |
| rxCecBuf = [0x00] * 19 |
| queue = [[0x00 for i in range(19)] for j in range(QUEUE_SIZE)] |
| |
| # Chameleon register address |
| I2C_HDMI = 0x48 |
| I2C_CEC = 0x4A |
| |
| # Chameleon CEC control registers |
| # (name starts with REG is register addr, followings are values for this reg) |
| REG06 = 0x06 |
| REG_EMPTY = 0x00 |
| REG07 = 0x07 |
| ENABLE_CEC_INTERRUPT_PIN = 0x40 |
| |
| REG08 = 0x08 |
| FIRE_FRAME = 0x80 |
| DEBUG_CEC_CLEAR = 0x40 |
| CEC_SCHMITT_TRIGGER = 0x08 |
| CEC_INTERRUPT = 0x01 |
| |
| REG09 = 0x09 |
| REGION_SELECT = 0x40 |
| INITAITOR_RX_CEC = 0x20 |
| ACKNOWLEDGE = 0x01 |
| |
| REG_MIN_BIT = 0x0B |
| REG_TIME_UNIT = 0x0C |
| |
| REG0F = 0x0F |
| IO_PULL_UP = 0x50 |
| |
| REG_TARG_ADDR = 0x22 |
| REG_MSCOUNT_L = 0x45 |
| REG_MSCOUNT_M = 0x46 |
| REG_MSCOUNT_H = 0x47 |
| REF_INT_STATUS= 0x4C |
| |
| def main(cmdline): |
| """ Main function. """ |
| args = [''] * 4 |
| for i, x in enumerate(cmdline): |
| args[i] = x |
| cmd = args[1] |
| |
| if cmd == '': cmd = 'help' |
| fname = 'cmd_' + cmd |
| |
| cec_open() |
| if fname in globals(): |
| if args[2] == '': |
| globals()[fname]() |
| else: |
| globals()[fname](args[2]) |
| else: |
| print 'Unknown command', cmd |
| cec_close() |
| |
| |
| def cmd_help(): |
| """ Print help message. """ |
| print usage |
| |
| |
| def cec_open(): |
| """ Enable cec port. """ |
| # enable IT6803 CEC port: enable cec clock and assign slave addr |
| i2cset(I2C_HDMI, 0x0E, 0xFF) |
| i2cset(I2C_HDMI, 0x86, 0x95) |
| |
| def cec_close(): |
| """ Close cec port. """ |
| # disable cec slave addr |
| i2cset(I2C_HDMI, 0x86, 0x94) |
| |
| |
| def cec_init(): |
| """ Initialize cec port in chameleon. """ |
| # initial CEC register. From reference[1] Ln480 |
| |
| # enable it680x cec |
| i2cset(I2C_CEC, 0xF8, 0xC3) |
| i2cset(I2C_CEC, 0xF8, 0xA5) |
| q_head = 0 |
| q_tail = 0 |
| regTxOutState = 3 |
| |
| # get 100ms timer, according to ref [1,2] |
| i2cset(I2C_CEC, REG09, ACKNOWLEDGE) |
| sleep(0.099) |
| i2cset(I2C_CEC, REG09, REG_EMPTY) |
| high = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_H, 1)[0] * 0x10000 |
| mid = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_M, 1)[0] * 0x100 |
| low = util.i2c_read(0, I2C_CEC, REG_MSCOUNT_L, 1)[0] |
| tus = (high + mid + low) / 1000 |
| # print tus |
| |
| # CEC configuration |
| i2cset(I2C_CEC, REG09, INITAITOR_RX_CEC | REGION_SELECT) |
| i2cset(I2C_CEC, REG_MIN_BIT, 0x14) |
| i2cset(I2C_CEC, REG_TIME_UNIT, tus) |
| i2cset(I2C_CEC, REG_TARG_ADDR, logicalAddr) |
| i2cset(I2C_CEC, REG08, CEC_SCHMITT_TRIGGER) |
| uc = util.i2c_read(0, I2C_CEC, REG09, 1)[0] |
| # i2cset(I2C_CEC, REG09, uc|0x02) |
| # cec_clr_int |
| i2cset(I2C_CEC, REG08, CEC_INTERRUPT|DEBUG_CEC_CLEAR|CEC_SCHMITT_TRIGGER) |
| i2cset(I2C_CEC, REG08, CEC_SCHMITT_TRIGGER|DEBUG_CEC_CLEAR) |
| # print 'logicalAddr: {}, TimeUnit: {}'.format(logicalAddr,tus) |
| |
| # Enable CEC interrupt pin |
| reg07_val = util.i2c_read(0, I2C_CEC, REG07, 1)[0] |
| i2cset(I2C_CEC, REG07, reg07_val | ENABLE_CEC_INTERRUPT_PIN) |
| |
| # Enable ALL interrupt mask |
| i2cset(I2C_CEC, REG06, REG_EMPTY) |
| |
| # IO pull up enable |
| i2cset(I2C_CEC, REG0F, IO_PULL_UP) |
| |
| def cec_msg_receive(): |
| """ Read message received. """ |
| # 0x3F means all interrupts are on |
| cecInt = cec_reg_read(REF_INT_STATUS) & 0x3F |
| if 0 != (cecInt & 0x10): |
| if not cec_msg_read(): |
| raise Exception('Queue is full!') |
| ## TODO check interrupt register Status |
| i2c_cec_set(REF_INT_STATUS, cecInt) |
| # Decode received message |
| return cec_decode() |
| |
| |
| def cmd_cec_msg(message): |
| """ parent function for a cec message. """ |
| cec_init() |
| fname = 'cec_msg_' + message |
| globals()[fname]() |
| cec_transmit() |
| |
| def cec_msg_standby(): |
| """ Send a stand by message. """ |
| # F = boardcast, 0x36 = stand by message |
| cec_cmd_set(0xF, 0x36, None, None) |
| # other operations need more assignments |
| |
| def cec_msg_viewon(): |
| """ Send a view on message. """ |
| # 0 = TV, 0x04 = image on |
| cec_cmd_set(0x0, 0x04, None, None) |
| |
| def cec_msg_poweron(): |
| """ Make a power on cec message. """ |
| global initiatorAddr |
| # 0x90 = power status message |
| cec_cmd_set(initiatorAddr, 0x90, 0x00, None) |
| |
| def cec_msg_poweroff(): |
| """ Make a power off cec message. """ |
| global initiatorAddr |
| # 0x90 = power status message |
| cec_cmd_set(initiatorAddr, 0x90, 0x01, None) |
| |
| def cec_reg_read(offset): |
| """ read it6803's register value from i2c line. """ |
| return util.i2c_read(0, I2C_CEC, offset, 1)[0] |
| |
| def cec_cmd_set(follower, txCmd, operand1, operand2): |
| """ Compose a cec message. """ |
| # print 'follower: {}, cmd: {}'.format(follower, txCmd) |
| # TODO set variables |
| txCmdBuf[0] = 2 |
| txCmdBuf[1] = (logicalAddr<<4) + follower |
| txCmdBuf[2] = txCmd |
| txCmdBuf[3] = 0 |
| txCmdBuf[4] = 0 |
| if operand1 is not None: |
| txCmdBuf[3] = operand1 |
| txCmdBuf[0] = 3 |
| if operand2 is not None: |
| txCmdBuf[4] = operand2 |
| txCmdBuf[0] = 4 |
| # print txCmdBuf |
| return |
| |
| def cec_transmit(): |
| """ File a cec message out. """ |
| # Assume the state is cecTransfer |
| # Set values from 0x10 to 0x23 |
| i2c_cec_set(0x23, txCmdBuf[0]) |
| for i in range (0, txCmdBuf[0]): |
| i2c_cec_set(0x10+i, txCmdBuf[i+1]) |
| |
| # Fire command |
| i2c_cec_set(REG08, FIRE_FRAME | CEC_SCHMITT_TRIGGER | DEBUG_CEC_CLEAR) |
| i2c_cec_set(REG08, CEC_SCHMITT_TRIGGER | DEBUG_CEC_CLEAR) |
| return |
| |
| def cec_msg_read(): |
| """ Read incoming cec messages from memory. """ |
| global q_head, q_tail |
| if (q_head % QUEUE_SIZE) != (q_tail % QUEUE_SIZE): |
| return False |
| q_tail += 1 |
| i = q_tail % QUEUE_SIZE |
| # 0x30 is starting point for receiving message |
| data = util.i2c_read(0, I2C_CEC, 0x30, 19) |
| for j in range(1, 19): |
| queue[i][j] = data[j-1] |
| queue[i][0] = data[18] |
| return True |
| |
| def cec_decode(): |
| """ Process incoming cec message. """ |
| global q_head, q_tail, initiatorAddr |
| if (q_head % QUEUE_SIZE) == (q_tail % QUEUE_SIZE): |
| # Queue is empty |
| return |
| q_head += 1 |
| rxCecBuf = queue[q_head % QUEUE_SIZE] |
| #print rxCecBuf |
| |
| if (rxCecBuf[0] == 1): |
| if logicalAddr == (rxCecBuf[1] & 0x0F): |
| # eReportPhysicalAddress |
| return |
| # Validate message |
| initiatorAddr = (rxCecBuf[1] >> 4) & 0x0F |
| followerAddr = rxCecBuf[1] & 0x0F |
| print 'Initiator: {} Follower: {}'.format(initiatorAddr, followerAddr) |
| |
| if (rxCecBuf[2] == 0x04): |
| print 'received image-view-on' |
| elif (rxCecBuf[2] == 0x36): |
| print 'received standby' |
| else: |
| print 'other command: {}'.format(rxCecBuf[2]) |
| return rxCecBuf[2] |
| |
| def i2cset(addr, offset, value): |
| """ set some register value via i2c line. """ |
| util.i2c_write(0, addr, offset, [value]) |
| |
| def i2c_cec_set(offset, value): |
| """ set it6803's register value via i2c line. """ |
| i2cset(I2C_CEC, offset, value) |
| |
| if __name__ == '__main__': |
| main(sys.argv) |