⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd_i2c.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * (C) Copyright 2001 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. * * See file CREDITS for list of people who contributed to this * project. * * 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 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 *//* * I2C Functions similar to the standard memory functions. * * There are several parameters in many of the commands that bear further * explanations: * * Two of the commands (imm and imw) take a byte/word/long modifier * (e.g. imm.w specifies the word-length modifier).  This was done to * allow manipulating word-length registers.  It was not done on any other * commands because it was not deemed useful. * * {i2c_chip} is the I2C chip address (the first byte sent on the bus). *   Each I2C chip on the bus has a unique address.  On the I2C data bus, *   the address is the upper seven bits and the LSB is the "read/write" *   bit.  Note that the {i2c_chip} address specified on the command *   line is not shifted up: e.g. a typical EEPROM memory chip may have *   an I2C address of 0x50, but the data put on the bus will be 0xA0 *   for write and 0xA1 for read.  This "non shifted" address notation *   matches at least half of the data sheets :-/. * * {addr} is the address (or offset) within the chip.  Small memory *   chips have 8 bit addresses.  Large memory chips have 16 bit *   addresses.  Other memory chips have 9, 10, or 11 bit addresses. *   Many non-memory chips have multiple registers and {addr} is used *   as the register index.  Some non-memory chips have only one register *   and therefore don't need any {addr} parameter. * *   The default {addr} parameter is one byte (.1) which works well for *   memories and registers with 8 bits of address space. * *   You can specify the length of the {addr} field with the optional .0, *   .1, or .2 modifier (similar to the .b, .w, .l modifier).  If you are *   manipulating a single register device which doesn't use an address *   field, use "0.0" for the address and the ".0" length field will *   suppress the address in the I2C data stream.  This also works for *   successive reads using the I2C auto-incrementing memory pointer. * *   If you are manipulating a large memory with 2-byte addresses, use *   the .2 address modifier, e.g. 210.2 addresses location 528 (decimal). * *   Then there are the unfortunate memory chips that spill the most *   significant 1, 2, or 3 bits of address into the chip address byte. *   This effectively makes one chip (logically) look like 2, 4, or *   8 chips.  This is handled (awkwardly) by #defining *   CFG_I2C_EEPROM_ADDR_OVERFLOW and using the .1 modifier on the *   {addr} field (since .1 is the default, it doesn't actually have to *   be specified).  Examples: given a memory chip at I2C chip address *   0x50, the following would happen... *     imd 50 0 10      display 16 bytes starting at 0x000 *                      On the bus: <S> A0 00 <E> <S> A1 <rd> ... <rd> *     imd 50 100 10    display 16 bytes starting at 0x100 *                      On the bus: <S> A2 00 <E> <S> A3 <rd> ... <rd> *     imd 50 210 10    display 16 bytes starting at 0x210 *                      On the bus: <S> A4 10 <E> <S> A5 <rd> ... <rd> *   This is awfully ugly.  It would be nice if someone would think up *   a better way of handling this. * * Adapted from cmd_mem.c which is copyright Wolfgang Denk (wd@denx.de). */#include <common.h>#include <command.h>#include <i2c.h>#include <asm/byteorder.h>#if (CONFIG_COMMANDS & CFG_CMD_I2C)/* Display values from last command. * Memory modify remembered values are different from display memory. */static uchar	i2c_dp_last_chip;static uint	i2c_dp_last_addr;static uint	i2c_dp_last_alen;static uint	i2c_dp_last_length = 0x10;static uchar	i2c_mm_last_chip;static uint	i2c_mm_last_addr;static uint	i2c_mm_last_alen;#if defined(CFG_I2C_NOPROBES)static uchar i2c_no_probes[] = CFG_I2C_NOPROBES;#endifstatic intmod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]);extern int cmd_get_data_size(char* arg, int default_size);/* * Syntax: *	imd {i2c_chip} {addr}{.0, .1, .2} {len} */#define DISP_LINE_LEN	16int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){	u_char	chip;	uint	addr, alen, length;	int	j, nbytes, linebytes;	/* We use the last specified parameters, unless new ones are	 * entered.	 */	chip   = i2c_dp_last_chip;	addr   = i2c_dp_last_addr;	alen   = i2c_dp_last_alen;	length = i2c_dp_last_length;	if (argc < 3) {		printf ("Usage:\n%s\n", cmdtp->usage);		return 1;	}	if ((flag & CMD_FLAG_REPEAT) == 0) {		/*		 * New command specified.		 */		alen = 1;		/*		 * I2C chip address		 */		chip = simple_strtoul(argv[1], NULL, 16);		/*		 * I2C data address within the chip.  This can be 1 or		 * 2 bytes long.  Some day it might be 3 bytes long :-).		 */		addr = simple_strtoul(argv[2], NULL, 16);		alen = 1;		for(j = 0; j < 8; j++) {			if (argv[2][j] == '.') {				alen = argv[2][j+1] - '0';				if (alen > 4) {					printf ("Usage:\n%s\n", cmdtp->usage);					return 1;				}				break;			} else if (argv[2][j] == '\0') {				break;			}		}		/*		 * If another parameter, it is the length to display.		 * Length is the number of objects, not number of bytes.		 */		if (argc > 3)			length = simple_strtoul(argv[3], NULL, 16);	}	/*	 * Print the lines.	 *	 * We buffer all read data, so we can make sure data is read only	 * once.	 */	nbytes = length;	do {		unsigned char	linebuf[DISP_LINE_LEN];		unsigned char	*cp;		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;		if(i2c_read(chip, addr, alen, linebuf, linebytes) != 0) {			puts ("Error reading the chip.\n");		} else {			printf("%04x:", addr);			cp = linebuf;			for (j=0; j<linebytes; j++) {				printf(" %02x", *cp++);				addr++;			}			puts ("    ");			cp = linebuf;			for (j=0; j<linebytes; j++) {				if ((*cp < 0x20) || (*cp > 0x7e))					puts (".");				else					printf("%c", *cp);				cp++;			}			putc ('\n');		}		nbytes -= linebytes;	} while (nbytes > 0);	i2c_dp_last_chip   = chip;	i2c_dp_last_addr   = addr;	i2c_dp_last_alen   = alen;	i2c_dp_last_length = length;	return 0;}int do_i2c_mm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){	return mod_i2c_mem (cmdtp, 1, flag, argc, argv);}int do_i2c_nm ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){	return mod_i2c_mem (cmdtp, 0, flag, argc, argv);}/* Write (fill) memory * * Syntax: *	imw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] */int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){	uchar	chip;	ulong	addr;	uint	alen;	uchar	byte;	int	count;	int	j;	if ((argc < 4) || (argc > 5)) {		printf ("Usage:\n%s\n", cmdtp->usage);		return 1;	}	/* 	 * Chip is always specified. 	 */	chip = simple_strtoul(argv[1], NULL, 16);	/*	 * Address is always specified.	 */	addr = simple_strtoul(argv[2], NULL, 16);	alen = 1;	for(j = 0; j < 8; j++) {		if (argv[2][j] == '.') {			alen = argv[2][j+1] - '0';			if(alen > 4) {				printf ("Usage:\n%s\n", cmdtp->usage);				return 1;			}			break;		} else if (argv[2][j] == '\0') {			break;		}	}	/*	 * Value to write is always specified.	 */	byte = simple_strtoul(argv[3], NULL, 16);	/*	 * Optional count	 */	if(argc == 5) {		count = simple_strtoul(argv[4], NULL, 16);	} else {		count = 1;	}	while (count-- > 0) {		if(i2c_write(chip, addr++, alen, &byte, 1) != 0) {			puts ("Error writing the chip.\n");		}		/*		 * Wait for the write to complete.  The write can take		 * up to 10mSec (we allow a little more time).		 *		 * On some chips, while the write is in progress, the		 * chip doesn't respond.  This apparently isn't a		 * universal feature so we don't take advantage of it.		 */		udelay(11000);#if 0		for(timeout = 0; timeout < 10; timeout++) {			udelay(2000);			if(i2c_probe(chip) == 0)				break;		}#endif	}	return (0);}/* Calculate a CRC on memory * * Syntax: *	icrc32 {i2c_chip} {addr}{.0, .1, .2} {count} */int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){	uchar	chip;	ulong	addr;	uint	alen;	int	count;	uchar	byte;	ulong	crc;	ulong	err;	int	j;	if (argc < 4) {		printf ("Usage:\n%s\n", cmdtp->usage);		return 1;	}	/* 	 * Chip is always specified. 	 */	chip = simple_strtoul(argv[1], NULL, 16);	/*	 * Address is always specified.	 */	addr = simple_strtoul(argv[2], NULL, 16);	alen = 1;	for(j = 0; j < 8; j++) {		if (argv[2][j] == '.') {			alen = argv[2][j+1] - '0';			if(alen > 4) {				printf ("Usage:\n%s\n", cmdtp->usage);				return 1;			}			break;		} else if (argv[2][j] == '\0') {			break;		}	}	/*	 * Count is always specified	 */	count = simple_strtoul(argv[3], NULL, 16);	printf ("CRC32 for %08lx ... %08lx ==> ", addr, addr + count - 1);	/*	 * CRC a byte at a time.  This is going to be slooow, but hey, the	 * memories are small and slow too so hopefully nobody notices.	 */	crc = 0;	err = 0;	while(count-- > 0) {		if(i2c_read(chip, addr, alen, &byte, 1) != 0) {			err++;		}		crc = crc32 (crc, &byte, 1);		addr++;	}	if(err > 0)	{		puts ("Error reading the chip,\n");	} else {		printf ("%08lx\n", crc);	}	return 0;}/* Modify memory. * * Syntax: *	imm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} *	inm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} */static intmod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]){	uchar	chip;	ulong	addr;	uint	alen;	ulong	data;	int	size = 1;	int	nbytes;	int	j;	extern char console_buffer[];	if (argc != 3) {		printf ("Usage:\n%s\n", cmdtp->usage);		return 1;	}#ifdef CONFIG_BOOT_RETRY_TIME	reset_cmd_timeout();	/* got a good command to get here */#endif	/*	 * We use the last specified parameters, unless new ones are	 * entered.	 */	chip = i2c_mm_last_chip;	addr = i2c_mm_last_addr;	alen = i2c_mm_last_alen;	if ((flag & CMD_FLAG_REPEAT) == 0) {		/*		 * New command specified.  Check for a size specification.		 * Defaults to byte if no or incorrect specification.		 */		size = cmd_get_data_size(argv[0], 1);		/*	 	 * Chip is always specified.	 	 */		chip = simple_strtoul(argv[1], NULL, 16);		/*		 * Address is always specified.		 */		addr = simple_strtoul(argv[2], NULL, 16);		alen = 1;		for(j = 0; j < 8; j++) {			if (argv[2][j] == '.') {				alen = argv[2][j+1] - '0';				if(alen > 4) {					printf ("Usage:\n%s\n", cmdtp->usage);					return 1;				}				break;			} else if (argv[2][j] == '\0') {				break;			}		}	}	/*	 * Print the address, followed by value.  Then accept input for	 * the next value.  A non-converted value exits.	 */	do {		printf("%08lx:", addr);		if(i2c_read(chip, addr, alen, (char *)&data, size) != 0) {			puts ("\nError reading the chip,\n");		} else {			data = cpu_to_be32(data);			if(size == 1) {				printf(" %02lx", (data >> 24) & 0x000000FF);			} else if(size == 2) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -