• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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