📄 bbu_i2c.s
字号:
;*********************************************************************************
;
; COPYRIGHT (C) 2006 Marvell International Ltd. All Rights Reserved.
;
; The information in this file is furnished for informational use only,
; is subject to change without notice, and should not be construed as
; a commitment by Marvell. Marvell assumes no responsibility or liability
; for any errors or inaccuracies that may appear in this software or any
; documenation that may be provided in association with this software.
;
;*********************************************************************************
;
; I2C_CS.s
; Subroutines for the I2C bus
;
INCLUDE xlli_PXA3xx_defs.inc
INCLUDE bbu_Monahans_defs.inc
GLOBAL BBU_getI2C ; Read from I2C bus
GLOBAL BBU_putI2C ; Write to I2C bus
GLOBAL BBU_getPI2C ; Read from the power I2C bus
GLOBAL BBU_putPI2C ; Write to the power I2C bus
GLOBAL BBU_getI2C_16 ; Read from I2C bus using 16-bit register address
GLOBAL BBU_putI2C_16 ; Write to I2C bus using 16-bit register address
;
; I2C BUS INTERFACE UNIT base address and register offsets from the base address
;
bbu_I2C_PHYSICAL_BASE EQU 0x40301680
bbu_I2C_IMBR_offset EQU 0X00 ; I2C Bus Monitor Register
bbu_I2C_IDBR_offset EQU 0X08 ; I2C Data Buffer Register
bbu_I2C_ICR_offset EQU 0X10 ; I2C Control Register
bbu_I2C_ISR_offset EQU 0X18 ; I2C Status Register
bbu_I2C_ISAR_offset EQU 0X20 ; I2C Slave Address Register
bbu_I2C_ICCR_offset EQU 0x28 ; Clock Count Register
bbu_ICR_IUE EQU 0X0040 ; ICR I2C Unit enable bit
bbu_ICR_SCLE EQU 0X0020 ; ICR I2C SCL Enable bit
bbu_ICR_TB EQU 0X0008 ; ICR Transfer Byte bit
bbu_ICR_ACKNAK EQU 0x0004 ; ICR ACK bit
bbu_ICR_STOP EQU 0x0002 ; ICR STOP bit
bbu_ICR_START EQU 0X0001 ; ICR START bit
bbu_ISR_IRF EQU 0x0080 ; ISR Receive full bit
bbu_ISR_ITE EQU 0x0040 ; ISR Transmit empty bit
bbu_PI2C_EN EQU 0x0040 ; Power I2C enable bit
bbu_ISR_BED EQU 0x0400 ; Bus Error Detect bit
BBU_I2C_TimeOut EQU 0x2000 ; I2C bus timeout loop counter value
bbu_PMRCREGS_PHYSICAL_BASE EQU 0x40F50000 ; Power manager base address
bbu_PCFR_offset EQU 0x00C ; Offset to Power Manager general config register
bbu_PI2DBR_offset EQU 0x188 ; Power I2C Data Buffer Register
bbu_PI2CR_offset EQU 0x190 ; Power I2C Control Register
bbu_PI2SR_offset EQU 0x198 ; Power I2C Status Register
bbu_PI2SAR_offset EQU 0x1A0 ; Power I2C Slave Address Register
AREA |text|,CODE,READONLY
;
;*********************************************************************************
;
; **************
; * *
; * BBU_getI2C * Subroutine
; * *
; **************
;
; This subroutine is used to read data from the Standard I2C bus
;
; PARAMETER PASSING:
;
; r0 = address in target device where data is to be read from (preserved)
;
; NOTE: If read address equals 0x100, the code just returns after the device
; address is sent. This can be used to discover if an address is used
; without reading or writing any data to the device.
;
; If read address equals 0x200, the code will read data back from certain
; GPIO expanders used on the platform.
;
; RETURNED VALUES:
;
; r1 = data read from the register pointed to by r0
; r2 = non zero if device was detected
; r2 = zero if device not detected (usually a time out issue)
;
BBU_getI2C FUNCTION
stmfd sp!, {r3-r6, lr} ; Save used registers
;
; Make sure the clock to the I2C unit is enabled
; Init the I2C controller for use
;
ldr r4, =bbu_I2C_PHYSICAL_BASE ; Load Power Manager controller base address
mov r3, #bbu_ISR_BED ; This is the Bus Detect Error detect bit
str r3, [r4, #bbu_I2C_ISR_offset] ; Insure this bit is cleared (sticky bit)
mov r1, #0 ; Set host controller slave address
str r1, [r4, #bbu_I2C_ISAR_offset] ; Set slave address register
str r1, [r4, #bbu_I2C_ICR_offset] ; Clear interrupts in ICR
mov r3, #(bbu_ICR_IUE | bbu_ICR_SCLE) ; Set IUE and SCLE bits
str r3, [r4, #bbu_I2C_ICR_offset] ; Enable the I2C in ICR
;
; Get the slave's address
;
ldr r5, =bbu_FFUART_PHYSICAL_BASE ; Fetch base address of the FFUART
ldrb r6, [r5, #bbu_UASPR_offset] ; Get contents of the scratch pad register
str r6, [r4, #bbu_I2C_IDBR_offset] ; Load Data Buffer Register
;
; Send 1st byte
;
orr r3, r3, #(bbu_ICR_TB | bbu_ICR_START)
str r3, [r4, #bbu_I2C_ICR_offset] ; Set TB and START bits (in addition to IUE & SCLE)
mov r2, #BBU_I2C_TimeOut ; Set up time out value
2 ldr r3, [r4, #bbu_I2C_ISR_offset] ; Get status register contents
subs r2, r2, #1 ; Decrement time out value
beq %F12 ; Exit path if timed out
ands r3, r3, #bbu_ISR_ITE ; Was the byte sent yet?
beq %B2 ; No - still being transmitted
str r3, [r4, #bbu_I2C_ISR_offset] ; Write the ITE bit to clear it (sticky)
mov r2, #0x10 ; Set time out loop count to allow time
3 subs r2, r2, #1 ; for the BED bit to (possibly) be set
bne %B3 ; Loop until time out is zero
ldr r3, [r4, #bbu_I2C_ISR_offset] ; Get status register contents
ands r3, r3, #bbu_ISR_BED ; Get status of Bus Error bit
moveq r2, #0xF ; Insure non-zero time out if no error
cmp r0, #0x100 ; Special case - Just seeing if device is there?
beq %F12 ; Yes - just exit
cmp r0, #0x200 ; Special case - for reading from certain GPIO expanders?
beq %F5 ; Yes - jump to this code
;
; Set up and then send 2nd byte (ADDRESS)
;
str r0, [r4, #bbu_I2C_IDBR_offset] ; Set register address in the IDBR
mov r3, #(bbu_ICR_TB | bbu_ICR_IUE | bbu_ICR_SCLE | bbu_ICR_STOP)
str r3, [r4, #bbu_I2C_ICR_offset] ; Set TB bit to start transfer
mov r2, #BBU_I2C_TimeOut ; Set up time out value
4 ldr r3, [r4, #bbu_I2C_ISR_offset] ; Get status register contents
subs r2, r2, #1 ; Decrement time out value
beq %F12 ; Exit path if timed out
ands r3, r3, #bbu_ISR_ITE ; Was the byte sent yet?
beq %B4 ; No - still being transmitted
str r3, [r4, #bbu_I2C_ISR_offset] ; Write the ITE bit to clear it (sticky)
;
; Delay 50 uS (clock is 3.6864 MHz)
;
5 ldr r2, =xlli_OSTREGS_PHYSICAL_BASE ; Load OS timer base address
ldr r3, [r2, #xlli_OSCR0_offset] ; Fetch starting value of OSCR0
add r3, r3, #0xB8 ; 0xB8 is about 50usec
6 ldr r5, [r2, #xlli_OSCR0_offset] ; Fetch current OSCR0 value
cmp r5, r3 ; Is the timer past the time out value?
bmi %B6 ; Not yet
;
; Set up and then send 3rd byte - Slave read address
;
orr r6, r6, #1 ; Turn the address into a slave address
str r6, [r4, #bbu_I2C_IDBR_offset] ; Load Data Buffer Register
mov r3, #(bbu_ICR_TB | bbu_ICR_IUE | bbu_ICR_SCLE | bbu_ICR_START)
str r3, [r4, #bbu_I2C_ICR_offset] ; Set TB bit to start transfer
8 ldr r3, [r4, #bbu_I2C_ISR_offset] ; Get status register contents
ands r3, r3, #bbu_ISR_ITE ; Was the byte sent yet?
beq %B8 ; No - still being transmitted
str r3, [r4, #bbu_I2C_ISR_offset] ; Write the ITE & IRF bits to clear them (sticky)
;
; Send STOP signal
;
mov r3, #(bbu_ICR_TB | bbu_ICR_IUE | bbu_ICR_SCLE | bbu_ICR_STOP | bbu_ICR_ACKNAK)
str r3, [r4, #bbu_I2C_ICR_offset] ; Set TB bit to start transfer
mov r2, #BBU_I2C_TimeOut ; Set up time out value
;
; Set up and then receive data byte
;
10 ldr r3, [r4, #bbu_I2C_ISR_offset] ; Get status register contents
subs r2, r2, #1 ; Decrement time out counter
moveq r2, #1 ; Reset to 1 if this transfer timed out
beq %F12 ; Exit path if timed out
ands r3, r3, #bbu_ISR_IRF ; Was the byte received yet?
beq %B10 ; no - keep looping
str r3, [r4, #bbu_I2C_ISR_offset] ; Write the IRF bit to clear it (sticky)
ldr r1, [r4, #bbu_I2C_IDBR_offset] ; Fetch data byte from the IDBR
12 ldmfd sp!, {r3-r6, pc} ; Return to caller
ENDFUNC
;
;*********************************************************************************
;
; **************
; * *
; * BBU_putI2C * Subroutine
; * *
; **************
;
; This subroutine is used to write data to the Regular I2C bus
;
; PARAMETER PASSING:
;
; r0 = address in target device where data is to be sent
; r1 = data to be loaded into the register pointed to by r0
;
; RETURNED VALUE:
;
; r2 = non zero if no I2C bus time out
; r2 = zero if I2C bus time out
;
BBU_putI2C FUNCTION
stmfd sp!, {r3-r6, lr} ; Save used registers
;
; Make sure the clock to the I2C unit is enabled
; Init the I2C controller for use
;
ldr r3, =bbu_I2C_PHYSICAL_BASE ; Load Power Manager controller base address
mov r2, #0 ; Set host controller slave address
str r2, [r3, #bbu_I2C_ISAR_offset] ; Set slave address register
str r2, [r3, #bbu_I2C_ICR_offset] ; Clear interrupts in ICR
mov r4, #(bbu_ICR_IUE | bbu_ICR_SCLE) ; Set IUE and SCLE bits
str r4, [r3, #bbu_I2C_ICR_offset] ; Enable the I2C in ICR
;
; Get the slave's address
;
ldr r5, =bbu_FFUART_PHYSICAL_BASE ; Fetch base address of FFUART
ldrb r6, [r5, #bbu_UASPR_offset] ; Get contents of the scratch pad register
str r6, [r3, #bbu_I2C_IDBR_offset] ; Load Data Buffer Register
;
; Send 1st byte
;
orr r4, r4, #(bbu_ICR_TB | bbu_ICR_START)
str r4, [r3, #bbu_I2C_ICR_offset] ; Set TB and START bits (in addition to IUE & SCLE)
mov r2, #BBU_I2C_TimeOut ; Set up time out loop
2 ldr r4, [r3, #bbu_I2C_ISR_offset] ; Get status register contents
subs r2, r2, #1 ; Decrement time out count
beq %F8 ; Timed out - return to caller
ands r4, r4, #bbu_ISR_ITE ; Was the byte sent yet?
beq %B2 ; No - still being transmitted
str r4, [r3, #bbu_I2C_ISR_offset] ; Write the ITE bit to clear it (sticky)
;
; Set up and then send 2nd byte (ADDRESS)
;
str r0, [r3, #bbu_I2C_IDBR_offset] ; Set register address in the IDBR
mov r4, #(bbu_ICR_TB | bbu_ICR_IUE | bbu_ICR_SCLE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -