[U-Boot] [PATCH] add 1-wire DS2401 serial number chip
Andrew Dyer
amdyer at gmail.com
Wed May 26 21:15:23 CEST 2010
On Wed, May 26, 2010 at 1:31 PM, Asen Dimov <dimov at ronetix.at> wrote:
>
The one-wire bus is generic, so I think it would make sense to split
the bus access logic and the handling of the DS2401 into parts so that
other people could make use of it.
We did an implementation a long time ago for the DS2502, and one of
the problems we ran into was the one wire bus timing was kind of tight
for early code (we were running it in misc_init_r() ), so we ended up
making up our own timer routines instead of the generic udelay stuff.
I include our file for reference below.
> Signed-off-by: Asen Dimov <dimov at ronetix.at>
> ---
> drivers/misc/Makefile | 1 +
> drivers/misc/ds2401.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++++
> include/ds2401.h | 36 +++++++
> 3 files changed, 302 insertions(+), 0 deletions(-)
> create mode 100644 drivers/misc/ds2401.c
> create mode 100644 include/ds2401.h
>
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 96aa331..4355b6e 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -32,6 +32,7 @@ COBJS-$(CONFIG_NS87308) += ns87308.o
> COBJS-$(CONFIG_STATUS_LED) += status_led.o
> COBJS-$(CONFIG_TWL4030_LED) += twl4030_led.o
> COBJS-$(CONFIG_FSL_PMIC) += fsl_pmic.o
> +COBJS-$(CONFIG_DS2401) += ds2401.o
>
> COBJS := $(COBJS-y)
> SRCS := $(COBJS:.o=.c)
> diff --git a/drivers/misc/ds2401.c b/drivers/misc/ds2401.c
> new file mode 100644
> index 0000000..4298d8a
> --- /dev/null
> +++ b/drivers/misc/ds2401.c
> @@ -0,0 +1,265 @@
> +/*
> + * Copyright 2009, 2010
> + * Ilko Iliev <iliev at ronetix.at>
> + * Ronetix Development Tools GmbH <www.ronetix.at>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * Version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +/*
> + * Driver for 1-wire, DS2401, a Silicon Serial Number chip
> + *
> + * Driver usage:
> + *
> + * To build the driver add in a board config file:
> + * #define CONFIG_DS2401 1
> + *
> + * In the board specific file define the get and set functions
> + * to read and write one bit from/to PIO.
> + *
> + * If you want to set a specific first three bytes of the MAC address
> + * define CONFIG_MAC_OUI.
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <ds2401.h>
> +
> +#ifndef CONFIG_MAC_OUI
> +#define CONFIG_MAC_OUI "02:00:00" /* Organizationally Unique Identifier*/
> +#endif
> +
> +static DS2401_FUNCS *DS2401_Funcs = NULL;
> +
> +/*
> + * Generate a 1-wire reset, return 1 if no presence detect was found,
> + * return 0 otherwise.
> + */
> +static int ds2401_reset(void)
> +{
> + int result;
> +
> + DS2401_Funcs->set(0);
> + udelay(480);
> + DS2401_Funcs->set(1);
> + udelay(70);
> +
> + result = DS2401_Funcs->get();
> +
> + udelay(410);
> + return result;
> +}
> +
> +/*
> + * Send 1 a 1-wire write bit.
> + * Provide 10us recovery time.
> + */
> +static void ds2401_write_bit(int bit)
> +{
> + if (bit) {
> + /*
> + * write '1' bit
> + */
> + DS2401_Funcs->set(0);
> + udelay(6);
> + DS2401_Funcs->set(1);
> + udelay(64);
> + } else {
> + /*
> + * write '0' bit
> + */
> + DS2401_Funcs->set(0);
> + udelay(60);
> + DS2401_Funcs->set(1);
> + udelay(10);
> + }
> +}
> +
> +/*
> + * Read a bit from the 1-wire bus and return it.
> + * Provide 10us recovery time.
> + */
> +static int ds2401_read_bit(void)
> +{
> + int result;
> +
> + DS2401_Funcs->set(0);
> +
> +#ifdef __OPTIMIZE__
> + udelay(1);
> +#endif
> +
> + DS2401_Funcs->set(1);
> + udelay(9);
> +
> + result = DS2401_Funcs->get();
> + udelay(55);
> +
> + return result;
> +}
> +
> +static void ds2401_write_byte(int data)
> +{
> + int loop;
> +
> + for (loop = 0; loop < 8; loop++) {
> + ds2401_write_bit(data & 0x01);
> + data >>= 1;
> + }
> +}
> +
> +static int ds2401_read_byte(void)
> +{
> + int loop, result = 0;
> +
> + for (loop = 0; loop < 8; loop++) {
> + result >>= 1;
> + if (ds2401_read_bit())
> + result |= 0x80;
> + }
> +
> + return result;
> +}
> +
> +static unsigned char ds2401_crc8_table[] = {
> + 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
> + 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
> + 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
> + 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
> + 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
> + 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
> + 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
> + 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
> + 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
> + 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
> + 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
> + 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
> + 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
> + 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
> + 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
> + 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
> +};
> +
> +static unsigned char ds2401_calc_crc8(unsigned char * data, int len)
> +{
> + unsigned char crc = 0;
> +
> + while (len--)
> + crc = ds2401_crc8_table[crc ^ *data++];
> +
> + return crc;
> +}
> +
> +void ds2401_init(DS2401_FUNCS *funcs)
> +{
> + DS2401_Funcs = funcs;
> +}
> +
> +/*
> + * Read the serial number from the 1-wire bus and return it.
> + * Returns 0 if successful.
> + * Returns non-zero if not successful.
> + */
> +int ds2401_get_number( unsigned char id[6] )
> +{
> + int ii, result;
> + unsigned char crc;
> + unsigned char buf[8];
> +
> + result = ds2401_reset();
> + if (result != 0)
> + return 1;
> +
> + ds2401_write_byte(DS2401_CMD_READ_ROM); /* send read rom command */
> +
> + /*
> + * read 8 bytes:
> + * buf[0] - family code (0x01)
> + * buf[1..6] - serial number
> + * buf[7] - CRC
> + */
> + for (ii = 0; ii < 8; ii++)
> + buf[ii] = ds2401_read_byte();
> +
> + /*
> + * calculate the 8-bit Dallas CRC
> + */
> + crc = ds2401_calc_crc8( buf, 7 );
> +
> + if ( crc != buf[7] )
> + return 1;
> +
> + for (ii = 0; ii < 6; ii++)
> + id[ii] = buf[ii + 1];
> +
> + return 0;
> +}
> +
> +int do_ds2401(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
> +{
> + int stat;
> + unsigned char ds2401_id[6];
> + char str[32];
> +
> + if (DS2401_Funcs == NULL) {
> + puts("Board specific functions for 1-wire not specified!\n");
> + return 0;
> + }
> +
> + stat = ds2401_get_number( ds2401_id );
> +
> + if (stat){
> + puts("No 1-wire device detected!\n");
> + return 0;
> + }
> +
> + if (strcmp(argv[1], "ethaddr") == 0){
> + sprintf(str, "%s:%X:%X:%X",
> + CONFIG_MAC_OUI,
> + (int)ds2401_id[2],
> + (int)ds2401_id[1],
> + (int)ds2401_id[0]);
> +
> + printf("Setting environment variable 'ethaddr' to %s\n", str);
> + setenv("ethaddr", str);
> + } else {
> + sprintf(str, "0x%X%X%X%X%X%X",
> + (int)ds2401_id[5],
> + (int)ds2401_id[4],
> + (int)ds2401_id[3],
> + (int)ds2401_id[2],
> + (int)ds2401_id[1],
> + (int)ds2401_id[0]);
> +
> + if (argc == 2 ) {
> + printf("Setting environment variable '%s' to %s\n",
> + argv[1], str);
> + setenv(argv[1], str);
> + } else {
> + printf("Serial number is %s\n", str);
> + }
> + }
> +
> + return 0;
> +}
> +
> +U_BOOT_CMD(
> + onewire, 2, 1, do_ds2401,
> + "Read 1-write ID and set an U-Boot variable or\n"
> + "the last three bytes of 'ethaddr'",
> + "[variable] - to set a specific variable with DS2401 serial number\n"
> + "onewire ethaddr - to set the last three bytes of MAC address\n"
> + "onewire - with no parameter to display serial number"
> +);
> diff --git a/include/ds2401.h b/include/ds2401.h
> new file mode 100644
> index 0000000..472e334
> --- /dev/null
> +++ b/include/ds2401.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright 2009
> + * Ilko Iliev <iliev at ronetix.at>
> + * Ronetix Development Tools GmbH <www.ronetix.at>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * Version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __DS2401_H_
> +#define __DS2401_H_
> +
> +#define DS2401_CMD_READ_ROM 0x33
> +
> +typedef struct
> +{
> + void (*set)(int value );
> + int (*get)(void);
> +} DS2401_FUNCS;
> +
> +extern void ds2401_init(DS2401_FUNCS *funcs);
> +extern int ds2401_get_number( unsigned char id[6] );
> +
> +#endif /* __DS2401_H_ */
> +
> --
> 1.5.5.6
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
/*
* (C) Copyright 2005
* Andrew Dyer, RightHand Technologies, adyer at righthandtech.com
*/
/* crc routines from dallas semiconductor one wire public kit */
/*---------------------------------------------------------------------------
* Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Dallas Semiconductor
* shall not be used except as stated in the Dallas Semiconductor
* Branding Policy.
*/
#include <common.h>
#include <asm/au1x00.h>
#include "eldo2.h"
#define DS2502_LEN (1024 / 8)
#if 0
#define ONEWIRE_DEBUG
#endif
#ifdef ONEWIRE_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#else
#define PRINTF(fmt,args...)
#endif
static const u8 crc_table[] = {
0x00,0x5e,0xbc,0xe2,0x61,0x3f,0xdd,0x83,0xc2,0x9c,0x7e,0x20,0xa3,0xfd,0x1f,0x41,
0x9d,0xc3,0x21,0x7f,0xfc,0xa2,0x40,0x1e,0x5f,0x01,0xe3,0xbd,0x3e,0x60,0x82,0xdc,
0x23,0x7d,0x9f,0xc1,0x42,0x1c,0xfe,0xa0,0xe1,0xbf,0x5d,0x03,0x80,0xde,0x3c,0x62,
0xbe,0xe0,0x02,0x5c,0xdf,0x81,0x63,0x3d,0x7c,0x22,0xc0,0x9e,0x1d,0x43,0xa1,0xff,
0x46,0x18,0xfa,0xa4,0x27,0x79,0x9b,0xc5,0x84,0xda,0x38,0x66,0xe5,0xbb,0x59,0x07,
0xdb,0x85,0x67,0x39,0xba,0xe4,0x06,0x58,0x19,0x47,0xa5,0xfb,0x78,0x26,0xc4,0x9a,
0x65,0x3b,0xd9,0x87,0x04,0x5a,0xb8,0xe6,0xa7,0xf9,0x1b,0x45,0xc6,0x98,0x7a,0x24,
0xf8,0xa6,0x44,0x1a,0x99,0xc7,0x25,0x7b,0x3a,0x64,0x86,0xd8,0x5b,0x05,0xe7,0xb9,
0x8c,0xd2,0x30,0x6e,0xed,0xb3,0x51,0x0f,0x4e,0x10,0xf2,0xac,0x2f,0x71,0x93,0xcd,
0x11,0x4f,0xad,0xf3,0x70,0x2e,0xcc,0x92,0xd3,0x8d,0x6f,0x31,0xb2,0xec,0x0e,0x50,
0xaf,0xf1,0x13,0x4d,0xce,0x90,0x72,0x2c,0x6d,0x33,0xd1,0x8f,0x0c,0x52,0xb0,0xee,
0x32,0x6c,0x8e,0xd0,0x53,0x0d,0xef,0xb1,0xf0,0xae,0x4c,0x12,0x91,0xcf,0x2d,0x73,
0xca,0x94,0x76,0x28,0xab,0xf5,0x17,0x49,0x08,0x56,0xb4,0xea,0x69,0x37,0xd5,0x8b,
0x57,0x09,0xeb,0xb5,0x36,0x68,0x8a,0xd4,0x95,0xcb,0x29,0x77,0xf4,0xaa,0x48,0x16,
0xe9,0xb7,0x55,0x0b,0x88,0xd6,0x34,0x6a,0x2b,0x75,0x97,0xc9,0x4a,0x14,0xf6,0xa8,
0x74,0x2a,0xc8,0x96,0x15,0x4b,0xa9,0xf7,0xb6,0xe8,0x0a,0x54,0xd7,0x89,0x6b,0x35
};
/*--------------------------------------------------------------------------
* Update the CRC
*
* 'state' - pointer to location holding the crc state
* 'x' - data byte to calculate the 8 bit crc from
*
*/
void docrc8(u8 *state, u8 x)
{
*state = crc_table[*state ^ x];
}
#define OWOUT1 ( *(volatile u32 *)SYS_TRIOUTCLR = GPIO_ONEWIRE )
#define OWOUT0 ( *(volatile u32 *)SYS_OUTPUTCLR = GPIO_ONEWIRE )
static inline int ow_in(void)
{
unsigned int data = *((volatile u32 *)SYS_PININPUTEN);
return (data & GPIO_ONEWIRE) ? 1 : 0;
}
static inline u32 ow_mips_count_get(void)
{
u32 count;
asm volatile ("mfc0 %0, $9" : "=r" (count) :);
return count;
}
/* because this code runs from prom and one-wire
timing is somewhat tight, provide our own
inlined stripped down delay routine for less
overhead */
/* this routine messes with the cpu system timer
and will break if called from code that
expects to be able to use set_timer() and
get_timer() */
static inline void ow_udelay(u32 usec)
{
u32 tmo = usec * CFG_MHZ;
/* clear count register */
asm volatile ("mtc0 $0, $9");
while (ow_mips_count_get() < tmo)
/*NOP*/;
}
/*---------------------------------------------------------------------------
** Generate a 1-Wire reset, return 1 if no presence detect was found,
** return 0 otherwise.
*/
static int ow_reset(void)
{
int result;
PRINTF("\n%s:%d: starting onewire reset\n", __FUNCTION__, __LINE__);
OWOUT0;
ow_udelay(600);
OWOUT1;
ow_udelay(70);
result = ow_in();
ow_udelay(410);
PRINTF("\n%s:%d: onewire reset result = %d\n", __FUNCTION__,
__LINE__, result);
return result;
}
/*---------------------------------------------------------------------------
** Send a 1-Wire write bit. Provide 10us recovery time.
*/
static void ow_write_bit(int bit)
{
if (bit) {
/* Write 1 bit */
OWOUT0;
ow_udelay(1);
OWOUT1;
ow_udelay(69); /* Complete the time slot and 10us recovery */
} else {
/* Write 0 bit */
OWOUT0;
ow_udelay(60);
OWOUT1;
ow_udelay(10);
}
}
/*---------------------------------------------------------------------------
** Read a bit from the 1-Wire bus and return it. Provide 10us recovery time.
*/
static int ow_read_bit(void)
{
int result;
OWOUT0;
ow_udelay(1);
OWOUT1;
ow_udelay(9);
result = ow_in(); /* Sample the bit value from the slave */
ow_udelay(55); /* Complete the time slot and 10us recovery */
return result;
}
/*---------------------------------------------------------------------------
** Write 1-Wire data byte
*/
static void ow_write_byte(int data)
{
int loop;
PRINTF("\n%s:%d:write data = %x\n",__FUNCTION__, __LINE__, data);
/* Loop to write each bit in the byte, LS-bit first */
for (loop = 0; loop < 8; loop++) {
ow_write_bit(data & 0x01);
/* shift the data byte for the next bit */
data >>= 1;
}
}
/*---------------------------------------------------------------------------
** Read 1-Wire data byte and return it
*/
static int ow_read_byte(void)
{
int loop, result=0;
for (loop = 0; loop < 8; loop++) {
/* shift the result to get it ready for the next bit */
result >>= 1;
/* if result is one, then set MS bit */
if (ow_read_bit())
result |= 0x80;
}
PRINTF("\n%s:%d:read result = %x\n",__FUNCTION__, __LINE__, result);
return result;
}
/*---------------------------------------------------------------------------
** Write a 1-Wire data byte and return the sampled result.
*/
static int ow_touch_byte(int data)
{
int loop, result=0;
for (loop = 0; loop < 8; loop++) {
/* shift the result to get it ready for the next bit */
result >>= 1;
/* If sending a 1 then read a bit else write a 0 */
if (data & 0x01) {
if (ow_read_bit())
result |= 0x80;
} else
ow_write_bit(0);
/* shift the data byte for the next bit */
data >>= 1;
}
return result;
}
/*---------------------------------------------------------------------------
** Read and return the serial number
**
*/
u8 *ow_get_sernum(void)
{
int i;
u8 crc_state;
static u8 buf[8];
if (ow_reset())
return 0; /* Return if no devices found */
ow_write_byte(0x33); /* Send Read ROM command */
crc_state = 0;
for (i=0; i<8; i++) {
buf[i] = ow_read_byte();
docrc8(&crc_state, buf[i]);
}
if ( crc_state != 0) {
printf("one wire rom function command CRC failed\n");
return 0;
}
return buf;
}
u16 utilcrc16;
static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
//--------------------------------------------------------------------------
// Reset crc16 to the value passed in
//
// 'reset' - data to set crc16 to.
//
void setcrc16(u16 reset)
{
utilcrc16 = reset;
return;
}
//--------------------------------------------------------------------------
// Calculate a new CRC16 from the input data short. Return the current
// CRC16 and also update the global variable CRC16.
//
// 'data' - data to perform a CRC16 on
//
// Returns: the current CRC16
//
u16 docrc16(u16 cdata)
{
cdata = (cdata ^ (utilcrc16 & 0xff)) & 0xff;
utilcrc16 >>= 8;
if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4])
utilcrc16 ^= 0xc001;
cdata <<= 6;
utilcrc16 ^= cdata;
cdata <<= 1;
utilcrc16 ^= cdata;
return utilcrc16;
}
u8 *ow_get_ethaddr(void)
{
int i;
u8 byte;
u8 crc_state;
u16 crc16_state;
static u8 buf[16];
if (ow_reset())
return 0; /* Return if no devices found */
ow_write_byte(0x33); /* Send Read ROM command */
crc_state = 0;
for (i=0; i<8; i++) {
byte = ow_read_byte();
docrc8(&crc_state, byte);
buf[i] = byte;
}
if ( crc_state != 0) {
printf("one wire rom function command CRC failed\n");
return 0;
}
ow_write_byte(0xf0); /* Send Read memory command */
ow_write_byte(0x00);
ow_write_byte(0x00);
byte = ow_read_byte();
crc_state = 0;
docrc8(&crc_state, 0xf0);
docrc8(&crc_state, 0x00);
docrc8(&crc_state, 0x00);
docrc8(&crc_state, byte);
if ( crc_state != 0) {
printf("one wire memory read command CRC failed\n");
return 0;
}
/* read the data -
* length (1 byte)
* project ID (4 bytes 00 00 11 29)
* ethernet mac (6 bytes 00 60 35 xx xx xx)
* crc16 (2 bytes)
*/
setcrc16(0);
for (i=0; i<13; i++) {
buf[i] = ow_read_byte();
crc16_state = docrc16(buf[i]);
PRINTF("%02x ", buf[i]);
}
if (crc16_state != 0xb001) {
printf("one wire memory read data CRC failed\n");
return 0;
}
return buf+5;
}
More information about the U-Boot
mailing list