1f29dbc25Smrg/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2f29dbc25Smrg *
3f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
4f29dbc25Smrg * of this software and associated documentation files (the "Software"), to
5f29dbc25Smrg * deal in the Software without restriction, including without limitation the
6f29dbc25Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7f29dbc25Smrg * sell copies of the Software, and to permit persons to whom the Software is
8f29dbc25Smrg * furnished to do so, subject to the following conditions:
9f29dbc25Smrg *
10f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
11f29dbc25Smrg * all copies or substantial portions of the Software.
12f29dbc25Smrg *
13f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19f29dbc25Smrg * IN THE SOFTWARE.
20f29dbc25Smrg *
21f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
23f29dbc25Smrg * software without specific prior written permission.
24f29dbc25Smrg * */
25f29dbc25Smrg
26f29dbc25Smrg/*
27f29dbc25Smrg * This file contains routines to write to and read from the I2C bus using
28f29dbc25Smrg * the ACCESS.bus hardware in the SC1200.
29f29dbc25Smrg * */
30f29dbc25Smrg
31f29dbc25Smrg/* SUPER IO DEFINITIONS */
32f29dbc25Smrg
33f29dbc25Smrg#define INDEX_1					0x15C   /* base address 1 selected              */
34f29dbc25Smrg#define DATA_1					0x15D
35f29dbc25Smrg#define INDEX_2					0x2E    /* base address 2 selected              */
36f29dbc25Smrg#define DATA_2					0x2F
37f29dbc25Smrg#define PCI_INDEX				0xCF8   /* PCI configuration space INDEX */
38f29dbc25Smrg#define PCI_DATA				0xCFC   /* PCI configuration space DATA  */
39f29dbc25Smrg#define BASE_ADR_MSB_REG		0x60    /* base address MSB register    */
40f29dbc25Smrg#define BASE_ADR_LSB_REG		0x61    /* base address LSB register    */
41f29dbc25Smrg
42f29dbc25Smrg#define SIO_BASE_ADR_15C_15D	0x6000000
43f29dbc25Smrg#define SIO_BASE_ADR_2E_2F 		0x4000000
44f29dbc25Smrg
45f29dbc25Smrg/* SUPER IO GLOBALS */
46f29dbc25Smrg
47f29dbc25Smrgunsigned short index_reg, data_reg;
48f29dbc25Smrg
49f29dbc25Smrg/* ACCESS BUS DEFINITIONS */
50f29dbc25Smrg
5104007ebaSmrg#define ACC_I2C_TIMEOUT 1000000 /* Number of reads before timing out */
5204007ebaSmrg#define ACB1_BASE 	    0x810       /* ACCESS.bus base addresses         */
53f29dbc25Smrg#define ACB2_BASE 	    0x820
5404007ebaSmrg#define ACBSDA			0       /* ACB serial data                   */
5504007ebaSmrg#define ACBST			1       /* ACB status                        */
5604007ebaSmrg#define ACBCST			2       /* ACB control status                */
5704007ebaSmrg#define ACBCTL1			3       /* ACB control 1                     */
5804007ebaSmrg#define ACBADDR			4       /* ACB own address                   */
5904007ebaSmrg#define ACBCTL2		    5   /* ACB control 2                     */
60f29dbc25Smrg#define LDN				0x7     /* Logical Device Numbers            */
61f29dbc25Smrg#define ACB1_LDN		0x5
62f29dbc25Smrg#define ACB2_LDN		0x6
63f29dbc25Smrg
64f29dbc25Smrg/* INITIAL ACCESS.bus BASE ADDRESS VALUES */
65f29dbc25Smrg
66f29dbc25Smrgunsigned short base_address_array[3] = { 0, ACB1_BASE, ACB2_BASE };
6704007ebaSmrg
68f29dbc25Smrgchar Freq = 0x71;
69f29dbc25Smrg
70f29dbc25Smrg/* LOCAL ACCESS.bus FUNCTION DECLARATIONS */
71f29dbc25Smrg
72f29dbc25Smrgvoid acc_i2c_start(unsigned char busnum);
73f29dbc25Smrgvoid acc_i2c_stop(unsigned char busnum);
74f29dbc25Smrgvoid acc_i2c_abort_data(unsigned char busnum);
75f29dbc25Smrgvoid acc_i2c_bus_recovery(unsigned char busnum);
76f29dbc25Smrgvoid acc_i2c_stall_after_start(unsigned char busnum, int state);
77f29dbc25Smrgvoid acc_i2c_send_address(unsigned char busnum, unsigned char cData);
78f29dbc25Smrgint acc_i2c_ack(unsigned char busnum, int fPut, int negAck);
79f29dbc25Smrgvoid acc_i2c_stop_clock(unsigned char busnum);
80f29dbc25Smrgvoid acc_i2c_activate_clock(unsigned char busnum);
81f29dbc25Smrgvoid acc_i2c_write_byte(unsigned char busnum, unsigned char cData);
82f29dbc25Smrgunsigned char acc_i2c_read_byte(unsigned char busnum, int last_byte);
83f29dbc25Smrgvoid acc_i2c_reset_bus(unsigned char busnum);
84f29dbc25Smrgint acc_i2c_request_master(unsigned char busnum);
85f29dbc25Smrgvoid acc_i2c_config(unsigned char busnum, short adr, char freq);
86f29dbc25Smrgchar acc_i2c_set_freq(unsigned char busnum, char freq);
87f29dbc25Smrgunsigned short acc_i2c_set_base_address(unsigned char busnum, short adr);
88f29dbc25Smrg
89f29dbc25Smrg/* LOCAL HELPER ROUTINES */
90f29dbc25Smrg
91f29dbc25Smrgvoid OsPciReadDWord(int bus, int dev, int func, int address,
9204007ebaSmrg                    unsigned long *data);
93f29dbc25Smrgint sio_set_index_data_reg(void);
94f29dbc25Smrgvoid sio_write_reg(unsigned char reg, unsigned char data);
95f29dbc25Smrgunsigned char sio_read_reg(unsigned char reg);
96f29dbc25Smrg
97f29dbc25Smrg/*---------------------------------------------------------------------------
98f29dbc25Smrg * OsPciReadDWord
99f29dbc25Smrg *
100f29dbc25Smrg * This routine reads one double word from the PCI configuration header
101f29dbc25Smrg * defined by 'bus', 'dev', 'func' and 'address' to the double word
102f29dbc25Smrg * pointed to by 'data'.
103f29dbc25Smrg *
104f29dbc25Smrg * Returns : None.
105f29dbc25Smrg *---------------------------------------------------------------------------
106f29dbc25Smrg */
107f29dbc25Smrgvoid
108f29dbc25SmrgOsPciReadDWord(int bus, int dev, int func, int address, unsigned long *data)
109f29dbc25Smrg{
110f29dbc25Smrg    /*
111f29dbc25Smrg     * The address of a double word in the Configuration Header is built in
112f29dbc25Smrg     * the following way :
113f29dbc25Smrg     * {10000000,bus[23:16],device[15:11],function[10:8],address[7:2],00}
114f29dbc25Smrg     */
115f29dbc25Smrg    long addr = (0x80000000 |
11604007ebaSmrg                 ((bus & 0xff) << 16) |
11704007ebaSmrg                 ((dev & 0x1f) << 11) | ((func & 0x7) << 8) | (address & 0xff));
118f29dbc25Smrg    OUTD(PCI_INDEX, addr);
119f29dbc25Smrg    *data = IND(PCI_DATA);
120f29dbc25Smrg}
121f29dbc25Smrg
122f29dbc25Smrg/*---------------------------------------------------------------------------
123f29dbc25Smrg *	sio_set_index_data_reg
124f29dbc25Smrg *
125f29dbc25Smrg *	This routine checks which index and data registers to use
126f29dbc25Smrg *  in order to access the Super I/O registers
127f29dbc25Smrg *
128f29dbc25Smrg *	Returns : 1 - OK
129f29dbc25Smrg *            0 - Super I/O disabled or configuration access disabled
130f29dbc25Smrg *---------------------------------------------------------------------------
131f29dbc25Smrg */
132f29dbc25Smrgint
133f29dbc25Smrgsio_set_index_data_reg(void)
134f29dbc25Smrg{
135f29dbc25Smrg    unsigned long xbus_expention_bar, io_control_reg1;
136f29dbc25Smrg
137f29dbc25Smrg    OsPciReadDWord(0, 0x12, 5, 0x10, &xbus_expention_bar);
138f29dbc25Smrg    xbus_expention_bar = xbus_expention_bar & 0xfffffffe;
13904007ebaSmrg    io_control_reg1 = IND((unsigned short) xbus_expention_bar);
140f29dbc25Smrg
141f29dbc25Smrg    if ((io_control_reg1) & (SIO_BASE_ADR_15C_15D)) {
142f29dbc25Smrg        index_reg = INDEX_1;
143f29dbc25Smrg        data_reg = DATA_1;
144f29dbc25Smrg        return (1);
145f29dbc25Smrg    }
146f29dbc25Smrg
147f29dbc25Smrg    if ((io_control_reg1) & (SIO_BASE_ADR_2E_2F)) {
148f29dbc25Smrg        index_reg = INDEX_2;
149f29dbc25Smrg        data_reg = DATA_2;
150f29dbc25Smrg        return (1);
151f29dbc25Smrg    }
152f29dbc25Smrg
153f29dbc25Smrg    return (0);
154f29dbc25Smrg}
155f29dbc25Smrg
156f29dbc25Smrg/*---------------------------------------------------------------------------
157f29dbc25Smrg *	sio_write_reg
158f29dbc25Smrg *
159f29dbc25Smrg *	This routine writes 'data' to 'reg' Super I/O register
160f29dbc25Smrg *
161f29dbc25Smrg *	Returns : None
162f29dbc25Smrg *---------------------------------------------------------------------------
163f29dbc25Smrg */
164f29dbc25Smrgvoid
165f29dbc25Smrgsio_write_reg(unsigned char reg, unsigned char data)
166f29dbc25Smrg{
167f29dbc25Smrg    OUTB(index_reg, reg);
168f29dbc25Smrg    OUTB(data_reg, data);
169f29dbc25Smrg}
170f29dbc25Smrg
171f29dbc25Smrg/*---------------------------------------------------------------------------
172f29dbc25Smrg *	sio_read_reg
173f29dbc25Smrg *
174f29dbc25Smrg *	This routine reads data from 'reg' Super I/O register
175f29dbc25Smrg *
176f29dbc25Smrg *	Returns : The data read from the requested register
177f29dbc25Smrg *---------------------------------------------------------------------------
178f29dbc25Smrg */
179f29dbc25Smrgunsigned char
180f29dbc25Smrgsio_read_reg(unsigned char reg)
181f29dbc25Smrg{
182f29dbc25Smrg    OUTB(index_reg, reg);
183f29dbc25Smrg    return INB(data_reg);
184f29dbc25Smrg}
185f29dbc25Smrg
186f29dbc25Smrg/*---------------------------------------------------------------------------
187f29dbc25Smrg *	gfx_i2c_reset
188f29dbc25Smrg *
189f29dbc25Smrg *	This routine resets the I2C bus as follows :
19079d5fcd7Smrg *	· Sets the base address of the ACCESS.bus
19179d5fcd7Smrg *	· Sets the frequency of the ACCESS.bus
19279d5fcd7Smrg *	· Resets the ACCESS.bus
193f29dbc25Smrg *
194f29dbc25Smrg * 	If 'adr'  is -1 the address is read from the hardware.
195f29dbc25Smrg *	If 'freq' is -1 the frequency is set to 56 clock cycles.
196f29dbc25Smrg *---------------------------------------------------------------------------
197f29dbc25Smrg */
198f29dbc25Smrg#if GFX_I2C_DYNAMIC
199f29dbc25Smrgint
200f29dbc25Smrgacc_i2c_reset(unsigned char busnum, short adr, char freq)
201f29dbc25Smrg#else
202f29dbc25Smrgint
203f29dbc25Smrggfx_i2c_reset(unsigned char busnum, short adr, char freq)
204f29dbc25Smrg#endif
205f29dbc25Smrg{
206f29dbc25Smrg    if ((busnum != 1) && (busnum != 2))
207f29dbc25Smrg        return GFX_STATUS_BAD_PARAMETER;
208f29dbc25Smrg    acc_i2c_config(busnum, adr, freq);
209f29dbc25Smrg    if (base_address_array[busnum] == 0)
210f29dbc25Smrg        return GFX_STATUS_ERROR;
211f29dbc25Smrg    acc_i2c_reset_bus(busnum);
212f29dbc25Smrg    return GFX_STATUS_OK;
213f29dbc25Smrg}
214f29dbc25Smrg
215f29dbc25Smrg/*---------------------------------------------------------------------------
216f29dbc25Smrg * gfx_i2c_select_gpio
217f29dbc25Smrg *
218f29dbc25Smrg * This routine selects which GPIO pins to use.
219f29dbc25Smrg *---------------------------------------------------------------------------
220f29dbc25Smrg */
221f29dbc25Smrg#if GFX_I2C_DYNAMIC
222f29dbc25Smrgint
223f29dbc25Smrgacc_i2c_select_gpio(int clock, int data)
224f29dbc25Smrg#else
225f29dbc25Smrgint
226f29dbc25Smrggfx_i2c_select_gpio(int clock, int data)
227f29dbc25Smrg#endif
228f29dbc25Smrg{
229f29dbc25Smrg    /* THIS ROUTINE DOES NOT APPLY TO THE ACCESS.bus IMPLEMENTATION. */
230f29dbc25Smrg
231f29dbc25Smrg    return (GFX_STATUS_OK);
232f29dbc25Smrg}
233f29dbc25Smrg
234f29dbc25Smrg/*---------------------------------------------------------------------------
235f29dbc25Smrg *	gfx_i2c_write
236f29dbc25Smrg *
237f29dbc25Smrg *	This routine writes data to the specified I2C address.
238f29dbc25Smrg *  busnum - ACCESS.bus number (1 or 2).
239f29dbc25Smrg *---------------------------------------------------------------------------
240f29dbc25Smrg */
241f29dbc25Smrg#if GFX_I2C_DYNAMIC
242f29dbc25Smrgint
243f29dbc25Smrgacc_i2c_write(unsigned char busnum, unsigned char chipadr,
24404007ebaSmrg              unsigned char subadr, unsigned char bytes, unsigned char *data)
245f29dbc25Smrg#else
246f29dbc25Smrgint
247f29dbc25Smrggfx_i2c_write(unsigned char busnum, unsigned char chipadr,
24804007ebaSmrg              unsigned char subadr, unsigned char bytes, unsigned char *data)
249f29dbc25Smrg#endif
250f29dbc25Smrg{
251f29dbc25Smrg    int loop = 0;
252f29dbc25Smrg
253f29dbc25Smrg    if ((busnum != 1) && (busnum != 2))
254f29dbc25Smrg        return GFX_STATUS_BAD_PARAMETER;
255f29dbc25Smrg
256f29dbc25Smrg    /* REQUEST MASTER */
257f29dbc25Smrg
258f29dbc25Smrg    if (!acc_i2c_request_master(busnum))
259f29dbc25Smrg        return (GFX_STATUS_ERROR);
260f29dbc25Smrg
261f29dbc25Smrg    /* WRITE ADDRESS COMMAND */
262f29dbc25Smrg
263f29dbc25Smrg    acc_i2c_ack(busnum, 1, 0);
264f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 1);
26504007ebaSmrg    acc_i2c_send_address(busnum, (unsigned char) (chipadr & 0xFE));
266f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 0);
267f29dbc25Smrg    if (!acc_i2c_ack(busnum, 0, 0))
268f29dbc25Smrg        return (GFX_STATUS_ERROR);
269f29dbc25Smrg
270f29dbc25Smrg    /* WRITE COMMAND */
271f29dbc25Smrg
272f29dbc25Smrg    acc_i2c_write_byte(busnum, subadr);
273f29dbc25Smrg    if (!acc_i2c_ack(busnum, 0, 0))
274f29dbc25Smrg        return (GFX_STATUS_ERROR);
275f29dbc25Smrg
276f29dbc25Smrg    /* WRITE DATA */
277f29dbc25Smrg
278f29dbc25Smrg    for (loop = 0; loop < bytes; loop++) {
279f29dbc25Smrg        acc_i2c_write_byte(busnum, *data);
280f29dbc25Smrg        if (loop < (bytes - 1))
281f29dbc25Smrg            data += sizeof(unsigned char);
282f29dbc25Smrg        if (!acc_i2c_ack(busnum, 0, 0))
283f29dbc25Smrg            return (GFX_STATUS_ERROR);
284f29dbc25Smrg    }
285f29dbc25Smrg    data -= (bytes - 1);
286f29dbc25Smrg    acc_i2c_stop(busnum);
287f29dbc25Smrg
288f29dbc25Smrg    return GFX_STATUS_OK;
289f29dbc25Smrg}
290f29dbc25Smrg
291f29dbc25Smrg/*---------------------------------------------------------------------------
292f29dbc25Smrg *	gfx_i2c_read
293f29dbc25Smrg *
294f29dbc25Smrg *	This routine reads data from the specified I2C address.
295f29dbc25Smrg *  busnum - ACCESS.bus number (1 or 2).
296f29dbc25Smrg *---------------------------------------------------------------------------
297f29dbc25Smrg */
298f29dbc25Smrg#if GFX_I2C_DYNAMIC
299f29dbc25Smrgint
300f29dbc25Smrgacc_i2c_read(unsigned char busnum, unsigned char chipadr,
30104007ebaSmrg             unsigned char subadr, unsigned char bytes, unsigned char *data)
302f29dbc25Smrg#else
303f29dbc25Smrgint
304f29dbc25Smrggfx_i2c_read(unsigned char busnum, unsigned char chipadr,
30504007ebaSmrg             unsigned char subadr, unsigned char bytes, unsigned char *data)
306f29dbc25Smrg#endif
307f29dbc25Smrg{
308f29dbc25Smrg    unsigned char bytesRead;
309f29dbc25Smrg
310f29dbc25Smrg    if ((busnum != 1) && (busnum != 2))
311f29dbc25Smrg        return GFX_STATUS_BAD_PARAMETER;
312f29dbc25Smrg
313f29dbc25Smrg    if (bytes == 0)
314f29dbc25Smrg        return GFX_STATUS_OK;
315f29dbc25Smrg
316f29dbc25Smrg    /* REQUEST MASTER */
317f29dbc25Smrg
318f29dbc25Smrg    if (!acc_i2c_request_master(busnum))
319f29dbc25Smrg        return (GFX_STATUS_ERROR);
320f29dbc25Smrg
321f29dbc25Smrg    /* WRITE ADDRESS COMMAND */
322f29dbc25Smrg
323f29dbc25Smrg    acc_i2c_ack(busnum, 1, 0);
324f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 1);
32504007ebaSmrg    acc_i2c_send_address(busnum, (unsigned char) (chipadr & 0xFE));
326f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 0);
327f29dbc25Smrg    if (!acc_i2c_ack(busnum, 0, 0))
328f29dbc25Smrg        return (GFX_STATUS_ERROR);
329f29dbc25Smrg
330f29dbc25Smrg    /* WRITE COMMAND */
331f29dbc25Smrg
332f29dbc25Smrg    acc_i2c_write_byte(busnum, subadr);
333f29dbc25Smrg    if (!acc_i2c_ack(busnum, 0, 0))
334f29dbc25Smrg        return (GFX_STATUS_ERROR);
335f29dbc25Smrg
336f29dbc25Smrg    /* START THE READ */
337f29dbc25Smrg
338f29dbc25Smrg    acc_i2c_start(busnum);
339f29dbc25Smrg
340f29dbc25Smrg    /* WRITE ADDRESS COMMAND */
341f29dbc25Smrg
342f29dbc25Smrg    acc_i2c_ack(busnum, 1, 1);
343f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 1);
34404007ebaSmrg    acc_i2c_send_address(busnum, (unsigned char) (chipadr | 0x01));
345f29dbc25Smrg
346f29dbc25Smrg    /* IF LAST BYTE */
347f29dbc25Smrg
348f29dbc25Smrg    if (bytes == 1)
349f29dbc25Smrg        acc_i2c_ack(busnum, 1, 1);
350f29dbc25Smrg    else
351f29dbc25Smrg        acc_i2c_ack(busnum, 1, 0);
352f29dbc25Smrg
353f29dbc25Smrg    acc_i2c_stall_after_start(busnum, 0);
354f29dbc25Smrg
355f29dbc25Smrg    if (!acc_i2c_ack(busnum, 0, 0))
356f29dbc25Smrg        return (GFX_STATUS_ERROR);
357f29dbc25Smrg
358f29dbc25Smrg    /* READ COMMAND */
359f29dbc25Smrg
360f29dbc25Smrg    for (bytesRead = 0; bytesRead < bytes; bytesRead += 1) {
361f29dbc25Smrg        if (bytesRead < (bytes - 2)) {
362f29dbc25Smrg            data[bytesRead] = acc_i2c_read_byte(busnum, 0);
363f29dbc25Smrg            acc_i2c_ack(busnum, 1, 0);
36404007ebaSmrg        }
36504007ebaSmrg        else if (bytesRead == (bytes - 2)) {    /* TWO BYTES LEFT */
366f29dbc25Smrg            acc_i2c_ack(busnum, 1, 1);
367f29dbc25Smrg            data[bytesRead] = acc_i2c_read_byte(busnum, 0);
368f29dbc25Smrg            acc_i2c_ack(busnum, 1, 1);
36904007ebaSmrg        }
37004007ebaSmrg        else {                  /* LAST BYTE */
371f29dbc25Smrg
372f29dbc25Smrg            data[bytesRead] = acc_i2c_read_byte(busnum, 1);
373f29dbc25Smrg            acc_i2c_stop(busnum);
374f29dbc25Smrg        }
375f29dbc25Smrg
376f29dbc25Smrg        /* WHILE NOT LAST BYTE */
377f29dbc25Smrg
378f29dbc25Smrg        if ((!(bytesRead == (bytes - 1))) && (!acc_i2c_ack(busnum, 0, 0)))
379f29dbc25Smrg            return (bytesRead);
380f29dbc25Smrg    }
381f29dbc25Smrg
382f29dbc25Smrg    return GFX_STATUS_OK;
383f29dbc25Smrg}
384f29dbc25Smrg
385f29dbc25Smrg/*---------------------------------------------------------------------------
386f29dbc25Smrg * gfx_i2c_init
387f29dbc25Smrg *
388f29dbc25Smrg * This routine initializes the use of the ACCESS.BUS.
389f29dbc25Smrg *---------------------------------------------------------------------------
390f29dbc25Smrg */
391f29dbc25Smrg#if GFX_I2C_DYNAMIC
392f29dbc25Smrgint
393f29dbc25Smrgacc_i2c_init(void)
394f29dbc25Smrg#else
395f29dbc25Smrgint
396f29dbc25Smrggfx_i2c_init(void)
397f29dbc25Smrg#endif
398f29dbc25Smrg{
399f29dbc25Smrg    /* ### ADD ### THIS ROUTINE IS NOT YET IMPLEMENTED FOR ACCESS.bus */
400f29dbc25Smrg    return (GFX_STATUS_OK);
401f29dbc25Smrg}
402f29dbc25Smrg
403f29dbc25Smrg/*---------------------------------------------------------------------------
404f29dbc25Smrg * gfx_i2c_cleanup
405f29dbc25Smrg *
406f29dbc25Smrg * This routine ends the use of the ACCESS.BUS.
407f29dbc25Smrg *---------------------------------------------------------------------------
408f29dbc25Smrg */
409f29dbc25Smrg#if GFX_I2C_DYNAMIC
410f29dbc25Smrgvoid
411f29dbc25Smrgacc_i2c_cleanup(void)
412f29dbc25Smrg#else
413f29dbc25Smrgvoid
414f29dbc25Smrggfx_i2c_cleanup(void)
415f29dbc25Smrg#endif
416f29dbc25Smrg{
417f29dbc25Smrg    /* ### ADD ### THIS ROUTINE IS NOT YET IMPLEMENTED FOR ACCESS.bus */
418f29dbc25Smrg}
419f29dbc25Smrg
420f29dbc25Smrg/*--------------------------------------------------------*/
421f29dbc25Smrg/*  LOCAL ROUTINES SPECIFIC TO ACCESS.bus IMPLEMENTATION  */
422f29dbc25Smrg/*--------------------------------------------------------*/
423f29dbc25Smrg
424f29dbc25Smrg/*---------------------------------------------------------------------------
425f29dbc25Smrg * acc_i2c_reset_bus
426f29dbc25Smrg *
427f29dbc25Smrg * This routine resets the I2C bus.
428f29dbc25Smrg *---------------------------------------------------------------------------
429f29dbc25Smrg */
430f29dbc25Smrgvoid
431f29dbc25Smrgacc_i2c_reset_bus(unsigned char busnum)
432f29dbc25Smrg{
433f29dbc25Smrg    unsigned char reg;
434f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
435f29dbc25Smrg
436f29dbc25Smrg    /* Disable the ACCESS.bus device and */
437f29dbc25Smrg    /* Configure the SCL frequency */
43804007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2),
43904007ebaSmrg         (unsigned char) (Freq & 0xFE));
440f29dbc25Smrg
441f29dbc25Smrg    /* Configure no interrupt mode (polling) and */
442f29dbc25Smrg    /* Disable global call address */
44304007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL1), 0x0);
444f29dbc25Smrg
445f29dbc25Smrg    /* Disable slave address */
44604007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBADDR), 0x0);
447f29dbc25Smrg
448f29dbc25Smrg    /* Enable the ACCESS.bus device */
44904007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL2));
450f29dbc25Smrg    reg |= 0x01;
45104007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2), reg);
452f29dbc25Smrg
453f29dbc25Smrg    /* Issue STOP event */
454f29dbc25Smrg
455f29dbc25Smrg    acc_i2c_stop(busnum);
456f29dbc25Smrg
457f29dbc25Smrg    /* Clear NEGACK, STASTR and BER bits */
45804007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBST), 0x38);
459f29dbc25Smrg
460f29dbc25Smrg    /* Clear BB (BUS BUSY) bit */
46104007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCST));
462f29dbc25Smrg    reg |= 0x02;
46304007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCST), reg);
464f29dbc25Smrg}
465f29dbc25Smrg
466f29dbc25Smrg/*---------------------------------------------------------------------------
467f29dbc25Smrg * acc_i2c_start
468f29dbc25Smrg *
469f29dbc25Smrg * This routine starts a transfer on the I2C bus.
470f29dbc25Smrg *---------------------------------------------------------------------------
471f29dbc25Smrg */
472f29dbc25Smrgvoid
473f29dbc25Smrgacc_i2c_start(unsigned char busnum)
474f29dbc25Smrg{
475f29dbc25Smrg    unsigned char reg;
476f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
477f29dbc25Smrg
47804007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL1));
479f29dbc25Smrg    reg |= 0x01;
48004007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
481f29dbc25Smrg}
482f29dbc25Smrg
483f29dbc25Smrg/*---------------------------------------------------------------------------
484f29dbc25Smrg * acc_i2c_stop
485f29dbc25Smrg *
486f29dbc25Smrg * This routine stops a transfer on the I2C bus.
487f29dbc25Smrg *---------------------------------------------------------------------------
488f29dbc25Smrg */
489f29dbc25Smrgvoid
490f29dbc25Smrgacc_i2c_stop(unsigned char busnum)
491f29dbc25Smrg{
492f29dbc25Smrg    unsigned char reg;
493f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
494f29dbc25Smrg
49504007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL1));
496f29dbc25Smrg    reg |= 0x02;
49704007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
498f29dbc25Smrg}
499f29dbc25Smrg
500f29dbc25Smrg/*---------------------------------------------------------------------------
501f29dbc25Smrg * acc_i2c_abort_data
502f29dbc25Smrg *---------------------------------------------------------------------------
503f29dbc25Smrg */
504f29dbc25Smrgvoid
505f29dbc25Smrgacc_i2c_abort_data(unsigned char busnum)
506f29dbc25Smrg{
507f29dbc25Smrg    unsigned char reg;
508f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
509f29dbc25Smrg
510f29dbc25Smrg    acc_i2c_stop(busnum);
51104007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL1));
512f29dbc25Smrg    reg |= 0x10;
51304007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
514f29dbc25Smrg}
515f29dbc25Smrg
516f29dbc25Smrg/*---------------------------------------------------------------------------
517f29dbc25Smrg * acc_i2c_bus_recovery
518f29dbc25Smrg *---------------------------------------------------------------------------
519f29dbc25Smrg */
520f29dbc25Smrgvoid
521f29dbc25Smrgacc_i2c_bus_recovery(unsigned char busnum)
522f29dbc25Smrg{
523f29dbc25Smrg    acc_i2c_abort_data(busnum);
524f29dbc25Smrg    acc_i2c_reset_bus(busnum);
525f29dbc25Smrg}
526f29dbc25Smrg
527f29dbc25Smrg/*---------------------------------------------------------------------------
528f29dbc25Smrg * acc_i2c_stall_after_start
529f29dbc25Smrg *---------------------------------------------------------------------------
530f29dbc25Smrg */
531f29dbc25Smrgvoid
532f29dbc25Smrgacc_i2c_stall_after_start(unsigned char busnum, int state)
533f29dbc25Smrg{
534f29dbc25Smrg    unsigned char reg;
535f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
536f29dbc25Smrg
53704007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL1));
538f29dbc25Smrg    if (state)
539f29dbc25Smrg        reg |= 0x80;
540f29dbc25Smrg    else
541f29dbc25Smrg        reg &= 0x7F;
54204007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
543f29dbc25Smrg
544f29dbc25Smrg    if (!state) {
54504007ebaSmrg        reg = INB((unsigned short) (bus_base_address + ACBST));
546f29dbc25Smrg        reg |= 0x08;
54704007ebaSmrg        OUTB((unsigned short) (bus_base_address + ACBST), reg);
548f29dbc25Smrg    }
549f29dbc25Smrg}
550f29dbc25Smrg
551f29dbc25Smrg/*---------------------------------------------------------------------------
552f29dbc25Smrg * acc_i2c_send_address
553f29dbc25Smrg *---------------------------------------------------------------------------
554f29dbc25Smrg */
555f29dbc25Smrgvoid
556f29dbc25Smrgacc_i2c_send_address(unsigned char busnum, unsigned char cData)
557f29dbc25Smrg{
558f29dbc25Smrg    unsigned char reg;
559f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
560f29dbc25Smrg    unsigned long timeout = 0;
561f29dbc25Smrg
562f29dbc25Smrg    /* WRITE THE DATA */
563f29dbc25Smrg
56404007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBSDA), cData);
565f29dbc25Smrg    while (1) {
56604007ebaSmrg        reg = INB((unsigned short) (bus_base_address + ACBST));
56704007ebaSmrg        if ((reg & 0x38) != 0)  /* check STASTR, BER and NEGACK */
568f29dbc25Smrg            break;
569f29dbc25Smrg        if (timeout++ == ACC_I2C_TIMEOUT) {
570f29dbc25Smrg            acc_i2c_bus_recovery(busnum);
571f29dbc25Smrg            return;
572f29dbc25Smrg        }
573f29dbc25Smrg    }
574f29dbc25Smrg
575f29dbc25Smrg    /* CHECK FOR BUS ERROR */
576f29dbc25Smrg
577f29dbc25Smrg    if (reg & 0x20) {
578f29dbc25Smrg        acc_i2c_bus_recovery(busnum);
579f29dbc25Smrg        return;
580f29dbc25Smrg    }
581f29dbc25Smrg
582f29dbc25Smrg    /* CHECK NEGATIVE ACKNOWLEDGE */
583f29dbc25Smrg
584f29dbc25Smrg    if (reg & 0x10) {
585f29dbc25Smrg        acc_i2c_abort_data(busnum);
586f29dbc25Smrg        return;
587f29dbc25Smrg    }
588f29dbc25Smrg
589f29dbc25Smrg}
590f29dbc25Smrg
591f29dbc25Smrg/*---------------------------------------------------------------------------
592f29dbc25Smrg * acc_i2c_ack
593f29dbc25Smrg *
594f29dbc25Smrg * This routine looks for acknowledge on the I2C bus.
595f29dbc25Smrg *---------------------------------------------------------------------------
596f29dbc25Smrg */
597f29dbc25Smrgint
598f29dbc25Smrgacc_i2c_ack(unsigned char busnum, int fPut, int negAck)
599f29dbc25Smrg{
600f29dbc25Smrg    unsigned char reg;
601f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
602f29dbc25Smrg    unsigned long timeout = 0;
603f29dbc25Smrg
60404007ebaSmrg    if (fPut) {                 /* read operation */
605f29dbc25Smrg        if (!negAck) {
606f29dbc25Smrg            /* Push Ack onto I2C bus */
60704007ebaSmrg            reg = INB((unsigned short) (bus_base_address + ACBCTL1));
608f29dbc25Smrg            reg &= 0xE7;
60904007ebaSmrg            OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
61004007ebaSmrg        }
61104007ebaSmrg        else {
612f29dbc25Smrg            /* Push negAck onto I2C bus */
61304007ebaSmrg            reg = INB((unsigned short) (bus_base_address + ACBCTL1));
614f29dbc25Smrg            reg |= 0x10;
61504007ebaSmrg            OUTB((unsigned short) (bus_base_address + ACBCTL1), reg);
616f29dbc25Smrg        }
61704007ebaSmrg    }
61804007ebaSmrg    else {                      /* write operation */
619f29dbc25Smrg        /* Receive Ack from I2C bus */
620f29dbc25Smrg        while (1) {
62104007ebaSmrg            reg = INB((unsigned short) (bus_base_address + ACBST));
62204007ebaSmrg            if ((reg & 0x70) != 0)      /* check SDAST, BER and NEGACK */
623f29dbc25Smrg                break;
624f29dbc25Smrg            if (timeout++ == ACC_I2C_TIMEOUT) {
625f29dbc25Smrg                acc_i2c_bus_recovery(busnum);
626f29dbc25Smrg                return (0);
627f29dbc25Smrg            }
628f29dbc25Smrg        }
629f29dbc25Smrg
630f29dbc25Smrg        /* CHECK FOR BUS ERROR */
631f29dbc25Smrg
632f29dbc25Smrg        if (reg & 0x20) {
633f29dbc25Smrg            acc_i2c_bus_recovery(busnum);
634f29dbc25Smrg            return (0);
635f29dbc25Smrg        }
636f29dbc25Smrg
637f29dbc25Smrg        /* CHECK NEGATIVE ACKNOWLEDGE */
638f29dbc25Smrg
639f29dbc25Smrg        if (reg & 0x10) {
640f29dbc25Smrg            acc_i2c_abort_data(busnum);
641f29dbc25Smrg            return (0);
642f29dbc25Smrg        }
643f29dbc25Smrg    }
644f29dbc25Smrg    return (1);
645f29dbc25Smrg}
646f29dbc25Smrg
647f29dbc25Smrg/*---------------------------------------------------------------------------
648f29dbc25Smrg * acc_i2c_stop_clock
649f29dbc25Smrg *
650f29dbc25Smrg * This routine stops the ACCESS.bus clock.
651f29dbc25Smrg *---------------------------------------------------------------------------
652f29dbc25Smrg */
653f29dbc25Smrgvoid
654f29dbc25Smrgacc_i2c_stop_clock(unsigned char busnum)
655f29dbc25Smrg{
656f29dbc25Smrg    unsigned char reg;
657f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
658f29dbc25Smrg
65904007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL2));
660f29dbc25Smrg    reg &= ~0x01;
66104007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2), reg);
662f29dbc25Smrg}
663f29dbc25Smrg
664f29dbc25Smrg/*---------------------------------------------------------------------------
665f29dbc25Smrg * acc_i2c_activate_clock
666f29dbc25Smrg *
667f29dbc25Smrg * This routine activates the ACCESS.bus clock.
668f29dbc25Smrg *---------------------------------------------------------------------------
669f29dbc25Smrg */
670f29dbc25Smrgvoid
671f29dbc25Smrgacc_i2c_activate_clock(unsigned char busnum)
672f29dbc25Smrg{
673f29dbc25Smrg    unsigned char reg;
674f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
675f29dbc25Smrg
67604007ebaSmrg    reg = INB((unsigned short) (bus_base_address + ACBCTL2));
677f29dbc25Smrg    reg |= 0x01;
67804007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2), reg);
679f29dbc25Smrg}
680f29dbc25Smrg
681f29dbc25Smrg/*---------------------------------------------------------------------------
682f29dbc25Smrg * acc_i2c_write_byte
683f29dbc25Smrg *
684f29dbc25Smrg * This routine writes a byte to the I2C bus
685f29dbc25Smrg *---------------------------------------------------------------------------
686f29dbc25Smrg */
687f29dbc25Smrgvoid
688f29dbc25Smrgacc_i2c_write_byte(unsigned char busnum, unsigned char cData)
689f29dbc25Smrg{
690f29dbc25Smrg    unsigned char reg;
691f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
692f29dbc25Smrg    unsigned long timeout = 0;
693f29dbc25Smrg
694f29dbc25Smrg    while (1) {
69504007ebaSmrg        reg = INB((unsigned short) (bus_base_address + ACBST));
696f29dbc25Smrg        if (reg & 0x70)
697f29dbc25Smrg            break;
698f29dbc25Smrg        if (timeout++ == ACC_I2C_TIMEOUT) {
699f29dbc25Smrg            acc_i2c_bus_recovery(busnum);
700f29dbc25Smrg            return;
701f29dbc25Smrg        }
702f29dbc25Smrg    }
703f29dbc25Smrg
704f29dbc25Smrg    /* CHECK FOR BUS ERROR */
705f29dbc25Smrg
706f29dbc25Smrg    if (reg & 0x20) {
707f29dbc25Smrg        acc_i2c_bus_recovery(busnum);
708f29dbc25Smrg        return;
709f29dbc25Smrg    }
710f29dbc25Smrg
711f29dbc25Smrg    /* CHECK NEGATIVE ACKNOWLEDGE */
712f29dbc25Smrg
713f29dbc25Smrg    if (reg & 0x10) {
714f29dbc25Smrg        acc_i2c_abort_data(busnum);
715f29dbc25Smrg        return;
716f29dbc25Smrg    }
717f29dbc25Smrg
718f29dbc25Smrg    /* WRITE THE DATA */
719f29dbc25Smrg
72004007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBSDA), cData);
721f29dbc25Smrg}
722f29dbc25Smrg
723f29dbc25Smrg/*---------------------------------------------------------------------------
724f29dbc25Smrg * acc_i2c_read_byte
725f29dbc25Smrg *
726f29dbc25Smrg * This routine reads a byte from the I2C bus
727f29dbc25Smrg *---------------------------------------------------------------------------
728f29dbc25Smrg */
729f29dbc25Smrgunsigned char
730f29dbc25Smrgacc_i2c_read_byte(unsigned char busnum, int last_byte)
731f29dbc25Smrg{
732f29dbc25Smrg    unsigned char cData, reg;
733f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
734f29dbc25Smrg    unsigned long timeout = 0;
735f29dbc25Smrg
736f29dbc25Smrg    while (1) {
73704007ebaSmrg        reg = INB((unsigned short) (bus_base_address + ACBST));
738f29dbc25Smrg        if (reg & 0x60)
739f29dbc25Smrg            break;
740f29dbc25Smrg        if (timeout++ == ACC_I2C_TIMEOUT) {
741f29dbc25Smrg            acc_i2c_bus_recovery(busnum);
742f29dbc25Smrg            return (0xEF);
743f29dbc25Smrg        }
744f29dbc25Smrg    }
745f29dbc25Smrg
746f29dbc25Smrg    /* CHECK FOR BUS ERROR */
747f29dbc25Smrg
748f29dbc25Smrg    if (reg & 0x20) {
749f29dbc25Smrg        acc_i2c_bus_recovery(busnum);
750f29dbc25Smrg        return (0xEE);
751f29dbc25Smrg    }
752f29dbc25Smrg
753f29dbc25Smrg    /* READ DATA */
754f29dbc25Smrg    if (last_byte)
755f29dbc25Smrg        acc_i2c_stop_clock(busnum);
75604007ebaSmrg    cData = INB((unsigned short) (bus_base_address + ACBSDA));
757f29dbc25Smrg    if (last_byte)
758f29dbc25Smrg        acc_i2c_activate_clock(busnum);
759f29dbc25Smrg
760f29dbc25Smrg    return (cData);
761f29dbc25Smrg}
762f29dbc25Smrg
763f29dbc25Smrg/*---------------------------------------------------------------------------
764f29dbc25Smrg * acc_i2c_request_master
765f29dbc25Smrg *---------------------------------------------------------------------------
766f29dbc25Smrg */
767f29dbc25Smrgint
768f29dbc25Smrgacc_i2c_request_master(unsigned char busnum)
769f29dbc25Smrg{
770f29dbc25Smrg    unsigned char reg;
771f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
772f29dbc25Smrg    unsigned long timeout = 0;
773f29dbc25Smrg
774f29dbc25Smrg    acc_i2c_start(busnum);
775f29dbc25Smrg    while (1) {
77604007ebaSmrg        reg = INB((unsigned short) (bus_base_address + ACBST));
777f29dbc25Smrg        if (reg & 0x60)
778f29dbc25Smrg            break;
779f29dbc25Smrg        if (timeout++ == ACC_I2C_TIMEOUT) {
780f29dbc25Smrg            acc_i2c_bus_recovery(busnum);
781f29dbc25Smrg            return (0);
782f29dbc25Smrg        }
783f29dbc25Smrg    }
784f29dbc25Smrg
785f29dbc25Smrg    /* CHECK FOR BUS ERROR */
786f29dbc25Smrg
787f29dbc25Smrg    if (reg & 0x20) {
788f29dbc25Smrg        acc_i2c_abort_data(busnum);
789f29dbc25Smrg        return (0);
790f29dbc25Smrg    }
791f29dbc25Smrg
792f29dbc25Smrg    /* CHECK NEGATIVE ACKNOWLEDGE */
793f29dbc25Smrg
794f29dbc25Smrg    if (reg & 0x10) {
795f29dbc25Smrg        acc_i2c_abort_data(busnum);
796f29dbc25Smrg        return (0);
797f29dbc25Smrg    }
798f29dbc25Smrg    return (1);
799f29dbc25Smrg}
800f29dbc25Smrg
801f29dbc25Smrg/*--------------------------------------------------------*/
802f29dbc25Smrg/*  LOCAL ROUTINES SPECIFIC TO ACCESS.bus INITIALIZATION  */
803f29dbc25Smrg/*--------------------------------------------------------*/
804f29dbc25Smrg
805f29dbc25Smrg/*----------------------------------------------------------------------------
806f29dbc25Smrg * acc_i2c_config
807f29dbc25Smrg *
808f29dbc25Smrg * This routine configures the I2C bus
809f29dbc25Smrg *----------------------------------------------------------------------------
810f29dbc25Smrg */
811f29dbc25Smrgvoid
812f29dbc25Smrgacc_i2c_config(unsigned char busnum, short adr, char freq)
813f29dbc25Smrg{
814f29dbc25Smrg    base_address_array[busnum] = acc_i2c_set_base_address(busnum, adr);
815f29dbc25Smrg    Freq = acc_i2c_set_freq(busnum, freq);
816f29dbc25Smrg}
817f29dbc25Smrg
818f29dbc25Smrg/*----------------------------------------------------------------------------
819f29dbc25Smrg * acc_i2c_set_freq
820f29dbc25Smrg *
821f29dbc25Smrg * This routine sets the frequency of the I2C bus
822f29dbc25Smrg *----------------------------------------------------------------------------
823f29dbc25Smrg */
824f29dbc25Smrgchar
825f29dbc25Smrgacc_i2c_set_freq(unsigned char busnum, char freq)
826f29dbc25Smrg{
827f29dbc25Smrg    unsigned short bus_base_address = base_address_array[busnum];
828f29dbc25Smrg
82904007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2), 0x0);
830f29dbc25Smrg
831f29dbc25Smrg    if (freq == -1)
832f29dbc25Smrg        freq = 0x71;
833f29dbc25Smrg    else {
834f29dbc25Smrg        freq = freq << 1;
835f29dbc25Smrg        freq |= 0x01;
836f29dbc25Smrg    }
837f29dbc25Smrg
83804007ebaSmrg    OUTB((unsigned short) (bus_base_address + ACBCTL2), freq);
839f29dbc25Smrg    return (freq);
840f29dbc25Smrg}
841f29dbc25Smrg
842f29dbc25Smrg/*---------------------------------------------------------------------------
843f29dbc25Smrg * acc_i2c_set_base_address
844f29dbc25Smrg *
845f29dbc25Smrg * This routine sets the base address of the I2C bus
846f29dbc25Smrg *---------------------------------------------------------------------------
847f29dbc25Smrg */
848f29dbc25Smrgunsigned short
849f29dbc25Smrgacc_i2c_set_base_address(unsigned char busnum, short adr)
850f29dbc25Smrg{
851f29dbc25Smrg    unsigned short ab_base_addr;
852f29dbc25Smrg
853f29dbc25Smrg    /* Get Super I/O Index and Data registers */
854f29dbc25Smrg    if (!sio_set_index_data_reg())
855f29dbc25Smrg        return (0);
856f29dbc25Smrg
857f29dbc25Smrg    /* Configure LDN to current ACB */
858f29dbc25Smrg    if (busnum == 1)
859f29dbc25Smrg        sio_write_reg(LDN, ACB1_LDN);
860f29dbc25Smrg    if (busnum == 2)
861f29dbc25Smrg        sio_write_reg(LDN, ACB2_LDN);
862f29dbc25Smrg
863f29dbc25Smrg    if (adr == -1) {
864f29dbc25Smrg        /* Get ACCESS.bus base address */
865f29dbc25Smrg        ab_base_addr = sio_read_reg(BASE_ADR_MSB_REG);
866f29dbc25Smrg        ab_base_addr = ab_base_addr << 8;
867f29dbc25Smrg        ab_base_addr |= sio_read_reg(BASE_ADR_LSB_REG);
868f29dbc25Smrg        if (ab_base_addr != 0)
869f29dbc25Smrg            return ab_base_addr;
870f29dbc25Smrg        else
871f29dbc25Smrg            adr = (busnum == 1 ? ACB1_BASE : ACB2_BASE);
872f29dbc25Smrg    }
873f29dbc25Smrg
874f29dbc25Smrg    /* Set ACCESS.bus base address */
87504007ebaSmrg    sio_write_reg(BASE_ADR_LSB_REG, (unsigned char) (adr & 0xFF));
87604007ebaSmrg    sio_write_reg(BASE_ADR_MSB_REG, (unsigned char) (adr >> 8));
877f29dbc25Smrg
878f29dbc25Smrg    return adr;
879f29dbc25Smrg}
880f29dbc25Smrg
881f29dbc25Smrg/* END OF FILE */
882