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