/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2007 by Michael Sevakis * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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 */