summaryrefslogtreecommitdiffstats
path: root/firmware/target/coldfire/iaudio/x5/ds2411-x5.c
blob: a8b2ae705c7d385f1850695914445e300761e5ac (plain)
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
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2007 by Michael Sevakis
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "config.h"
#include "system.h"
#include "cpu.h"
#include "ds2411.h"
#include "logf.h"

/* Delay factor that depends on CPU frequency */
static unsigned int ds2411_delay_factor = 0;

#define DS2411_BIT (1 << 22)

/* Delay the specified number of microseconds - plus a tiny bit */
#define DELAY(uS)                \
    asm volatile(                   \
        "move.l %[x], %%d0      \n" \
        "mulu.l %[factor], %%d0 \n" \
    "1:                         \n" \
        "subq.l #1, %%d0        \n" \
        "bhi.s  1b              \n" \
        : : [factor]"d"(ds2411_delay_factor), [x]"d"(uS) : "d0");

/* Calculate the CRC of a byte */
static unsigned char ds2411_calc_crc(unsigned char byte)
{
    /* POLYNOMIAL = X^8 + X^5 + X^4 + 1 */
    static const unsigned char eor[8] =
    {
        0x5e, /* 01011110 */
        0xbc, /* 10111100 */
        0x61, /* 01100001 */
        0xc2, /* 11000010 */
        0x9d, /* 10011101 */
        0x23, /* 00100011 */
        0x46, /* 01000110 */
        0x8c, /* 10001100 */
    };

    unsigned char crc = 0;
    int i = 0;

    do
    {
        if (byte & (1 << i))
            crc ^= eor[i];
    }
    while (++i < 8);

    return crc;
} /* ds2411_calc_crc */

/* Write a byte to the DS2411 - LSb first */
static void ds2411_write_byte(unsigned char data)
{
    int i = 0;

    do
    {
        if (data & 0x01)
        {
            /* Write a "1": Hold line low, then leave line pulled up and wait
               out the remainder of Tslot */
            or_l(DS2411_BIT, &GPIO_ENABLE);
            DELAY(6);
            and_l(~DS2411_BIT, &GPIO_ENABLE);
            DELAY(60);
        }
        else
        {
            /* Write a "0": Hold line low, then leave line pulled up and wait
               out the remainder of Tslot which is just Trec */
            or_l(DS2411_BIT, &GPIO_ENABLE);
            DELAY(60);
            and_l(~DS2411_BIT, &GPIO_ENABLE);
            DELAY(6);
        }

        data >>= 1;
    }
    while (++i < 8);
} /* ds2411_write_byte */

/* Read a byte from the DS2411 - LSb first */
static unsigned char ds2411_read_byte(void)
{
    int i = 0;
    unsigned data = 0;

    do
    {
        /* Hold line low to begin bit read: Tf + Trl */
        or_l(DS2411_BIT, &GPIO_ENABLE);
        DELAY(6);

        /* Set line high and delay before sampling within the master
           sampling window: Tmsr - max 15us from Trl start */
        and_l(~DS2411_BIT, &GPIO_ENABLE);
        DELAY(9);

        /* Sample data line */
        if ((GPIO_READ & DS2411_BIT) != 0)
            data |= 1 << i;

        /* Wait out the remainder of Tslot */
        DELAY(60);   
    }
    while (++i < 8);

    return data;
} /* ds2411_read_byte */

/*
 * Byte 0:    8-bit family code (01h)
 * Bytes 1-6: 48-bit serial number
 * Byte 7:    8-bit CRC code
 */
int ds2411_read_id(struct ds2411_id *id)
{
    int i;
    unsigned char crc;

    /* Initialize delay factor based on loop time: 3*(uS-1) + 3 */
    ds2411_delay_factor = MIN(cpu_frequency / (1000000*3), 1);

    /* Init GPIO 1 wire bus for bit banging with a pullup resistor where 
     * it is set low as output and switched between input and output mode.
     * Required for bidirectional communication on a single wire.
     */
    or_l(DS2411_BIT, &GPIO_FUNCTION);   /* Set pin as GPIO            */
    and_l(~DS2411_BIT, &GPIO_ENABLE);   /* Set as input               */
    and_l(~DS2411_BIT, &GPIO_OUT);      /* Set low when set as output */

    /* Delay 100us to stabilize */
    DELAY(100);

    /* Issue reset pulse - 480uS or more to ensure standard (not overdrive)
       mode - we don't have the timing accuracy for that. */
    or_l(DS2411_BIT, &GPIO_ENABLE);
    /* Delay 560us: (Trstlmin + Trstlmax) / 2*/
    DELAY(560);
    and_l(~DS2411_BIT, &GPIO_ENABLE);
    /* Delay 66us: Tpdhmax + 6 */
    DELAY(66);

    /* Read presence pulse - line should be pulled low at proper time by the
       slave device */
    if (GPIO_READ & DS2411_BIT)
    {
        logf("ds2411: no presence pulse");
        return DS2411_NO_PRESENCE;
    }

    /* Trsth + 1 - 66 = Tpdhmax + Tpdlmax + Trecmin + 1 - 66 */
    DELAY(240);

    /* ds2411 should be ready for data transfer */

    /* Send Read ROM command */
    ds2411_write_byte(0x33);

    /* Read ROM serial number and CRC */
    i = 0, crc = 0;

    do
    {
        unsigned char byte = ds2411_read_byte();
        ((unsigned char *)id)[i] = byte;
        crc = ds2411_calc_crc(crc ^ byte);
    }
    while (++i < 8);

    /* Check that family code is ok */
    if (id->family_code != 0x01)
    {
        logf("ds2411: invalid family code=%02X", (unsigned)id->family_code);
        return DS2411_INVALID_FAMILY_CODE;
    }

    /* Check that CRC was ok */
    if (crc != 0) /* Because last loop eors the CRC with the resulting CRC */
    {
        logf("ds2411: invalid CRC=%02X", (unsigned)id->crc);
        return DS2411_INVALID_CRC;
    }

    /* Good ID read */
    return DS2411_OK;
} /* ds2411_read_id */