/* Copyright (c) 2005 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Neither the name of the Advanced Micro Devices, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * */ /* * This file contains routines to write to and read from the I2C bus using * the ACCESS.bus hardware in the SC1200. * */ /* SUPER IO DEFINITIONS */ #define INDEX_1 0x15C /* base address 1 selected */ #define DATA_1 0x15D #define INDEX_2 0x2E /* base address 2 selected */ #define DATA_2 0x2F #define PCI_INDEX 0xCF8 /* PCI configuration space INDEX */ #define PCI_DATA 0xCFC /* PCI configuration space DATA */ #define BASE_ADR_MSB_REG 0x60 /* base address MSB register */ #define BASE_ADR_LSB_REG 0x61 /* base address LSB register */ #define SIO_BASE_ADR_15C_15D 0x6000000 #define SIO_BASE_ADR_2E_2F 0x4000000 /* SUPER IO GLOBALS */ unsigned short index_reg, data_reg; /* ACCESS BUS DEFINITIONS */ #define ACC_I2C_TIMEOUT 1000000 /* Number of reads before timing out */ #define ACB1_BASE 0x810 /* ACCESS.bus base addresses */ #define ACB2_BASE 0x820 #define ACBSDA 0 /* ACB serial data */ #define ACBST 1 /* ACB status */ #define ACBCST 2 /* ACB control status */ #define ACBCTL1 3 /* ACB control 1 */ #define ACBADDR 4 /* ACB own address */ #define ACBCTL2 5 /* ACB control 2 */ #define LDN 0x7 /* Logical Device Numbers */ #define ACB1_LDN 0x5 #define ACB2_LDN 0x6 /* INITIAL ACCESS.bus BASE ADDRESS VALUES */ unsigned short base_address_array[3] = { 0, ACB1_BASE, ACB2_BASE }; char Freq = 0x71; /* LOCAL ACCESS.bus FUNCTION DECLARATIONS */ void acc_i2c_start(unsigned char busnum); void acc_i2c_stop(unsigned char busnum); void acc_i2c_abort_data(unsigned char busnum); void acc_i2c_bus_recovery(unsigned char busnum); void acc_i2c_stall_after_start(unsigned char busnum, int state); void acc_i2c_send_address(unsigned char busnum, unsigned char cData); int acc_i2c_ack(unsigned char busnum, int fPut, int negAck); void acc_i2c_stop_clock(unsigned char busnum); void acc_i2c_activate_clock(unsigned char busnum); void acc_i2c_write_byte(unsigned char busnum, unsigned char cData); unsigned char acc_i2c_read_byte(unsigned char busnum, int last_byte); void acc_i2c_reset_bus(unsigned char busnum); int acc_i2c_request_master(unsigned char busnum); void acc_i2c_config(unsigned char busnum, short adr, char freq); char acc_i2c_set_freq(unsigned char busnum, char freq); unsigned short acc_i2c_set_base_address(unsigned char busnum, short adr); /* LOCAL HELPER ROUTINES */ void OsPciReadDWord(int bus, int dev, int func, int address, unsigned long *data); int sio_set_index_data_reg(void); void sio_write_reg(unsigned char reg, unsigned char data); unsigned char sio_read_reg(unsigned char reg); /*--------------------------------------------------------------------------- * OsPciReadDWord * * This routine reads one double word from the PCI configuration header * defined by 'bus', 'dev', 'func' and 'address' to the double word * pointed to by 'data'. * * Returns : None. *--------------------------------------------------------------------------- */ void OsPciReadDWord(int bus, int dev, int func, int address, unsigned long *data) { /* * The address of a double word in the Configuration Header is built in * the following way : * {10000000,bus[23:16],device[15:11],function[10:8],address[7:2],00} */ long addr = (0x80000000 | ((bus & 0xff) << 16) | ((dev & 0x1f) << 11) | ((func & 0x7) << 8) | (address & 0xff)); OUTD(PCI_INDEX, addr); *data = IND(PCI_DATA); } /*--------------------------------------------------------------------------- * sio_set_index_data_reg * * This routine checks which index and data registers to use * in order to access the Super I/O registers * * Returns : 1 - OK * 0 - Super I/O disabled or configuration access disabled *--------------------------------------------------------------------------- */ int sio_set_index_data_reg(void) { unsigned long xbus_expention_bar, io_control_reg1; OsPciReadDWord(0, 0x12, 5, 0x10, &xbus_expention_bar); xbus_expention_bar = xbus_expention_bar & 0xfffffffe; io_control_reg1 = IND((unsigned short)xbus_expention_bar); if ((io_control_reg1) & (SIO_BASE_ADR_15C_15D)) { index_reg = INDEX_1; data_reg = DATA_1; return (1); } if ((io_control_reg1) & (SIO_BASE_ADR_2E_2F)) { index_reg = INDEX_2; data_reg = DATA_2; return (1); } return (0); } /*--------------------------------------------------------------------------- * sio_write_reg * * This routine writes 'data' to 'reg' Super I/O register * * Returns : None *--------------------------------------------------------------------------- */ void sio_write_reg(unsigned char reg, unsigned char data) { OUTB(index_reg, reg); OUTB(data_reg, data); } /*--------------------------------------------------------------------------- * sio_read_reg * * This routine reads data from 'reg' Super I/O register * * Returns : The data read from the requested register *--------------------------------------------------------------------------- */ unsigned char sio_read_reg(unsigned char reg) { OUTB(index_reg, reg); return INB(data_reg); } /*--------------------------------------------------------------------------- * gfx_i2c_reset * * This routine resets the I2C bus as follows : * · Sets the base address of the ACCESS.bus * · Sets the frequency of the ACCESS.bus * · Resets the ACCESS.bus * * If 'adr' is -1 the address is read from the hardware. * If 'freq' is -1 the frequency is set to 56 clock cycles. *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC int acc_i2c_reset(unsigned char busnum, short adr, char freq) #else int gfx_i2c_reset(unsigned char busnum, short adr, char freq) #endif { if ((busnum != 1) && (busnum != 2)) return GFX_STATUS_BAD_PARAMETER; acc_i2c_config(busnum, adr, freq); if (base_address_array[busnum] == 0) return GFX_STATUS_ERROR; acc_i2c_reset_bus(busnum); return GFX_STATUS_OK; } /*--------------------------------------------------------------------------- * gfx_i2c_select_gpio * * This routine selects which GPIO pins to use. *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC int acc_i2c_select_gpio(int clock, int data) #else int gfx_i2c_select_gpio(int clock, int data) #endif { /* THIS ROUTINE DOES NOT APPLY TO THE ACCESS.bus IMPLEMENTATION. */ return (GFX_STATUS_OK); } /*--------------------------------------------------------------------------- * gfx_i2c_write * * This routine writes data to the specified I2C address. * busnum - ACCESS.bus number (1 or 2). *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC int acc_i2c_write(unsigned char busnum, unsigned char chipadr, unsigned char subadr, unsigned char bytes, unsigned char *data) #else int gfx_i2c_write(unsigned char busnum, unsigned char chipadr, unsigned char subadr, unsigned char bytes, unsigned char *data) #endif { int loop = 0; if ((busnum != 1) && (busnum != 2)) return GFX_STATUS_BAD_PARAMETER; /* REQUEST MASTER */ if (!acc_i2c_request_master(busnum)) return (GFX_STATUS_ERROR); /* WRITE ADDRESS COMMAND */ acc_i2c_ack(busnum, 1, 0); acc_i2c_stall_after_start(busnum, 1); acc_i2c_send_address(busnum, (unsigned char)(chipadr & 0xFE)); acc_i2c_stall_after_start(busnum, 0); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); /* WRITE COMMAND */ acc_i2c_write_byte(busnum, subadr); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); /* WRITE DATA */ for (loop = 0; loop < bytes; loop++) { acc_i2c_write_byte(busnum, *data); if (loop < (bytes - 1)) data += sizeof(unsigned char); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); } data -= (bytes - 1); acc_i2c_stop(busnum); return GFX_STATUS_OK; } /*--------------------------------------------------------------------------- * gfx_i2c_read * * This routine reads data from the specified I2C address. * busnum - ACCESS.bus number (1 or 2). *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC int acc_i2c_read(unsigned char busnum, unsigned char chipadr, unsigned char subadr, unsigned char bytes, unsigned char *data) #else int gfx_i2c_read(unsigned char busnum, unsigned char chipadr, unsigned char subadr, unsigned char bytes, unsigned char *data) #endif { unsigned char bytesRead; if ((busnum != 1) && (busnum != 2)) return GFX_STATUS_BAD_PARAMETER; if (bytes == 0) return GFX_STATUS_OK; /* REQUEST MASTER */ if (!acc_i2c_request_master(busnum)) return (GFX_STATUS_ERROR); /* WRITE ADDRESS COMMAND */ acc_i2c_ack(busnum, 1, 0); acc_i2c_stall_after_start(busnum, 1); acc_i2c_send_address(busnum, (unsigned char)(chipadr & 0xFE)); acc_i2c_stall_after_start(busnum, 0); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); /* WRITE COMMAND */ acc_i2c_write_byte(busnum, subadr); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); /* START THE READ */ acc_i2c_start(busnum); /* WRITE ADDRESS COMMAND */ acc_i2c_ack(busnum, 1, 1); acc_i2c_stall_after_start(busnum, 1); acc_i2c_send_address(busnum, (unsigned char)(chipadr | 0x01)); /* IF LAST BYTE */ if (bytes == 1) acc_i2c_ack(busnum, 1, 1); else acc_i2c_ack(busnum, 1, 0); acc_i2c_stall_after_start(busnum, 0); if (!acc_i2c_ack(busnum, 0, 0)) return (GFX_STATUS_ERROR); /* READ COMMAND */ for (bytesRead = 0; bytesRead < bytes; bytesRead += 1) { if (bytesRead < (bytes - 2)) { data[bytesRead] = acc_i2c_read_byte(busnum, 0); acc_i2c_ack(busnum, 1, 0); } else if (bytesRead == (bytes - 2)) { /* TWO BYTES LEFT */ acc_i2c_ack(busnum, 1, 1); data[bytesRead] = acc_i2c_read_byte(busnum, 0); acc_i2c_ack(busnum, 1, 1); } else { /* LAST BYTE */ data[bytesRead] = acc_i2c_read_byte(busnum, 1); acc_i2c_stop(busnum); } /* WHILE NOT LAST BYTE */ if ((!(bytesRead == (bytes - 1))) && (!acc_i2c_ack(busnum, 0, 0))) return (bytesRead); } return GFX_STATUS_OK; } /*--------------------------------------------------------------------------- * gfx_i2c_init * * This routine initializes the use of the ACCESS.BUS. *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC int acc_i2c_init(void) #else int gfx_i2c_init(void) #endif { /* ### ADD ### THIS ROUTINE IS NOT YET IMPLEMENTED FOR ACCESS.bus */ return (GFX_STATUS_OK); } /*--------------------------------------------------------------------------- * gfx_i2c_cleanup * * This routine ends the use of the ACCESS.BUS. *--------------------------------------------------------------------------- */ #if GFX_I2C_DYNAMIC void acc_i2c_cleanup(void) #else void gfx_i2c_cleanup(void) #endif { /* ### ADD ### THIS ROUTINE IS NOT YET IMPLEMENTED FOR ACCESS.bus */ } /*--------------------------------------------------------*/ /* LOCAL ROUTINES SPECIFIC TO ACCESS.bus IMPLEMENTATION */ /*--------------------------------------------------------*/ /*--------------------------------------------------------------------------- * acc_i2c_reset_bus * * This routine resets the I2C bus. *--------------------------------------------------------------------------- */ void acc_i2c_reset_bus(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; /* Disable the ACCESS.bus device and */ /* Configure the SCL frequency */ OUTB((unsigned short)(bus_base_address + ACBCTL2), (unsigned char)(Freq & 0xFE)); /* Configure no interrupt mode (polling) and */ /* Disable global call address */ OUTB((unsigned short)(bus_base_address + ACBCTL1), 0x0); /* Disable slave address */ OUTB((unsigned short)(bus_base_address + ACBADDR), 0x0); /* Enable the ACCESS.bus device */ reg = INB((unsigned short)(bus_base_address + ACBCTL2)); reg |= 0x01; OUTB((unsigned short)(bus_base_address + ACBCTL2), reg); /* Issue STOP event */ acc_i2c_stop(busnum); /* Clear NEGACK, STASTR and BER bits */ OUTB((unsigned short)(bus_base_address + ACBST), 0x38); /* Clear BB (BUS BUSY) bit */ reg = INB((unsigned short)(bus_base_address + ACBCST)); reg |= 0x02; OUTB((unsigned short)(bus_base_address + ACBCST), reg); } /*--------------------------------------------------------------------------- * acc_i2c_start * * This routine starts a transfer on the I2C bus. *--------------------------------------------------------------------------- */ void acc_i2c_start(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; reg = INB((unsigned short)(bus_base_address + ACBCTL1)); reg |= 0x01; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); } /*--------------------------------------------------------------------------- * acc_i2c_stop * * This routine stops a transfer on the I2C bus. *--------------------------------------------------------------------------- */ void acc_i2c_stop(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; reg = INB((unsigned short)(bus_base_address + ACBCTL1)); reg |= 0x02; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); } /*--------------------------------------------------------------------------- * acc_i2c_abort_data *--------------------------------------------------------------------------- */ void acc_i2c_abort_data(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; acc_i2c_stop(busnum); reg = INB((unsigned short)(bus_base_address + ACBCTL1)); reg |= 0x10; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); } /*--------------------------------------------------------------------------- * acc_i2c_bus_recovery *--------------------------------------------------------------------------- */ void acc_i2c_bus_recovery(unsigned char busnum) { acc_i2c_abort_data(busnum); acc_i2c_reset_bus(busnum); } /*--------------------------------------------------------------------------- * acc_i2c_stall_after_start *--------------------------------------------------------------------------- */ void acc_i2c_stall_after_start(unsigned char busnum, int state) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; reg = INB((unsigned short)(bus_base_address + ACBCTL1)); if (state) reg |= 0x80; else reg &= 0x7F; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); if (!state) { reg = INB((unsigned short)(bus_base_address + ACBST)); reg |= 0x08; OUTB((unsigned short)(bus_base_address + ACBST), reg); } } /*--------------------------------------------------------------------------- * acc_i2c_send_address *--------------------------------------------------------------------------- */ void acc_i2c_send_address(unsigned char busnum, unsigned char cData) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; unsigned long timeout = 0; /* WRITE THE DATA */ OUTB((unsigned short)(bus_base_address + ACBSDA), cData); while (1) { reg = INB((unsigned short)(bus_base_address + ACBST)); if ((reg & 0x38) != 0) /* check STASTR, BER and NEGACK */ break; if (timeout++ == ACC_I2C_TIMEOUT) { acc_i2c_bus_recovery(busnum); return; } } /* CHECK FOR BUS ERROR */ if (reg & 0x20) { acc_i2c_bus_recovery(busnum); return; } /* CHECK NEGATIVE ACKNOWLEDGE */ if (reg & 0x10) { acc_i2c_abort_data(busnum); return; } } /*--------------------------------------------------------------------------- * acc_i2c_ack * * This routine looks for acknowledge on the I2C bus. *--------------------------------------------------------------------------- */ int acc_i2c_ack(unsigned char busnum, int fPut, int negAck) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; unsigned long timeout = 0; if (fPut) { /* read operation */ if (!negAck) { /* Push Ack onto I2C bus */ reg = INB((unsigned short)(bus_base_address + ACBCTL1)); reg &= 0xE7; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); } else { /* Push negAck onto I2C bus */ reg = INB((unsigned short)(bus_base_address + ACBCTL1)); reg |= 0x10; OUTB((unsigned short)(bus_base_address + ACBCTL1), reg); } } else { /* write operation */ /* Receive Ack from I2C bus */ while (1) { reg = INB((unsigned short)(bus_base_address + ACBST)); if ((reg & 0x70) != 0) /* check SDAST, BER and NEGACK */ break; if (timeout++ == ACC_I2C_TIMEOUT) { acc_i2c_bus_recovery(busnum); return (0); } } /* CHECK FOR BUS ERROR */ if (reg & 0x20) { acc_i2c_bus_recovery(busnum); return (0); } /* CHECK NEGATIVE ACKNOWLEDGE */ if (reg & 0x10) { acc_i2c_abort_data(busnum); return (0); } } return (1); } /*--------------------------------------------------------------------------- * acc_i2c_stop_clock * * This routine stops the ACCESS.bus clock. *--------------------------------------------------------------------------- */ void acc_i2c_stop_clock(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; reg = INB((unsigned short)(bus_base_address + ACBCTL2)); reg &= ~0x01; OUTB((unsigned short)(bus_base_address + ACBCTL2), reg); } /*--------------------------------------------------------------------------- * acc_i2c_activate_clock * * This routine activates the ACCESS.bus clock. *--------------------------------------------------------------------------- */ void acc_i2c_activate_clock(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; reg = INB((unsigned short)(bus_base_address + ACBCTL2)); reg |= 0x01; OUTB((unsigned short)(bus_base_address + ACBCTL2), reg); } /*--------------------------------------------------------------------------- * acc_i2c_write_byte * * This routine writes a byte to the I2C bus *--------------------------------------------------------------------------- */ void acc_i2c_write_byte(unsigned char busnum, unsigned char cData) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; unsigned long timeout = 0; while (1) { reg = INB((unsigned short)(bus_base_address + ACBST)); if (reg & 0x70) break; if (timeout++ == ACC_I2C_TIMEOUT) { acc_i2c_bus_recovery(busnum); return; } } /* CHECK FOR BUS ERROR */ if (reg & 0x20) { acc_i2c_bus_recovery(busnum); return; } /* CHECK NEGATIVE ACKNOWLEDGE */ if (reg & 0x10) { acc_i2c_abort_data(busnum); return; } /* WRITE THE DATA */ OUTB((unsigned short)(bus_base_address + ACBSDA), cData); } /*--------------------------------------------------------------------------- * acc_i2c_read_byte * * This routine reads a byte from the I2C bus *--------------------------------------------------------------------------- */ unsigned char acc_i2c_read_byte(unsigned char busnum, int last_byte) { unsigned char cData, reg; unsigned short bus_base_address = base_address_array[busnum]; unsigned long timeout = 0; while (1) { reg = INB((unsigned short)(bus_base_address + ACBST)); if (reg & 0x60) break; if (timeout++ == ACC_I2C_TIMEOUT) { acc_i2c_bus_recovery(busnum); return (0xEF); } } /* CHECK FOR BUS ERROR */ if (reg & 0x20) { acc_i2c_bus_recovery(busnum); return (0xEE); } /* READ DATA */ if (last_byte) acc_i2c_stop_clock(busnum); cData = INB((unsigned short)(bus_base_address + ACBSDA)); if (last_byte) acc_i2c_activate_clock(busnum); return (cData); } /*--------------------------------------------------------------------------- * acc_i2c_request_master *--------------------------------------------------------------------------- */ int acc_i2c_request_master(unsigned char busnum) { unsigned char reg; unsigned short bus_base_address = base_address_array[busnum]; unsigned long timeout = 0; acc_i2c_start(busnum); while (1) { reg = INB((unsigned short)(bus_base_address + ACBST)); if (reg & 0x60) break; if (timeout++ == ACC_I2C_TIMEOUT) { acc_i2c_bus_recovery(busnum); return (0); } } /* CHECK FOR BUS ERROR */ if (reg & 0x20) { acc_i2c_abort_data(busnum); return (0); } /* CHECK NEGATIVE ACKNOWLEDGE */ if (reg & 0x10) { acc_i2c_abort_data(busnum); return (0); } return (1); } /*--------------------------------------------------------*/ /* LOCAL ROUTINES SPECIFIC TO ACCESS.bus INITIALIZATION */ /*--------------------------------------------------------*/ /*---------------------------------------------------------------------------- * acc_i2c_config * * This routine configures the I2C bus *---------------------------------------------------------------------------- */ void acc_i2c_config(unsigned char busnum, short adr, char freq) { base_address_array[busnum] = acc_i2c_set_base_address(busnum, adr); Freq = acc_i2c_set_freq(busnum, freq); } /*---------------------------------------------------------------------------- * acc_i2c_set_freq * * This routine sets the frequency of the I2C bus *---------------------------------------------------------------------------- */ char acc_i2c_set_freq(unsigned char busnum, char freq) { unsigned short bus_base_address = base_address_array[busnum]; OUTB((unsigned short)(bus_base_address + ACBCTL2), 0x0); if (freq == -1) freq = 0x71; else { freq = freq << 1; freq |= 0x01; } OUTB((unsigned short)(bus_base_address + ACBCTL2), freq); return (freq); } /*--------------------------------------------------------------------------- * acc_i2c_set_base_address * * This routine sets the base address of the I2C bus *--------------------------------------------------------------------------- */ unsigned short acc_i2c_set_base_address(unsigned char busnum, short adr) { unsigned short ab_base_addr; /* Get Super I/O Index and Data registers */ if (!sio_set_index_data_reg()) return (0); /* Configure LDN to current ACB */ if (busnum == 1) sio_write_reg(LDN, ACB1_LDN); if (busnum == 2) sio_write_reg(LDN, ACB2_LDN); if (adr == -1) { /* Get ACCESS.bus base address */ ab_base_addr = sio_read_reg(BASE_ADR_MSB_REG); ab_base_addr = ab_base_addr << 8; ab_base_addr |= sio_read_reg(BASE_ADR_LSB_REG); if (ab_base_addr != 0) return ab_base_addr; else adr = (busnum == 1 ? ACB1_BASE : ACB2_BASE); } /* Set ACCESS.bus base address */ sio_write_reg(BASE_ADR_LSB_REG, (unsigned char)(adr & 0xFF)); sio_write_reg(BASE_ADR_MSB_REG, (unsigned char)(adr >> 8)); return adr; } /* END OF FILE */