X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fcmd_i2c.c;h=29f5181baf8238aefa01c1df923d5e0dd5530b8e;hb=03a8890ee098e00f8b3c89c2d7f134ed4b89b68c;hp=a7672cf7606367182b85ce766a50cdc5527aaa13;hpb=4a8cf3382a6fea5cccc1e2ae61a4601bf26490c3;p=karo-tx-uboot.git diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index a7672cf760..29f5181baf 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -1,24 +1,13 @@ /* - * (C) Copyright 2001 - * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. - * - * See file CREDITS for list of people who contributed to this - * project. + * (C) Copyright 2009 + * Sergey Kubushyn, himself, ksi@koi8.net * - * 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. + * Changes for unified multibus/multiadapter I2C support. * - * 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. + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. * - * 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 + * SPDX-License-Identifier: GPL-2.0+ */ /* @@ -78,10 +67,14 @@ #include #include +#include #include #include #include #include +#include + +DECLARE_GLOBAL_DATA_PTR; /* Display values from last command. * Memory modify remembered values are different from display memory. @@ -101,7 +94,7 @@ static uint i2c_mm_last_alen; * pairs. The following macros take care of this */ #if defined(CONFIG_SYS_I2C_NOPROBES) -#if defined(CONFIG_I2C_MULTI_BUS) +#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) static struct { uchar bus; @@ -117,55 +110,113 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES; #define COMPARE_BUS(b,i) ((b) == 0) /* Make compiler happy */ #define COMPARE_ADDR(a,i) (i2c_no_probes[(i)] == (a)) #define NO_PROBE_ADDR(i) i2c_no_probes[(i)] -#endif /* CONFIG_MULTI_BUS */ - -#define NUM_ELEMENTS_NOPROBE (sizeof(i2c_no_probes)/sizeof(i2c_no_probes[0])) +#endif /* defined(CONFIG_SYS_I2C) */ #endif -#if defined(CONFIG_I2C_MUX) -static I2C_MUX_DEVICE *i2c_mux_devices = NULL; -static int i2c_mux_busid = CONFIG_SYS_MAX_I2C_BUS; - -DECLARE_GLOBAL_DATA_PTR; +#define DISP_LINE_LEN 16 -#endif +/** + * i2c_init_board() - Board-specific I2C bus init + * + * This function is the default no-op implementation of I2C bus + * initialization. This function can be overriden by board-specific + * implementation if needed. + */ +__weak +void i2c_init_board(void) +{ +} /* TODO: Implement architecture-specific get/set functions */ -unsigned int __def_i2c_get_bus_speed(void) + +/** + * i2c_get_bus_speed() - Return I2C bus speed + * + * This function is the default implementation of function for retrieveing + * the current I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns I2C bus speed in Hz. + */ +#if !defined(CONFIG_SYS_I2C) +/* + * TODO: Implement architecture-specific get/set functions + * Should go away, if we switched completely to new multibus support + */ +__weak +unsigned int i2c_get_bus_speed(void) { return CONFIG_SYS_I2C_SPEED; } -unsigned int i2c_get_bus_speed(void) - __attribute__((weak, alias("__def_i2c_get_bus_speed"))); -int __def_i2c_set_bus_speed(unsigned int speed) +/** + * i2c_set_bus_speed() - Configure I2C bus speed + * @speed: Newly set speed of the I2C bus in Hz + * + * This function is the default implementation of function for setting + * the I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns zero on success, negative value on error. + */ +__weak +int i2c_set_bus_speed(unsigned int speed) { if (speed != CONFIG_SYS_I2C_SPEED) return -1; return 0; } -int i2c_set_bus_speed(unsigned int) - __attribute__((weak, alias("__def_i2c_set_bus_speed"))); +#endif -#define DISP_LINE_LEN 16 +/** + * get_alen() - Small parser helper function to get address length + * + * Returns the address length. + */ +static uint get_alen(char *arg) +{ + int j; + int alen; -/* + alen = 1; + for (j = 0; j < 8; j++) { + if (arg[j] == '.') { + alen = arg[j+1] - '0'; + break; + } else if (arg[j] == '\0') + break; + } + return alen; +} + +/** + * do_i2c_read() - Handle the "i2c read" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr} */ - -static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; uint devaddr, alen, length; u_char *memaddr; - int j; - if (argc != 5) { - cmd_usage(cmdtp); - return 1; - } + if (argc != 5) + return CMD_RET_USAGE; /* * I2C chip address @@ -177,18 +228,9 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr = 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; /* * Length is the number of objects, not number of bytes. @@ -207,11 +249,68 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } +static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u_char chip; + uint devaddr, alen, length; + u_char *memaddr; + + if (argc != 5) + return cmd_usage(cmdtp); + + /* + * memaddr is the address where to store things in memory + */ + memaddr = (u_char *)simple_strtoul(argv[1], NULL, 16); + + /* + * I2C chip address + */ + chip = simple_strtoul(argv[2], NULL, 16); + + /* + * I2C data address within the chip. This can be 1 or + * 2 bytes long. Some day it might be 3 bytes long :-). + */ + devaddr = simple_strtoul(argv[3], NULL, 16); + alen = get_alen(argv[3]); + if (alen > 3) + return cmd_usage(cmdtp); + + /* + * Length is the number of objects, not number of bytes. + */ + length = simple_strtoul(argv[4], NULL, 16); + + while (length-- > 0) { + if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) { + puts("Error writing to the chip.\n"); + return 1; + } /* + * No write delay with FRAM devices. + */ +#if !defined(CONFIG_SYS_I2C_FRAM) + udelay(11000); +#endif + } + return 0; +} + +/** + * do_i2c_md() - Handle the "i2c md" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c md {i2c_chip} {addr}{.0, .1, .2} {len} */ -static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; uint addr, alen, length; @@ -225,16 +324,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) alen = i2c_dp_last_alen; length = i2c_dp_last_length; - if (argc < 3) { - cmd_usage(cmdtp); - return 1; - } + if (argc < 3) + return CMD_RET_USAGE; if ((flag & CMD_FLAG_REPEAT) == 0) { /* * New command specified. */ - alen = 1; /* * I2C chip address @@ -246,18 +342,9 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; /* * If another parameter, it is the length to display. @@ -311,25 +398,29 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } - -/* Write (fill) memory +/** + * do_i2c_mw() - Handle the "i2c mw" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] */ -static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uchar chip; ulong addr; uint alen; uchar byte; int count; - int j; - if ((argc < 4) || (argc > 5)) { - cmd_usage(cmdtp); - return 1; - } + if ((argc < 4) || (argc > 5)) + return CMD_RET_USAGE; /* * Chip is always specified. @@ -340,18 +431,9 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; /* * Value to write is always specified. @@ -381,15 +463,25 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #endif } - return (0); + return 0; } -/* Calculate a CRC on memory +/** + * do_i2c_crc() - Handle the "i2c crc32" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Calculate a CRC on memory + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count} */ -static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uchar chip; ulong addr; @@ -398,12 +490,9 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) uchar byte; ulong crc; ulong err; - int j; - if (argc < 4) { - cmd_usage(cmdtp); - return 1; - } + if (argc < 4) + return CMD_RET_USAGE; /* * Chip is always specified. @@ -414,18 +503,9 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; /* * Count is always specified @@ -453,15 +533,24 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } -/* Modify memory. +/** + * mod_i2c_mem() - Handle the "i2c mm" and "i2c nm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Modify memory. + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} * i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} */ - static int -mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]) +mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[]) { uchar chip; ulong addr; @@ -469,13 +558,9 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]) ulong data; int size = 1; int nbytes; - int j; - extern char console_buffer[]; - if (argc != 3) { - cmd_usage(cmdtp); - return 1; - } + if (argc != 3) + return CMD_RET_USAGE; #ifdef CONFIG_BOOT_RETRY_TIME reset_cmd_timeout(); /* got a good command to get here */ @@ -504,18 +589,9 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]) * 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; } /* @@ -588,23 +664,42 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]) return 0; } -/* +/** + * do_i2c_probe() - Handle the "i2c probe" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: - * i2c probe {addr}{.0, .1, .2} + * i2c probe {addr} + * + * Returns zero (success) if one or more I2C devices was found */ -static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int j; + int addr = -1; + int found = 0; #if defined(CONFIG_SYS_I2C_NOPROBES) int k, skip; - uchar bus = GET_BUS_NUM; + unsigned int bus = GET_BUS_NUM; #endif /* NOPROBES */ + if (argc == 2) + addr = simple_strtol(argv[1], 0, 16); + puts ("Valid chip addresses:"); for (j = 0; j < 128; j++) { + if ((0 <= addr) && (j != addr)) + continue; + #if defined(CONFIG_SYS_I2C_NOPROBES) skip = 0; - for (k=0; k < NUM_ELEMENTS_NOPROBE; k++) { + for (k = 0; k < ARRAY_SIZE(i2c_no_probes); k++) { if (COMPARE_BUS(bus, k) && COMPARE_ADDR(j, k)) { skip = 1; break; @@ -613,30 +708,41 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) if (skip) continue; #endif - if (i2c_probe(j) == 0) + if (i2c_probe(j) == 0) { printf(" %02X", j); + found++; + } } putc ('\n'); #if defined(CONFIG_SYS_I2C_NOPROBES) puts ("Excluded chip addresses:"); - for (k=0; k < NUM_ELEMENTS_NOPROBE; k++) { + for (k = 0; k < ARRAY_SIZE(i2c_no_probes); k++) { if (COMPARE_BUS(bus,k)) printf(" %02X", NO_PROBE_ADDR(k)); } putc ('\n'); #endif - return 0; + return (0 == found); } -/* +/** + * do_i2c_loop() - Handle the "i2c loop" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}] * {length} - Number of bytes to read * {delay} - A DECIMAL number and defaults to 1000 uSec */ -static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; ulong alen; @@ -644,12 +750,9 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) uint length; u_char bytes[16]; int delay; - int j; - if (argc < 3) { - cmd_usage(cmdtp); - return 1; - } + if (argc < 3) + return CMD_RET_USAGE; /* * Chip is always specified. @@ -660,18 +763,9 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) * 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 > 3) { - cmd_usage(cmdtp); - return 1; - } - break; - } else if (argv[2][j] == '\0') - break; - } + alen = get_alen(argv[2]); + if (alen > 3) + return CMD_RET_USAGE; /* * Length is the number of objects, not number of bytes. @@ -703,6 +797,8 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) /* * The SDRAM command is separately configured because many * (most?) embedded boards don't use SDRAM DIMMs. + * + * FIXME: Document and probably move elsewhere! */ #if defined(CONFIG_CMD_SDRAM) static void print_ddr2_tcyc (u_char const b) @@ -756,7 +852,7 @@ static void decode_bits (u_char const b, char const *str[], int const do_once) * Syntax: * i2c sdram {i2c_chip} */ -static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { enum { unknown, EDO, SDRAM, DDR2 } type; @@ -809,10 +905,9 @@ static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) "32 MiB", "16 MiB", "8 MiB", "4 MiB" }; - if (argc < 2) { - cmd_usage(cmdtp); - return 1; - } + if (argc < 2) + return CMD_RET_USAGE; + /* * Chip is always specified. */ @@ -1232,57 +1327,141 @@ static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) } #endif -#if defined(CONFIG_I2C_MUX) -static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +/* + * Syntax: + * i2c edid {i2c_chip} + */ +#if defined(CONFIG_I2C_EDID) +int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - int ret=0; + u_char chip; + struct edid1_info edid; + + if (argc < 2) { + cmd_usage(cmdtp); + return 1; + } + + chip = simple_strtoul(argv[1], NULL, 16); + if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { + puts("Error reading EDID content.\n"); + return 1; + } + + if (edid_check_info(&edid)) { + puts("Content isn't valid EDID.\n"); + return 1; + } + + edid_print_info(&edid); + return 0; + +} +#endif /* CONFIG_I2C_EDID */ + +/** + * do_i2c_show_bus() - Handle the "i2c bus" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero always. + */ +#if defined(CONFIG_SYS_I2C) +int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int i; +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + int j; +#endif if (argc == 1) { /* show all busses */ - I2C_MUX *mux; - I2C_MUX_DEVICE *device = i2c_mux_devices; - - printf ("Busses reached over muxes:\n"); - while (device != NULL) { - printf ("Bus ID: %x\n", device->busid); - printf (" reached over Mux(es):\n"); - mux = device->mux; - while (mux != NULL) { - printf (" %s@%x ch: %x\n", mux->name, mux->chip, mux->channel); - mux = mux->next; + for (i = 0; i < CONFIG_SYS_NUM_I2C_BUSES; i++) { + printf("Bus %d:\t%s", i, I2C_ADAP_NR(i)->name); +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + for (j = 0; j < CONFIG_SYS_I2C_MAX_HOPS; j++) { + if (i2c_bus[i].next_hop[j].chip == 0) + break; + printf("->%s@0x%2x:%d", + i2c_bus[i].next_hop[j].mux.name, + i2c_bus[i].next_hop[j].chip, + i2c_bus[i].next_hop[j].channel); } - device = device->next; +#endif + printf("\n"); } } else { - I2C_MUX_DEVICE *dev; - - dev = i2c_mux_ident_muxstring ((uchar *)argv[1]); - ret = 0; + /* show specific bus */ + i = simple_strtoul(argv[1], NULL, 10); + if (i >= CONFIG_SYS_NUM_I2C_BUSES) { + printf("Invalid bus %d\n", i); + return -1; + } + printf("Bus %d:\t%s", i, I2C_ADAP_NR(i)->name); +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + for (j = 0; j < CONFIG_SYS_I2C_MAX_HOPS; j++) { + if (i2c_bus[i].next_hop[j].chip == 0) + break; + printf("->%s@0x%2x:%d", + i2c_bus[i].next_hop[j].mux.name, + i2c_bus[i].next_hop[j].chip, + i2c_bus[i].next_hop[j].channel); + } +#endif + printf("\n"); } - return ret; + + return 0; } -#endif /* CONFIG_I2C_MUX */ +#endif -#if defined(CONFIG_I2C_MULTI_BUS) -static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +/** + * do_i2c_bus_num() - Handle the "i2c dev" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) +int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - int bus_idx, ret=0; + int ret = 0; + unsigned int bus_no; if (argc == 1) /* querying current setting */ printf("Current bus is %d\n", i2c_get_bus_num()); else { - bus_idx = simple_strtoul(argv[1], NULL, 10); - printf("Setting bus to %d\n", bus_idx); - ret = i2c_set_bus_num(bus_idx); + bus_no = simple_strtoul(argv[1], NULL, 10); + if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) { + printf("Invalid bus %d\n", bus_no); + return -1; + } + printf("Setting bus to %d\n", bus_no); + ret = i2c_set_bus_num(bus_no); if (ret) printf("Failure changing bus number (%d)\n", ret); } return ret; } -#endif /* CONFIG_I2C_MULTI_BUS */ - -static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +#endif /* defined(CONFIG_SYS_I2C) */ + +/** + * do_i2c_bus_speed() - Handle the "i2c speed" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int speed, ret=0; @@ -1299,30 +1478,67 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return ret; } -static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +/** + * do_i2c_mm() - Handle the "i2c mm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { return mod_i2c_mem (cmdtp, 1, flag, argc, argv); } -static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +/** + * do_i2c_nm() - Handle the "i2c nm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { return mod_i2c_mem (cmdtp, 0, flag, argc, argv); } -static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +/** + * do_i2c_reset() - Handle the "i2c reset" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero always. + */ +static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { +#if defined(CONFIG_SYS_I2C) + i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr); +#else i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif return 0; } static cmd_tbl_t cmd_i2c_sub[] = { -#if defined(CONFIG_I2C_MUX) - U_BOOT_CMD_MKENT(bus, 1, 1, do_i2c_add_bus, "", ""), -#endif /* CONFIG_I2C_MUX */ +#if defined(CONFIG_SYS_I2C) + U_BOOT_CMD_MKENT(bus, 1, 1, do_i2c_show_bus, "", ""), +#endif U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""), -#if defined(CONFIG_I2C_MULTI_BUS) +#if defined(CONFIG_SYS_I2C) || \ + defined(CONFIG_I2C_MULTI_BUS) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""), #endif /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) + U_BOOT_CMD_MKENT(edid, 1, 1, do_edid, "", ""), +#endif /* CONFIG_I2C_EDID */ U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""), U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""), U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""), @@ -1330,6 +1546,7 @@ static cmd_tbl_t cmd_i2c_sub[] = { U_BOOT_CMD_MKENT(nm, 2, 1, do_i2c_nm, "", ""), U_BOOT_CMD_MKENT(probe, 0, 1, do_i2c_probe, "", ""), U_BOOT_CMD_MKENT(read, 5, 1, do_i2c_read, "", ""), + U_BOOT_CMD_MKENT(write, 5, 0, do_i2c_write, "", ""), U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""), #if defined(CONFIG_CMD_SDRAM) U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""), @@ -1337,263 +1554,72 @@ static cmd_tbl_t cmd_i2c_sub[] = { U_BOOT_CMD_MKENT(speed, 1, 1, do_i2c_bus_speed, "", ""), }; -static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +#ifdef CONFIG_NEEDS_MANUAL_RELOC +void i2c_reloc(void) { + fixup_cmdtable(cmd_i2c_sub, ARRAY_SIZE(cmd_i2c_sub)); +} +#endif + +/** + * do_i2c() - Handle the "i2c" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { cmd_tbl_t *c; + if (argc < 2) + return CMD_RET_USAGE; + /* Strip off leading 'i2c' command argument */ argc--; argv++; c = find_cmd_tbl(argv[0], &cmd_i2c_sub[0], ARRAY_SIZE(cmd_i2c_sub)); - if (c) { - return c->cmd(cmdtp, flag, argc, argv); - } else { - cmd_usage(cmdtp); - return 1; - } + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; } /***************************************************/ - -U_BOOT_CMD( - i2c, 6, 1, do_i2c, - "I2C sub-system", -#if defined(CONFIG_I2C_MUX) - "bus [muxtype:muxaddr:muxchannel] - add a new bus reached over muxes\ni2c " -#endif /* CONFIG_I2C_MUX */ +#ifdef CONFIG_SYS_LONGHELP +static char i2c_help_text[] = +#if defined(CONFIG_SYS_I2C) + "bus [muxtype:muxaddr:muxchannel] - show I2C bus info\n" +#endif "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n" -#if defined(CONFIG_I2C_MULTI_BUS) +#if defined(CONFIG_SYS_I2C) || \ + defined(CONFIG_I2C_MULTI_BUS) "i2c dev [dev] - show or set current I2C bus\n" #endif /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) + "i2c edid chip - print EDID configuration information\n" +#endif /* CONFIG_I2C_EDID */ "i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n" "i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n" "i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n" "i2c mw chip address[.0, .1, .2] value [count] - write to I2C device (fill)\n" "i2c nm chip address[.0, .1, .2] - write to I2C device (constant address)\n" - "i2c probe - show devices on the I2C bus\n" + "i2c probe [address] - test for and show device(s) on the I2C bus\n" "i2c read chip address[.0, .1, .2] length memaddress - read to memory \n" + "i2c write memaddress chip address[.0, .1, .2] length - write memory to i2c\n" "i2c reset - re-init the I2C Controller\n" #if defined(CONFIG_CMD_SDRAM) "i2c sdram chip - print SDRAM configuration information\n" #endif - "i2c speed [speed] - show or set I2C bus speed" -); - -#if defined(CONFIG_I2C_MUX) -int i2c_mux_add_device(I2C_MUX_DEVICE *dev) -{ - I2C_MUX_DEVICE *devtmp = i2c_mux_devices; - - if (i2c_mux_devices == NULL) { - i2c_mux_devices = dev; - return 0; - } - while (devtmp->next != NULL) - devtmp = devtmp->next; - - devtmp->next = dev; - return 0; -} - -I2C_MUX_DEVICE *i2c_mux_search_device(int id) -{ - I2C_MUX_DEVICE *device = i2c_mux_devices; - - while (device != NULL) { - if (device->busid == id) - return device; - device = device->next; - } - return NULL; -} - -/* searches in the buf from *pos the next ':'. - * returns: - * 0 if found (with *pos = where) - * < 0 if an error occured - * > 0 if the end of buf is reached - */ -static int i2c_mux_search_next (int *pos, uchar *buf, int len) -{ - while ((buf[*pos] != ':') && (*pos < len)) { - *pos += 1; - } - if (*pos >= len) - return 1; - if (buf[*pos] != ':') - return -1; - return 0; -} - -static int i2c_mux_get_busid (void) -{ - int tmp = i2c_mux_busid; - - i2c_mux_busid ++; - return tmp; -} - -/* Analyses a Muxstring and sends immediately the - Commands to the Muxes. Runs from Flash. - */ -int i2c_mux_ident_muxstring_f (uchar *buf) -{ - int pos = 0; - int oldpos; - int ret = 0; - int len = strlen((char *)buf); - int chip; - uchar channel; - int was = 0; - - while (ret == 0) { - oldpos = pos; - /* search name */ - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("ERROR\n"); - /* search address */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("ERROR\n"); - buf[pos] = 0; - chip = simple_strtoul((char *)&buf[oldpos], NULL, 16); - buf[pos] = ':'; - /* search channel */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret < 0) - printf ("ERROR\n"); - was = 0; - if (buf[pos] != 0) { - buf[pos] = 0; - was = 1; - } - channel = simple_strtoul((char *)&buf[oldpos], NULL, 16); - if (was) - buf[pos] = ':'; - if (i2c_write(chip, 0, 0, &channel, 1) != 0) { - printf ("Error setting Mux: chip:%x channel: \ - %x\n", chip, channel); - return -1; - } - pos ++; - oldpos = pos; - - } - - return 0; -} - -/* Analyses a Muxstring and if this String is correct - * adds a new I2C Bus. - */ -I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf) -{ - I2C_MUX_DEVICE *device; - I2C_MUX *mux; - int pos = 0; - int oldpos; - int ret = 0; - int len = strlen((char *)buf); - int was = 0; - - device = (I2C_MUX_DEVICE *)malloc (sizeof(I2C_MUX_DEVICE)); - device->mux = NULL; - device->busid = i2c_mux_get_busid (); - device->next = NULL; - while (ret == 0) { - mux = (I2C_MUX *)malloc (sizeof(I2C_MUX)); - mux->next = NULL; - /* search name of mux */ - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("%s no name.\n", __FUNCTION__); - mux->name = (char *)malloc (pos - oldpos + 1); - memcpy (mux->name, &buf[oldpos], pos - oldpos); - mux->name[pos - oldpos] = 0; - /* search address */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("%s no mux address.\n", __FUNCTION__); - buf[pos] = 0; - mux->chip = simple_strtoul((char *)&buf[oldpos], NULL, 16); - buf[pos] = ':'; - /* search channel */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret < 0) - printf ("%s no mux channel.\n", __FUNCTION__); - was = 0; - if (buf[pos] != 0) { - buf[pos] = 0; - was = 1; - } - mux->channel = simple_strtoul((char *)&buf[oldpos], NULL, 16); - if (was) - buf[pos] = ':'; - if (device->mux == NULL) - device->mux = mux; - else { - I2C_MUX *muxtmp = device->mux; - while (muxtmp->next != NULL) { - muxtmp = muxtmp->next; - } - muxtmp->next = mux; - } - pos ++; - oldpos = pos; - } - if (ret > 0) { - /* Add Device */ - i2c_mux_add_device (device); - return device; - } - - return NULL; -} - -int i2x_mux_select_mux(int bus) -{ - I2C_MUX_DEVICE *dev; - I2C_MUX *mux; - - if ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC) { - /* select Default Mux Bus */ -#if defined(CONFIG_SYS_I2C_IVM_BUS) - i2c_mux_ident_muxstring_f ((uchar *)CONFIG_SYS_I2C_IVM_BUS); -#else - { - unsigned char *buf; - buf = (unsigned char *) getenv("EEprom_ivm"); - if (buf != NULL) - i2c_mux_ident_muxstring_f (buf); - } + "i2c speed [speed] - show or set I2C bus speed"; #endif - return 0; - } - dev = i2c_mux_search_device(bus); - if (dev == NULL) - return -1; - mux = dev->mux; - while (mux != NULL) { - if (i2c_write(mux->chip, 0, 0, &mux->channel, 1) != 0) { - printf ("Error setting Mux: chip:%x channel: \ - %x\n", mux->chip, mux->channel); - return -1; - } - mux = mux->next; - } - return 0; -} -#endif /* CONFIG_I2C_MUX */ +U_BOOT_CMD( + i2c, 6, 1, do_i2c, + "I2C sub-system", + i2c_help_text +);