rockbox/firmware/target/coldfire/iaudio/x5/ds2411-x5.c

215 lines
6 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* 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,d"(ds2411_delay_factor), [x]"r,i"(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 level = disable_irq_save(); /* Timing sensitive */
int i;
unsigned char crc;
/* Initialize delay factor based on loop time: 3*(uS-1) + 3 */
ds2411_delay_factor = MAX(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) == 0)
{
/* 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);
i = DS2411_INVALID_FAMILY_CODE;
}
/* Check that CRC was ok */
else if (crc != 0) /* Because last loop eors the CRC with the resulting CRC */
{
logf("ds2411: invalid CRC=%02X", (unsigned)id->crc);
i = DS2411_INVALID_CRC;
}
else
{
/* Good ID read */
i = DS2411_OK;
}
}
else
{
logf("ds2411: no presence pulse");
i = DS2411_NO_PRESENCE;
}
restore_irq(level);
return i;
} /* ds2411_read_id */