summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/mvme5500/GT64260/GT64260TWSI.c
blob: 6b5b46e511d242b6797ceea486c9f421557a1f32 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
 * Two-Wire Serial Interface (TWSI) support for the GT64260
 */

/*
 * Copyright (c) 2004, Brookhaven National Laboratory and
 *                 Shuchen Kate Feng <feng1@bnl.gov>
 * All rights reserved.
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution.
 *
 * See section 24:TWSI interface of "the GT-64260B System Controller
 * for powerPc Processors Data Sheet".
 *
 * For full TWSI protocol description look in Philips Semiconductor
 * TWSI spec.
 *
 * We need it to read out I2C devices used for the MVME5500
 * (eg. the memory SPD and VPD).
 */

#include <libcpu/spr.h>  /*registers.h included here for rtems_bsp_delay()*/
#include <libcpu/io.h>
#include <rtems/bspIo.h>

#include "bsp/gtreg.h"
#include "bsp/GT64260TWSI.h"

#define MAX_LOOP 100

#define TWSI_DEBUG 0

static int TWSI_initFlg = 0;  /* TWSI Initialization Flag */

void GT64260TWSIinit(void)
{
  if ( !TWSI_initFlg ) {
#if TWSI_DEBUG
   printk("GT64260TWSIinit(");
#endif
   outl( 0, TWSI_SFT_RST); /* soft reset */
   rtems_bsp_delay(1000);

   /* See 24.2.5 : Assume bus speed is 133MHZ
    * Try to be close to the default frequency : 62.5KHZ
    * value 0x2c: 69.27 KHz TWSI bus clock
    */
   outl(0x2c, TWSI_BAUDE_RATE);
   rtems_bsp_delay(1000);

   /* Set Acknowledge and enable TWSI in the Control register */
   outl(0x44, TWSI_CTRL);
   rtems_bsp_delay(4000);
   TWSI_initFlg = 1;
#if TWSI_DEBUG
   printk(")\n");
#endif
  }
}

/* return the interrupt flag */
static int GT64260TWSIintFlag(void)
{
  unsigned int loop;

  for (loop = 0; loop < MAX_LOOP; loop++ ) {
    /* Return 1 if the interrupt flag is set */
    if (inl(TWSI_CTRL) & TWSI_INTFLG)
      return(1);
    rtems_bsp_delay(1000);
  }
  return(0);
}

int GT64260TWSIstop(void)
{

#if TWSI_DEBUG
  printk("GT64260TWSIstop(");
#endif

  outl((inl(TWSI_CTRL) | TWSI_STOP), TWSI_CTRL);
  rtems_bsp_delay(1000);

  /* Check if interrupt flag bit is set*/
  if (GT64260TWSIintFlag()) {
     outl((inl( TWSI_CTRL) & ~TWSI_INTFLG), TWSI_CTRL);
     rtems_bsp_delay(1000);
#if TWSI_DEBUG
     printk(")\n");
#endif
     return(0);
  }
#if TWSI_DEBUG
     printk("NoIntFlag\n");
#endif
  return(-1);
}

int GT64260TWSIstart(void)
{
  unsigned int loop;
  unsigned int status;

#if TWSI_DEBUG
  printk("GT64260TWSIstart(");
#endif
  /* Initialize the TWSI interface */
  GT64260TWSIinit();

  /* set the start bit */
  outl((TWSI_START | TWSI_TWSIEN), TWSI_CTRL);
  rtems_bsp_delay(1000);

  if (GT64260TWSIintFlag()) {
    /* Check for completion of START sequence */
    for (loop = 0; loop<MAX_LOOP; loop++ ) {
      /* if (start condition transmitted) ||
       *    (repeated start condition transmitted )
       */
      if (((status= inl( TWSI_STATUS)) == 8) || (status == 0x10)) {
#if TWSI_DEBUG
        printk(")");
#endif
        return(0);
      }
      rtems_bsp_delay(1000);
    }
  }
  /* if loop ends or intFlag ==0 */
  GT64260TWSIstop();
  return(-1);
}

int GT64260TWSIread(unsigned char * pData, int lastByte)
{
  unsigned int loop;

#if TWSI_DEBUG
  printk("GT64260TWSIread(");
#endif
  /* Clear INTFLG and set ACK and ENABLE bits */
  outl((TWSI_ACK | TWSI_TWSIEN), TWSI_CTRL);
  rtems_bsp_delay(1000);

  if (GT64260TWSIintFlag()) {
    for (loop = 0; loop< MAX_LOOP; loop++) {
      /* if Master received read data, acknowledge transmitted */
      if ( (inl( TWSI_STATUS) == 0x50)) {
        *pData = (unsigned char) inl( TWSI_DATA);
        rtems_bsp_delay(1500);

        /* Clear INTFLAG and set Enable bit only */
        if (lastByte)
         outl(TWSI_TWSIEN, TWSI_CTRL);
        rtems_bsp_delay(1500);
#if TWSI_DEBUG
        printk(")\n");
#endif
        return(0);
      }
      rtems_bsp_delay(1000);
    } /* end for */
  }
  /* if loop ends or intFlag ==0 */
  GT64260TWSIstop();
  return(-1);
}

/* do a TWSI write cycle on the TWSI bus*/
int GT64260TWSIwrite(unsigned char Data)
{
  unsigned int loop;
  unsigned int status;

#if TWSI_DEBUG
  printk("GT64260TWSIwrite(");
#endif
  /* Write data into the TWSI data register */
  outl(((unsigned int) Data), TWSI_DATA);
  rtems_bsp_delay(1000);

  /* Clear INTFLG in the control register to drive data onto TWSI bus */
  outl(0, TWSI_CTRL);
  rtems_bsp_delay(1000);

  if (GT64260TWSIintFlag() ) {
    for (loop = 0; loop< MAX_LOOP; loop++) {
      rtems_bsp_delay(1000);
      /* if address + write bit transmitted, acknowledge not received */
      if ( (status = inl( TWSI_STATUS)) == 0x20) {
        /* No device responding, generate STOP and return -1 */
        printk("no device responding\n");
        GT64260TWSIstop();
        return(-1);
      }
      /* if (address + write bit transmitted, acknowledge received)
       * (Master transmmitted data byte, acknowledge received)
       *    (address + read bit transmitted, acknowledge received)
       */
      if ((status == 0x18)||(status == 0x28)||(status == 0x40)) {
#if TWSI_DEBUG
        printk(")\n");
#endif
        return(0);
      }
      rtems_bsp_delay(1000);
    } /* end for */
  }
  printk("No correct status, timeout\n");
  GT64260TWSIstop();
  return(-1);
}