From 80d9ef8d40b2aa35c4a3483f5cf3549215187a7c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 20 Nov 2014 21:20:32 +0900 Subject: [PATCH 01/19] lib: string: move strlcpy() to a common place Move strlcpy() definition from drivers/usb/gadget/ether.c to lib/string.c because it is a very useful function. Let's add the prototype to include/linux/string.h too. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/usb/gadget/ether.c | 24 ------------------------ include/linux/string.h | 3 +++ lib/string.c | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d0dd29ffb2..ba442d5ed5 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -852,30 +852,6 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ); DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT); #endif - -/** - * strlcpy - Copy a %NUL terminated string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} - /*============================================================================*/ /* diff --git a/include/linux/string.h b/include/linux/string.h index 96348d617f..c7047ba0bc 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -30,6 +30,9 @@ extern char * strcpy(char *,const char *); #ifndef __HAVE_ARCH_STRNCPY extern char * strncpy(char *,const char *, __kernel_size_t); #endif +#ifndef __HAVE_ARCH_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif #ifndef __HAVE_ARCH_STRCAT extern char * strcat(char *, const char *); #endif diff --git a/lib/string.c b/lib/string.c index 29c2ca7ef6..87c9a408e6 100644 --- a/lib/string.c +++ b/lib/string.c @@ -102,6 +102,31 @@ char * strncpy(char * dest,const char *src,size_t count) } #endif +#ifndef __HAVE_ARCH_STRLCPY +/** + * strlcpy - Copy a C-string into a sized buffer + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @size: size of destination buffer + * + * Compatible with *BSD: the result is always a valid + * NUL-terminated string that fits in the buffer (unless, + * of course, the buffer size is zero). It does not pad + * out the result like strncpy() does. + */ +size_t strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = strlen(src); + + if (size) { + size_t len = (ret >= size) ? size - 1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} +#endif + #ifndef __HAVE_ARCH_STRCAT /** * strcat - Append one %NUL-terminated string to another From a56642c7baa02ec4f054d630ec4e5e56d8e087da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 29 Nov 2014 17:01:56 +0900 Subject: [PATCH 02/19] dm_test: improve the appearance shown by "dm tree" command The command "dm tree" lists devices in a tree-like format. This commit makes it look more like what the Unix command "tree" shows. => dm tree Class Probed Name ---------------------------------------- root [ + ] root_driver demo [ ] |-- demo_shape_drv demo [ ] |-- demo_simple_drv demo [ ] |-- demo_shape_drv demo [ ] |-- demo_simple_drv demo [ ] |-- demo_shape_drv test [ ] |-- test_drv test [ ] |-- test_drv test [ ] |-- test_drv gpio [ ] |-- gpio_sandbox serial [ ] |-- serial_sandbox serial [ + ] |-- serial demo [ ] |-- triangle demo [ ] |-- square demo [ ] |-- hexagon gpio [ ] |-- gpios spi [ ] |-- spi@0 spi_emul [ ] | `-- flash@0 cros_ec [ + ] `-- cros-ec@0 Signed-off-by: Masahiro Yamada --- test/dm/cmd_dm.c | 101 ++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c index 26980d209f..79a674efcc 100644 --- a/test/dm/cmd_dm.c +++ b/test/dm/cmd_dm.c @@ -16,59 +16,38 @@ #include #include -/** - * dm_display_line() - Display information about a single device - * - * Displays a single line of information with an option prefix - * - * @dev: Device to display - * @buf: Prefix to display at the start of the line - */ -static void dm_display_line(struct udevice *dev, char *buf) +static void show_devices(struct udevice *dev, int depth, int last_flag) { - printf("%s- %c %s @ %08lx", buf, - dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ', - dev->name, (ulong)map_to_sysmem(dev)); - if (dev->req_seq != -1) - printf(", %d", dev->req_seq); - puts("\n"); -} + int i, is_last; + struct udevice *child; + char class_name[12]; -static int display_succ(struct udevice *in, char *buf) -{ - int len; - int ip = 0; - char local[16]; - struct udevice *pos, *n, *prev = NULL; + /* print the first 11 characters to not break the tree-format. */ + strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name)); + printf(" %-11s [ %c ] ", class_name, + dev->flags & DM_FLAG_ACTIVATED ? '+' : ' '); - dm_display_line(in, buf); - - if (list_empty(&in->child_head)) - return 0; - - len = strlen(buf); - strncpy(local, buf, sizeof(local)); - snprintf(local + len, 2, "|"); - if (len && local[len - 1] == '`') - local[len - 1] = ' '; - - list_for_each_entry_safe(pos, n, &in->child_head, sibling_node) { - if (ip++) - display_succ(prev, local); - prev = pos; + for (i = depth; i >= 0; i--) { + is_last = (last_flag >> i) & 1; + if (i) { + if (is_last) + printf(" "); + else + printf("| "); + } else { + if (is_last) + printf("`-- "); + else + printf("|-- "); + } } - snprintf(local + len, 2, "`"); - display_succ(prev, local); + printf("%s\n", dev->name); - return 0; -} - -static int dm_dump(struct udevice *dev) -{ - if (!dev) - return -EINVAL; - return display_succ(dev, ""); + list_for_each_entry(child, &dev->child_head, sibling_node) { + is_last = list_is_last(&child->sibling_node, &dev->child_head); + show_devices(child, depth + 1, (last_flag << 1) | is_last); + } } static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc, @@ -77,8 +56,30 @@ static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc, struct udevice *root; root = dm_root(); - printf("ROOT %08lx\n", (ulong)map_to_sysmem(root)); - return dm_dump(root); + if (root) { + printf(" Class Probed Name\n"); + printf("----------------------------------------\n"); + show_devices(root, -1, 0); + } + + return 0; +} + +/** + * dm_display_line() - Display information about a single device + * + * Displays a single line of information with an option prefix + * + * @dev: Device to display + */ +static void dm_display_line(struct udevice *dev) +{ + printf("- %c %s @ %08lx", + dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ', + dev->name, (ulong)map_to_sysmem(dev)); + if (dev->req_seq != -1) + printf(", %d", dev->req_seq); + puts("\n"); } static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc, @@ -99,7 +100,7 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc, if (list_empty(&uc->dev_head)) continue; list_for_each_entry(dev, &uc->dev_head, uclass_node) { - dm_display_line(dev, ""); + dm_display_line(dev); } puts("\n"); } From 59c73d7555a88bbe7b42a7153181fe4252e83c24 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:36:35 -0700 Subject: [PATCH 03/19] dm: serial_pl01x: Add missing private data size The private data size is missing from the driver, so we store it at 0, which causes problems when something overwrites memory at 0. Fix this. Change-Id: I6f551ee905b0064ae8343e41e46450c37c8c8c1a Signed-off-by: Simon Glass Tested-by: Stephen Warren --- drivers/serial/serial_pl01x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index e1bf4965f9..75eb6bd729 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -348,6 +348,7 @@ U_BOOT_DRIVER(serial_pl01x) = { .probe = pl01x_serial_probe, .ops = &pl01x_serial_ops, .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct pl01x_priv), }; #endif From 115066666c251c2a481eeff7b700da14eba91d10 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 24 Nov 2014 21:36:34 -0700 Subject: [PATCH 04/19] dm: rpi: Move serial to driver model Adjust the configuration to use the driver model version of the pl01x serial driver. Add the required platform data. Signed-off-by: Simon Glass Tested-by: Stephen Warren --- board/raspberrypi/rpi/rpi.c | 12 ++++++++++++ include/configs/rpi.h | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 51a4fa1030..7dbd40ecf8 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -24,6 +24,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -36,6 +37,17 @@ U_BOOT_DEVICE(bcm2835_gpios) = { .platdata = &gpio_platdata, }; +static const struct pl01x_serial_platdata serial_platdata = { + .base = 0x20201000, + .type = TYPE_PL011, + .clock = 3000000, +}; + +U_BOOT_DEVICE(bcm2835_serials) = { + .name = "serial_pl01x", + .platdata = &serial_platdata, +}; + struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; diff --git a/include/configs/rpi.h b/include/configs/rpi.h index 4d5426e501..c94f411202 100644 --- a/include/configs/rpi.h +++ b/include/configs/rpi.h @@ -34,6 +34,7 @@ #define CONFIG_DM #define CONFIG_CMD_DM #define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL /* Memory layout */ #define CONFIG_NR_DRAM_BANKS 1 @@ -51,6 +52,7 @@ CONFIG_SYS_SDRAM_SIZE - \ GENERATED_GBL_DATA_SIZE) #define CONFIG_SYS_MALLOC_LEN SZ_4M +#define CONFIG_SYS_MALLOC_F_LEN (1 << 10) #define CONFIG_SYS_MEMTEST_START 0x00100000 #define CONFIG_SYS_MEMTEST_END 0x00200000 #define CONFIG_LOADADDR 0x00200000 @@ -92,9 +94,7 @@ #endif /* Console UART */ -#define CONFIG_PL011_SERIAL -#define CONFIG_PL011_CLOCK 3000000 -#define CONFIG_PL01x_PORTS { (void *)0x20201000 } +#define CONFIG_PL01X_SERIAL #define CONFIG_CONS_INDEX 0 #define CONFIG_BAUDRATE 115200 From 59345b1f0f9941d32b45d0e27401355b34106357 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Wed, 8 Oct 2014 22:48:37 +0200 Subject: [PATCH 05/19] lib: errno: introduce errno_str(): returns errno related message The functions error's numbers are standarized - but the error messages are not. The errors are often handled with unclear error messages, so why not use an errno standarized messages. Advantages: - This could decrease the binary size. - Appended with a detailed information, the error message will be clear. This commit introduces new function: - const char *errno_to_str(int errno) The functions returns a pointer to the errno corresponding text message: - if errno is null or positive number - a pointer to "Success" message - if errno is negative - a pointer to errno related message Signed-off-by: Przemyslaw Marczak Reviewed-by: Tom Rini --- include/errno.h | 3 + lib/Makefile | 1 + lib/errno_str.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 lib/errno_str.c diff --git a/include/errno.h b/include/errno.h index e24a33b386..14ac3cb10b 100644 --- a/include/errno.h +++ b/include/errno.h @@ -6,4 +6,7 @@ extern int errno; #define __set_errno(val) do { errno = val; } while (0) +#ifdef CONFIG_ERRNO_STR +const char *errno_str(int errno); +#endif #endif /* _ERRNO_H */ diff --git a/lib/Makefile b/lib/Makefile index 3ceb69752c..07d175f45e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -51,6 +51,7 @@ endif obj-$(CONFIG_ADDR_MAP) += addr_map.o obj-y += hashtable.o obj-y += errno.o +obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-y += display_options.o obj-$(CONFIG_BCH) += bch.o obj-y += crc32.o diff --git a/lib/errno_str.c b/lib/errno_str.c new file mode 100644 index 0000000000..0ba950e970 --- /dev/null +++ b/lib/errno_str.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2014 Samsung Electronics + * Przemyslaw Marczak + * + * SDPX-License-Identifier: GPL-2.0+ + */ +#include +#include + +#define ERRNO_MSG(errno, msg) msg +#define SAME_AS(x) (const char *)&errno_message[x] + +static const char * const errno_message[] = { + ERRNO_MSG(0, "Success"), + ERRNO_MSG(EPERM, "Operation not permitted"), + ERRNO_MSG(ENOEN, "No such file or directory"), + ERRNO_MSG(ESRCH, "No such process"), + ERRNO_MSG(EINTR, "Interrupted system call"), + ERRNO_MSG(EIO, "I/O error"), + ERRNO_MSG(ENXIO, "No such device or address"), + ERRNO_MSG(E2BIG, "Argument list too long"), + ERRNO_MSG(ENOEXEC, "Exec format error"), + ERRNO_MSG(EBADF, "Bad file number"), + ERRNO_MSG(ECHILD, "No child processes"), + ERRNO_MSG(EAGAIN, "Try again"), + ERRNO_MSG(ENOMEM, "Out of memory"), + ERRNO_MSG(EACCES, "Permission denied"), + ERRNO_MSG(EFAULT, "Bad address"), + ERRNO_MSG(ENOTBL, "Block device required"), + ERRNO_MSG(EBUSY, "Device or resource busy"), + ERRNO_MSG(EEXIST, "File exists"), + ERRNO_MSG(EXDEV, "Cross-device link"), + ERRNO_MSG(ENODEV, "No such device"), + ERRNO_MSG(ENOTDIR, "Not a directory"), + ERRNO_MSG(EISDIR, "Is a directory"), + ERRNO_MSG(EINVAL, "Invalid argument"), + ERRNO_MSG(ENFILE, "File table overflow"), + ERRNO_MSG(EMFILE, "Too many open files"), + ERRNO_MSG(ENOTTY, "Not a typewriter"), + ERRNO_MSG(ETXTBSY, "Text file busy"), + ERRNO_MSG(EFBIG, "File too large"), + ERRNO_MSG(ENOSPC, "No space left on device"), + ERRNO_MSG(ESPIPE, "Illegal seek"), + ERRNO_MSG(EROFS, "Read-only file system"), + ERRNO_MSG(EMLINK, "Too many links"), + ERRNO_MSG(EPIPE, "Broken pipe"), + ERRNO_MSG(EDOM, "Math argument out of domain of func"), + ERRNO_MSG(ERANGE, "Math result not representable"), + ERRNO_MSG(EDEADLK, "Resource deadlock would occur"), + ERRNO_MSG(ENAMETOOLONG, "File name too long"), + ERRNO_MSG(ENOLCK, "No record locks available"), + ERRNO_MSG(ENOSYS, "Function not implemented"), + ERRNO_MSG(ENOTEMPTY, "Directory not empty"), + ERRNO_MSG(ELOOP, "Too many symbolic links encountered"), + ERRNO_MSG(EWOULDBLOCK, SAME_AS(EAGAIN)), + ERRNO_MSG(ENOMSG, "No message of desired type"), + ERRNO_MSG(EIDRM, "Identifier removed"), + ERRNO_MSG(ECHRNG, "Channel number out of range"), + ERRNO_MSG(EL2NSYNC, "Level 2 not synchronized"), + ERRNO_MSG(EL3HLT, "Level 3 halted"), + ERRNO_MSG(EL3RST, "Level 3 reset"), + ERRNO_MSG(ELNRNG, "Link number out of range"), + ERRNO_MSG(EUNATCH, "Protocol driver not attached"), + ERRNO_MSG(ENOCSI, "No CSI structure available"), + ERRNO_MSG(EL2HLT, "Level 2 halted"), + ERRNO_MSG(EBADE, "Invalid exchange"), + ERRNO_MSG(EBADR, "Invalid request descriptor"), + ERRNO_MSG(EXFULL, "Exchange full"), + ERRNO_MSG(ENOANO, "No anode"), + ERRNO_MSG(EBADRQC, "Invalid request code"), + ERRNO_MSG(EBADSLT, "Invalid slot"), + ERRNO_MSG(EDEADLOCK, SAME_AS(EDEADLK)), + ERRNO_MSG(EBFONT, "Bad font file format"), + ERRNO_MSG(ENOSTR, "Device not a stream"), + ERRNO_MSG(ENODATA, "No data available"), + ERRNO_MSG(ETIME, "Timer expired"), + ERRNO_MSG(ENOSR, "Out of streams resources"), + ERRNO_MSG(ENONET, "Machine is not on the network"), + ERRNO_MSG(ENOPKG, "Package not installed"), + ERRNO_MSG(EREMOTE, "Object is remote"), + ERRNO_MSG(ENOLINK, "Link has been severed"), + ERRNO_MSG(EADV, "Advertise error"), + ERRNO_MSG(ESRMNT, "Srmount error"), + ERRNO_MSG(ECOMM, "Communication error on send"), + ERRNO_MSG(EPROTO, "Protocol error"), + ERRNO_MSG(EMULTIHOP, "Multihop attempted"), + ERRNO_MSG(EDOTDOT, "RFS specific error"), + ERRNO_MSG(EBADMSG, "Not a data message"), + ERRNO_MSG(EOVERFLOW, "Value too large for defined data type"), + ERRNO_MSG(ENOTUNIQ, "Name not unique on network"), + ERRNO_MSG(EBADFD, "File descriptor in bad state"), + ERRNO_MSG(EREMCHG, "Remote address changed"), + ERRNO_MSG(ELIBACC, "Can not access a needed shared library"), + ERRNO_MSG(ELIBBAD, "Accessing a corrupted shared library"), + ERRNO_MSG(ELIBSCN, ".lib section in a.out corrupted"), + ERRNO_MSG(ELIBMAX, "Attempting to link in too many shared libraries"), + ERRNO_MSG(ELIBEXEC, "Cannot exec a shared library directly"), + ERRNO_MSG(EILSEQ, "Illegal byte sequence"), + ERRNO_MSG(ERESTART, "Interrupted system call should be restarted"), + ERRNO_MSG(ESTRPIPE, "Streams pipe error"), + ERRNO_MSG(EUSERS, "Too many users"), + ERRNO_MSG(ENOTSOCK, "Socket operation on non-socket"), + ERRNO_MSG(EDESTADDRREQ, "Destination address required"), + ERRNO_MSG(EMSGSIZE, "Message too long"), + ERRNO_MSG(EPROTOTYPE, "Protocol wrong type for socket"), + ERRNO_MSG(ENOPROTOOPT, "Protocol not available"), + ERRNO_MSG(EPROTONOSUPPORT, "Protocol not supported"), + ERRNO_MSG(ESOCKTNOSUPPORT, "Socket type not supported"), + ERRNO_MSG(EOPNOTSUPP, "Operation not supported on transport endpoint"), + ERRNO_MSG(EPFNOSUPPORT, "Protocol family not supported"), + ERRNO_MSG(AFNOSUPPORT, "Address family not supported by protocol"), + ERRNO_MSG(EADDRINUSE, "Address already in use"), + ERRNO_MSG(EADDRNOTAVAIL, "Cannot assign requested address"), + ERRNO_MSG(ENETDOWN, "Network is down"), + ERRNO_MSG(ENETUNREACH, "Network is unreachable"), + ERRNO_MSG(ENETRESET, "Network dropped connection because of reset"), + ERRNO_MSG(ECONNABORTED, "Software caused connection abort"), + ERRNO_MSG(ECONNRESET, "Connection reset by peer"), + ERRNO_MSG(ENOBUFS, "No buffer space available"), + ERRNO_MSG(EISCONN, "Transport endpoint is already connected"), + ERRNO_MSG(ENOTCONN, "Transport endpoint is not connected"), + ERRNO_MSG(ESHUTDOWN, "Cannot send after transport endpoint shutdown"), + ERRNO_MSG(ETOOMANYREFS, "Too many references: cannot splice"), + ERRNO_MSG(ETIMEDOUT, "Connection timed out"), + ERRNO_MSG(ECONNREFUSED, "Connection refused"), + ERRNO_MSG(EHOSTDOWN, "Host is down"), + ERRNO_MSG(EHOSTUNREACH, "No route to host"), + ERRNO_MSG(EALREADY, "Operation already in progress"), + ERRNO_MSG(EINPROGRESS, "Operation now in progress"), + ERRNO_MSG(ESTALE, "Stale NFS file handle"), + ERRNO_MSG(EUCLEAN, "Structure needs cleaning"), + ERRNO_MSG(ENOTNAM, "Not a XENIX named type file"), + ERRNO_MSG(ENAVAIL, "No XENIX semaphores available"), + ERRNO_MSG(EISNAM, "Is a named type file"), + ERRNO_MSG(EREMOTEIO, "Remote I/O error"), + ERRNO_MSG(EDQUOT, "Quota exceeded"), + ERRNO_MSG(ENOMEDIUM, "No medium found"), + ERRNO_MSG(EMEDIUMTYPE, "Wrong medium type"), +}; + +const char *errno_str(int errno) +{ + if (errno >= 0) + return errno_message[0]; + + return errno_message[abs(errno)]; +} From c6202d857ebce5d6c8f0ec1d8d30352195546280 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:47 -0700 Subject: [PATCH 06/19] dm: i2c: Add a uclass for I2C The uclass implements the same operations as the current I2C framework but makes some changes to make it fit driver model better: - Remove the chip address from API calls - Remove the address length from API calls - Remove concept of 'current' I2C bus - Drop all existing init functions Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada Signed-off-by: Simon Glass --- drivers/i2c/Makefile | 1 + drivers/i2c/i2c-uclass.c | 466 +++++++++++++++++++++++++++++++++++++ include/config_fallbacks.h | 6 + include/dm/uclass-id.h | 2 + include/i2c.h | 352 ++++++++++++++++++++++++++++ 5 files changed, 827 insertions(+) create mode 100644 drivers/i2c/i2c-uclass.c diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index dae3d71d2b..063e097603 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -4,6 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_I2C) += i2c-uclass.o obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c new file mode 100644 index 0000000000..005bf8662f --- /dev/null +++ b/drivers/i2c/i2c-uclass.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define I2C_MAX_OFFSET_LEN 4 + +/** + * i2c_setup_offset() - Set up a new message with a chip offset + * + * @chip: Chip to use + * @offset: Byte offset within chip + * @offset_buf: Place to put byte offset + * @msg: Message buffer + * @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the + * message is still set up but will not contain an offset. + */ +static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset, + uint8_t offset_buf[], struct i2c_msg *msg) +{ + int offset_len; + + msg->addr = chip->chip_addr; + msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + msg->len = chip->offset_len; + msg->buf = offset_buf; + if (!chip->offset_len) + return -EADDRNOTAVAIL; + assert(chip->offset_len <= I2C_MAX_OFFSET_LEN); + offset_len = chip->offset_len; + while (offset_len--) + *offset_buf++ = offset >> (8 * offset_len); + + return 0; +} + +static int i2c_read_bytewise(struct udevice *dev, uint offset, + uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[2], *ptr; + uint8_t offset_buf[I2C_MAX_OFFSET_LEN]; + int ret; + int i; + + for (i = 0; i < len; i++) { + if (i2c_setup_offset(chip, offset + i, offset_buf, msg)) + return -EINVAL; + ptr = msg + 1; + ptr->addr = chip->chip_addr; + ptr->flags = msg->flags | I2C_M_RD; + ptr->len = 1; + ptr->buf = &buffer[i]; + ptr++; + + ret = ops->xfer(bus, msg, ptr - msg); + if (ret) + return ret; + } + + return 0; +} + +static int i2c_write_bytewise(struct udevice *dev, uint offset, + const uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + uint8_t buf[I2C_MAX_OFFSET_LEN + 1]; + int ret; + int i; + + for (i = 0; i < len; i++) { + if (i2c_setup_offset(chip, offset + i, buf, msg)) + return -EINVAL; + buf[msg->len++] = buffer[i]; + + ret = ops->xfer(bus, msg, 1); + if (ret) + return ret; + } + + return 0; +} + +int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[2], *ptr; + uint8_t offset_buf[I2C_MAX_OFFSET_LEN]; + int msg_count; + + if (!ops->xfer) + return -ENOSYS; + if (chip->flags & DM_I2C_CHIP_RD_ADDRESS) + return i2c_read_bytewise(dev, offset, buffer, len); + ptr = msg; + if (!i2c_setup_offset(chip, offset, offset_buf, ptr)) + ptr++; + + if (len) { + ptr->addr = chip->chip_addr; + ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + ptr->flags |= I2C_M_RD; + ptr->len = len; + ptr->buf = buffer; + ptr++; + } + msg_count = ptr - msg; + + return ops->xfer(bus, msg, msg_count); +} + +int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + + if (!ops->xfer) + return -ENOSYS; + + if (chip->flags & DM_I2C_CHIP_WR_ADDRESS) + return i2c_write_bytewise(dev, offset, buffer, len); + /* + * The simple approach would be to send two messages here: one to + * set the offset and one to write the bytes. However some drivers + * will not be expecting this, and some chips won't like how the + * driver presents this on the I2C bus. + * + * The API does not support separate offset and data. We could extend + * it with a flag indicating that there is data in the next message + * that needs to be processed in the same transaction. We could + * instead add an additional buffer to each message. For now, handle + * this in the uclass since it isn't clear what the impact on drivers + * would be with this extra complication. Unfortunately this means + * copying the message. + * + * Use the stack for small messages, malloc() for larger ones. We + * need to allow space for the offset (up to 4 bytes) and the message + * itself. + */ + if (len < 64) { + uint8_t buf[I2C_MAX_OFFSET_LEN + len]; + + i2c_setup_offset(chip, offset, buf, msg); + msg->len += len; + memcpy(buf + chip->offset_len, buffer, len); + + return ops->xfer(bus, msg, 1); + } else { + uint8_t *buf; + int ret; + + buf = malloc(I2C_MAX_OFFSET_LEN + len); + if (!buf) + return -ENOMEM; + i2c_setup_offset(chip, offset, buf, msg); + msg->len += len; + memcpy(buf + chip->offset_len, buffer, len); + + ret = ops->xfer(bus, msg, 1); + free(buf); + return ret; + } +} + +/** + * i2c_probe_chip() - probe for a chip on a bus + * + * @bus: Bus to probe + * @chip_addr: Chip address to probe + * @flags: Flags for the chip + * @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip + * does not respond to probe + */ +static int i2c_probe_chip(struct udevice *bus, uint chip_addr, + enum dm_i2c_chip_flags chip_flags) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct i2c_msg msg[1]; + int ret; + + if (ops->probe_chip) { + ret = ops->probe_chip(bus, chip_addr, chip_flags); + if (!ret || ret != -ENOSYS) + return ret; + } + + if (!ops->xfer) + return -ENOSYS; + + /* Probe with a zero-length message */ + msg->addr = chip_addr; + msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; + msg->len = 0; + msg->buf = NULL; + + return ops->xfer(bus, msg, 1); +} + +static int i2c_bind_driver(struct udevice *bus, uint chip_addr, + struct udevice **devp) +{ + struct dm_i2c_chip chip; + char name[30], *str; + struct udevice *dev; + int ret; + + snprintf(name, sizeof(name), "generic_%x", chip_addr); + str = strdup(name); + ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev); + debug("%s: device_bind_driver: ret=%d\n", __func__, ret); + if (ret) + goto err_bind; + + /* Tell the device what we know about it */ + memset(&chip, '\0', sizeof(chip)); + chip.chip_addr = chip_addr; + chip.offset_len = 1; /* we assume */ + ret = device_probe_child(dev, &chip); + debug("%s: device_probe_child: ret=%d\n", __func__, ret); + if (ret) + goto err_probe; + + *devp = dev; + return 0; + +err_probe: + device_unbind(dev); +err_bind: + free(str); + return ret; +} + +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp) +{ + struct udevice *dev; + + debug("%s: Searching bus '%s' for address %02x: ", __func__, + bus->name, chip_addr); + for (device_find_first_child(bus, &dev); dev; + device_find_next_child(&dev)) { + struct dm_i2c_chip store; + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + int ret; + + if (!chip) { + chip = &store; + i2c_chip_ofdata_to_platdata(gd->fdt_blob, + dev->of_offset, chip); + } + if (chip->chip_addr == chip_addr) { + ret = device_probe(dev); + debug("found, ret=%d\n", ret); + if (ret) + return ret; + *devp = dev; + return 0; + } + } + debug("not found\n"); + return i2c_bind_driver(bus, chip_addr, devp); +} + +int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp) +{ + struct udevice *bus; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus); + if (ret) { + debug("Cannot find I2C bus %d\n", busnum); + return ret; + } + ret = i2c_get_chip(bus, chip_addr, devp); + if (ret) { + debug("Cannot find I2C chip %02x on bus %d\n", chip_addr, + busnum); + return ret; + } + + return 0; +} + +int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags, + struct udevice **devp) +{ + int ret; + + *devp = NULL; + + /* First probe that chip */ + ret = i2c_probe_chip(bus, chip_addr, chip_flags); + debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name, + chip_addr, ret); + if (ret) + return ret; + + /* The chip was found, see if we have a driver, and probe it */ + ret = i2c_get_chip(bus, chip_addr, devp); + debug("%s: i2c_get_chip: ret=%d\n", __func__, ret); + + return ret; +} + +int i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct dm_i2c_bus *i2c = bus->uclass_priv; + int ret; + + /* + * If we have a method, call it. If not then the driver probably wants + * to deal with speed changes on the next transfer. It can easily read + * the current speed from this uclass + */ + if (ops->set_bus_speed) { + ret = ops->set_bus_speed(bus, speed); + if (ret) + return ret; + } + i2c->speed_hz = speed; + + return 0; +} + +/* + * i2c_get_bus_speed: + * + * Returns speed of selected I2C bus in Hz + */ +int i2c_get_bus_speed(struct udevice *bus) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + struct dm_i2c_bus *i2c = bus->uclass_priv; + + if (!ops->get_bus_speed) + return i2c->speed_hz; + + return ops->get_bus_speed(bus); +} + +int i2c_set_chip_flags(struct udevice *dev, uint flags) +{ + struct udevice *bus = dev->parent; + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + struct dm_i2c_ops *ops = i2c_get_ops(bus); + int ret; + + if (ops->set_flags) { + ret = ops->set_flags(dev, flags); + if (ret) + return ret; + } + chip->flags = flags; + + return 0; +} + +int i2c_get_chip_flags(struct udevice *dev, uint *flagsp) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + + *flagsp = chip->flags; + + return 0; +} + +int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len) +{ + struct dm_i2c_chip *chip = dev_get_parentdata(dev); + + if (offset_len > I2C_MAX_OFFSET_LEN) + return -EINVAL; + chip->offset_len = offset_len; + + return 0; +} + +int i2c_deblock(struct udevice *bus) +{ + struct dm_i2c_ops *ops = i2c_get_ops(bus); + + /* + * We could implement a software deblocking here if we could get + * access to the GPIOs used by I2C, and switch them to GPIO mode + * and then back to I2C. This is somewhat beyond our powers in + * driver model at present, so for now just fail. + * + * See https://patchwork.ozlabs.org/patch/399040/ + */ + if (!ops->deblock) + return -ENOSYS; + + return ops->deblock(bus); +} + +int i2c_chip_ofdata_to_platdata(const void *blob, int node, + struct dm_i2c_chip *chip) +{ + chip->offset_len = 1; /* default */ + chip->flags = 0; + chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1); + if (chip->chip_addr == -1) { + debug("%s: I2C Node '%s' has no 'reg' property\n", __func__, + fdt_get_name(blob, node, NULL)); + return -EINVAL; + } + + return 0; +} + +static int i2c_post_probe(struct udevice *dev) +{ + struct dm_i2c_bus *i2c = dev->uclass_priv; + + i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", 100000); + + return i2c_set_bus_speed(dev, i2c->speed_hz); +} + +int i2c_post_bind(struct udevice *dev) +{ + /* Scan the bus for devices */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + +UCLASS_DRIVER(i2c) = { + .id = UCLASS_I2C, + .name = "i2c", + .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus), + .post_bind = i2c_post_bind, + .post_probe = i2c_post_probe, +}; + +UCLASS_DRIVER(i2c_generic) = { + .id = UCLASS_I2C_GENERIC, + .name = "i2c_generic", +}; + +U_BOOT_DRIVER(i2c_generic_chip_drv) = { + .name = "i2c_generic_chip_drv", + .id = UCLASS_I2C_GENERIC, +}; diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h index 508db5626b..ddfe0450d2 100644 --- a/include/config_fallbacks.h +++ b/include/config_fallbacks.h @@ -91,4 +91,10 @@ #undef CONFIG_IMAGE_FORMAT_LEGACY #endif +#ifdef CONFIG_DM_I2C +# ifdef CONFIG_SYS_I2C +# error "Cannot define CONFIG_SYS_I2C when CONFIG_DM_I2C is used" +# endif +#endif + #endif /* __CONFIG_FALLBACKS_H */ diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 202f59b505..01866c3a9c 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -29,6 +29,8 @@ enum uclass_id { UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_CROS_EC, /* Chrome OS EC */ UCLASS_THERMAL, /* Thermal sensor */ + UCLASS_I2C, /* I2C bus */ + UCLASS_I2C_GENERIC, /* Generic I2C device */ UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/i2c.h b/include/i2c.h index 1b4078ed62..9c6a60cf9a 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -17,6 +17,355 @@ #ifndef _I2C_H_ #define _I2C_H_ +/* + * For now there are essentially two parts to this file - driver model + * here at the top, and the older code below (with CONFIG_SYS_I2C being + * most recent). The plan is to migrate everything to driver model. + * The driver model structures and API are separate as they are different + * enough as to be incompatible for compilation purposes. + */ + +#ifdef CONFIG_DM_I2C + +enum dm_i2c_chip_flags { + DM_I2C_CHIP_10BIT = 1 << 0, /* Use 10-bit addressing */ + DM_I2C_CHIP_RD_ADDRESS = 1 << 1, /* Send address for each read byte */ + DM_I2C_CHIP_WR_ADDRESS = 1 << 2, /* Send address for each write byte */ +}; + +/** + * struct dm_i2c_chip - information about an i2c chip + * + * An I2C chip is a device on the I2C bus. It sits at a particular address + * and normally supports 7-bit or 10-bit addressing. + * + * To obtain this structure, use dev_get_parentdata(dev) where dev is the + * chip to examine. + * + * @chip_addr: Chip address on bus + * @offset_len: Length of offset in bytes. A single byte offset can + * represent up to 256 bytes. A value larger than 1 may be + * needed for larger devices. + * @flags: Flags for this chip (dm_i2c_chip_flags) + * @emul: Emulator for this chip address (only used for emulation) + */ +struct dm_i2c_chip { + uint chip_addr; + uint offset_len; + uint flags; +#ifdef CONFIG_SANDBOX + struct udevice *emul; +#endif +}; + +/** + * struct dm_i2c_bus- information about an i2c bus + * + * An I2C bus contains 0 or more chips on it, each at its own address. The + * bus can operate at different speeds (measured in Hz, typically 100KHz + * or 400KHz). + * + * To obtain this structure, use bus->uclass_priv where bus is the I2C + * bus udevice. + * + * @speed_hz: Bus speed in hertz (typically 100000) + */ +struct dm_i2c_bus { + int speed_hz; +}; + +/** + * i2c_read() - read bytes from an I2C chip + * + * To obtain an I2C device (called a 'chip') given the I2C bus address you + * can use i2c_get_chip(). To obtain a bus by bus number use + * uclass_get_device_by_seq(UCLASS_I2C, ). + * + * To set the address length of a devce use i2c_set_addr_len(). It + * defaults to 1. + * + * @dev: Chip to read from + * @offset: Offset within chip to start reading + * @buffer: Place to put data + * @len: Number of bytes to read + * + * @return 0 on success, -ve on failure + */ +int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, + int len); + +/** + * i2c_write() - write bytes to an I2C chip + * + * See notes for i2c_read() above. + * + * @dev: Chip to write to + * @offset: Offset within chip to start writing + * @buffer: Buffer containing data to write + * @len: Number of bytes to write + * + * @return 0 on success, -ve on failure + */ +int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, + int len); + +/** + * i2c_probe() - probe a particular chip address + * + * This can be useful to check for the existence of a chip on the bus. + * It is typically implemented by writing the chip address to the bus + * and checking that the chip replies with an ACK. + * + * @bus: Bus to probe + * @chip_addr: 7-bit address to probe (10-bit and others are not supported) + * @chip_flags: Flags for the probe (see enum dm_i2c_chip_flags) + * @devp: Returns the device found, or NULL if none + * @return 0 if a chip was found at that address, -ve if not + */ +int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags, + struct udevice **devp); + +/** + * i2c_set_bus_speed() - set the speed of a bus + * + * @bus: Bus to adjust + * @speed: Requested speed in Hz + * @return 0 if OK, -EINVAL for invalid values + */ +int i2c_set_bus_speed(struct udevice *bus, unsigned int speed); + +/** + * i2c_get_bus_speed() - get the speed of a bus + * + * @bus: Bus to check + * @return speed of selected I2C bus in Hz, -ve on error + */ +int i2c_get_bus_speed(struct udevice *bus); + +/** + * i2c_set_chip_flags() - set flags for a chip + * + * Typically addresses are 7 bits, but for 10-bit addresses you should set + * flags to DM_I2C_CHIP_10BIT. All accesses will then use 10-bit addressing. + * + * @dev: Chip to adjust + * @flags: New flags + * @return 0 if OK, -EINVAL if value is unsupported, other -ve value on error + */ +int i2c_set_chip_flags(struct udevice *dev, uint flags); + +/** + * i2c_get_chip_flags() - get flags for a chip + * + * @dev: Chip to check + * @flagsp: Place to put flags + * @return 0 if OK, other -ve value on error + */ +int i2c_get_chip_flags(struct udevice *dev, uint *flagsp); + +/** + * i2c_set_offset_len() - set the offset length for a chip + * + * The offset used to access a chip may be up to 4 bytes long. Typically it + * is only 1 byte, which is enough for chips with 256 bytes of memory or + * registers. The default value is 1, but you can call this function to + * change it. + * + * @offset_len: New offset length value (typically 1 or 2) + */ + +int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len); +/** + * i2c_deblock() - recover a bus that is in an unknown state + * + * See the deblock() method in 'struct dm_i2c_ops' for full information + * + * @bus: Bus to recover + * @return 0 if OK, -ve on error + */ +int i2c_deblock(struct udevice *bus); + +/* + * Not all of these flags are implemented in the U-Boot API + */ +enum dm_i2c_msg_flags { + I2C_M_TEN = 0x0010, /* ten-bit chip address */ + I2C_M_RD = 0x0001, /* read data, from slave to master */ + I2C_M_STOP = 0x8000, /* send stop after this message */ + I2C_M_NOSTART = 0x4000, /* no start before this message */ + I2C_M_REV_DIR_ADDR = 0x2000, /* invert polarity of R/W bit */ + I2C_M_IGNORE_NAK = 0x1000, /* continue after NAK */ + I2C_M_NO_RD_ACK = 0x0800, /* skip the Ack bit on reads */ + I2C_M_RECV_LEN = 0x0400, /* length is first received byte */ +}; + +/** + * struct i2c_msg - an I2C message + * + * @addr: Slave address + * @flags: Flags (see enum dm_i2c_msg_flags) + * @len: Length of buffer in bytes, may be 0 for a probe + * @buf: Buffer to send/receive, or NULL if no data + */ +struct i2c_msg { + uint addr; + uint flags; + uint len; + u8 *buf; +}; + +/** + * struct i2c_msg_list - a list of I2C messages + * + * This is called i2c_rdwr_ioctl_data in Linux but the name does not seem + * appropriate in U-Boot. + * + * @msg: Pointer to i2c_msg array + * @nmsgs: Number of elements in the array + */ +struct i2c_msg_list { + struct i2c_msg *msgs; + uint nmsgs; +}; + +/** + * struct dm_i2c_ops - driver operations for I2C uclass + * + * Drivers should support these operations unless otherwise noted. These + * operations are intended to be used by uclass code, not directly from + * other code. + */ +struct dm_i2c_ops { + /** + * xfer() - transfer a list of I2C messages + * + * @bus: Bus to read from + * @msg: List of messages to transfer + * @nmsgs: Number of messages in the list + * @return 0 if OK, -EREMOTEIO if the slave did not ACK a byte, + * -ECOMM if the speed cannot be supported, -EPROTO if the chip + * flags cannot be supported, other -ve value on some other error + */ + int (*xfer)(struct udevice *bus, struct i2c_msg *msg, int nmsgs); + + /** + * probe_chip() - probe for the presense of a chip address + * + * This function is optional. If omitted, the uclass will send a zero + * length message instead. + * + * @bus: Bus to probe + * @chip_addr: Chip address to probe + * @chip_flags: Probe flags (enum dm_i2c_chip_flags) + * @return 0 if chip was found, -EREMOTEIO if not, -ENOSYS to fall back + * to default probem other -ve value on error + */ + int (*probe_chip)(struct udevice *bus, uint chip_addr, uint chip_flags); + + /** + * set_bus_speed() - set the speed of a bus (optional) + * + * The bus speed value will be updated by the uclass if this function + * does not return an error. This method is optional - if it is not + * provided then the driver can read the speed from + * bus->uclass_priv->speed_hz + * + * @bus: Bus to adjust + * @speed: Requested speed in Hz + * @return 0 if OK, -EINVAL for invalid values + */ + int (*set_bus_speed)(struct udevice *bus, unsigned int speed); + + /** + * get_bus_speed() - get the speed of a bus (optional) + * + * Normally this can be provided by the uclass, but if you want your + * driver to check the bus speed by looking at the hardware, you can + * implement that here. This method is optional. This method would + * normally be expected to return bus->uclass_priv->speed_hz. + * + * @bus: Bus to check + * @return speed of selected I2C bus in Hz, -ve on error + */ + int (*get_bus_speed)(struct udevice *bus); + + /** + * set_flags() - set the flags for a chip (optional) + * + * This is generally implemented by the uclass, but drivers can + * check the value to ensure that unsupported options are not used. + * This method is optional. If provided, this method will always be + * called when the flags change. + * + * @dev: Chip to adjust + * @flags: New flags value + * @return 0 if OK, -EINVAL if value is unsupported + */ + int (*set_flags)(struct udevice *dev, uint flags); + + /** + * deblock() - recover a bus that is in an unknown state + * + * I2C is a synchronous protocol and resets of the processor in the + * middle of an access can block the I2C Bus until a powerdown of + * the full unit is done. This is because slaves can be stuck + * waiting for addition bus transitions for a transaction that will + * never complete. Resetting the I2C master does not help. The only + * way is to force the bus through a series of transitions to make + * sure that all slaves are done with the transaction. This method + * performs this 'deblocking' if support by the driver. + * + * This method is optional. + */ + int (*deblock)(struct udevice *bus); +}; + +#define i2c_get_ops(dev) ((struct dm_i2c_ops *)(dev)->driver->ops) + +/** + * i2c_get_chip() - get a device to use to access a chip on a bus + * + * This returns the device for the given chip address. The device can then + * be used with calls to i2c_read(), i2c_write(), i2c_probe(), etc. + * + * @bus: Bus to examine + * @chip_addr: Chip address for the new device + * @devp: Returns pointer to new device if found or -ENODEV if not + * found + */ +int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp); + +/** + * i2c_get_chip() - get a device to use to access a chip on a bus number + * + * This returns the device for the given chip address on a particular bus + * number. + * + * @busnum: Bus number to examine + * @chip_addr: Chip address for the new device + * @devp: Returns pointer to new device if found or -ENODEV if not + * found + */ +int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp); + +/** + * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data + * + * This decodes the chip address from a device tree node and puts it into + * its dm_i2c_chip structure. This should be called in your driver's + * ofdata_to_platdata() method. + * + * @blob: Device tree blob + * @node: Node offset to read from + * @spi: Place to put the decoded information + */ +int i2c_chip_ofdata_to_platdata(const void *blob, int node, + struct dm_i2c_chip *chip); + +#endif + +#ifndef CONFIG_DM_I2C + /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * @@ -451,4 +800,7 @@ int i2c_get_bus_num_fdt(int node); * @return 0 if port was reset, -1 if not found */ int i2c_reset_port_fdt(const void *blob, int node); + +#endif /* !CONFIG_DM_I2C */ + #endif /* _I2C_H_ */ From 63656b762e50b2f11e228d94fdbb025a84900c71 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:48 -0700 Subject: [PATCH 07/19] dm: i2c: Implement driver model support in the i2c command The concept of a 'current bus' is now implemented in the command line rather than in the uclass. Also the address length does not need to be specified with each command - really we should consider dropping this from most commands but it works OK for now. Signed-off-by: Simon Glass Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada --- common/cmd_i2c.c | 376 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 323 insertions(+), 53 deletions(-) diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index c266b88e5b..22db1bb47c 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -69,8 +69,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES; #define DISP_LINE_LEN 16 +/* + * Default for driver model is to use the chip's existing address length. + * For legacy code, this is not stored, so we need to use a suitable + * default. + */ +#ifdef CONFIG_DM_I2C +#define DEFAULT_ADDR_LEN (-1) +#else +#define DEFAULT_ADDR_LEN 1 +#endif + +#ifdef CONFIG_DM_I2C +static struct udevice *i2c_cur_bus; + +static int i2c_set_bus_num(unsigned int busnum) +{ + struct udevice *bus; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus); + if (ret) { + debug("%s: No bus %d\n", __func__, busnum); + return ret; + } + i2c_cur_bus = bus; + + return 0; +} + +static int i2c_get_cur_bus(struct udevice **busp) +{ + if (!i2c_cur_bus) { + puts("No I2C bus selected\n"); + return -ENODEV; + } + *busp = i2c_cur_bus; + + return 0; +} + +static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp) +{ + struct udevice *bus; + int ret; + + ret = i2c_get_cur_bus(&bus); + if (ret) + return ret; + + return i2c_get_chip(bus, chip_addr, devp); +} + +#endif + /** * i2c_init_board() - Board-specific I2C bus init * @@ -143,7 +199,7 @@ void i2c_init_board(void) * * Returns I2C bus speed in Hz. */ -#if !defined(CONFIG_SYS_I2C) +#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_DM_I2C) /* * TODO: Implement architecture-specific get/set functions * Should go away, if we switched completely to new multibus support @@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed) * * Returns the address length. */ -static uint get_alen(char *arg) +static uint get_alen(char *arg, int default_len) { int j; int alen; - alen = 1; + alen = default_len; for (j = 0; j < 8; j++) { if (arg[j] == '.') { alen = arg[j+1] - '0'; @@ -227,8 +283,13 @@ static int i2c_report_err(int ret, enum i2c_err_op op) static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - uint devaddr, alen, length; + uint devaddr, length; + int alen; u_char *memaddr; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 5) return CMD_RET_USAGE; @@ -243,7 +304,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv * 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; @@ -257,18 +318,31 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv */ memaddr = (u_char *)simple_strtoul(argv[4], NULL, 16); - if (i2c_read(chip, devaddr, alen, memaddr, length) != 0) { - i2c_report_err(-1, I2C_ERR_READ); - return 1; - } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (!ret) + ret = i2c_read(dev, devaddr, memaddr, length); +#else + ret = i2c_read(chip, devaddr, alen, memaddr, length); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + 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; + uint devaddr, length; + int alen; u_char *memaddr; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 5) return cmd_usage(cmdtp); @@ -288,7 +362,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ * 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr = simple_strtoul(argv[3], NULL, 16); - alen = get_alen(argv[3]); + alen = get_alen(argv[3], DEFAULT_ADDR_LEN); if (alen > 3) return cmd_usage(cmdtp); @@ -297,10 +371,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ */ length = simple_strtoul(argv[4], NULL, 16); +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif + while (length-- > 0) { - if (i2c_write(chip, devaddr++, alen, memaddr++, 1) != 0) { - return i2c_report_err(-1, I2C_ERR_WRITE); - } +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, devaddr++, memaddr++, 1); +#else + ret = i2c_write(chip, devaddr++, alen, memaddr++, 1); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); /* * No write delay with FRAM devices. */ @@ -311,6 +397,38 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ return 0; } +#ifdef CONFIG_DM_I2C +static int do_i2c_flags(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + uint flags; + int chip; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + chip = simple_strtoul(argv[1], NULL, 16); + ret = i2c_get_cur_bus_chip(chip, &dev); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + + if (argc > 2) { + flags = simple_strtoul(argv[2], NULL, 16); + ret = i2c_set_chip_flags(dev, flags); + } else { + ret = i2c_get_chip_flags(dev, &flags); + if (!ret) + printf("%x\n", flags); + } + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); + + return 0; +} +#endif + /** * do_i2c_md() - Handle the "i2c md" command-line command * @cmdtp: Command data struct pointer @@ -327,8 +445,13 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - uint addr, alen, length; + uint addr, length; + int alen; int j, nbytes, linebytes; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif /* We use the last specified parameters, unless new ones are * entered. @@ -356,7 +479,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * 2 bytes long. Some day it might be 3 bytes long :-). */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; @@ -368,6 +491,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] length = simple_strtoul(argv[3], NULL, 16); } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); +#endif + /* * Print the lines. * @@ -381,8 +512,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; - if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, linebuf, linebytes); +#else + ret = i2c_read(chip, addr, alen, linebuf, linebytes); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { printf("%04x:", addr); cp = linebuf; @@ -429,9 +565,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] { uchar chip; ulong addr; - uint alen; + int alen; uchar byte; int count; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if ((argc < 4) || (argc > 5)) return CMD_RET_USAGE; @@ -445,10 +585,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif /* * Value to write is always specified. */ @@ -463,8 +610,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] count = 1; while (count-- > 0) { - if (i2c_write(chip, addr++, alen, &byte, 1) != 0) - i2c_report_err(-1, I2C_ERR_WRITE); +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, addr++, &byte, 1); +#else + ret = i2c_write(chip, addr++, alen, &byte, 1); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_WRITE); /* * Wait for the write to complete. The write can take * up to 10mSec (we allow a little more time). @@ -499,11 +651,15 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] { uchar chip; ulong addr; - uint alen; + int alen; int count; uchar byte; ulong crc; ulong err; + int ret = 0; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 4) return CMD_RET_USAGE; @@ -517,10 +673,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); +#endif /* * Count is always specified */ @@ -534,13 +697,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] crc = 0; err = 0; while (count-- > 0) { - if (i2c_read(chip, addr, alen, &byte, 1) != 0) +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, &byte, 1); +#else + ret = i2c_read(chip, addr, alen, &byte, 1); +#endif + if (ret) err++; crc = crc32 (crc, &byte, 1); addr++; } if (err > 0) - i2c_report_err(-1, I2C_ERR_READ); + i2c_report_err(ret, I2C_ERR_READ); else printf ("%08lx\n", crc); @@ -568,10 +736,14 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg { uchar chip; ulong addr; - uint alen; + int alen; ulong data; int size = 1; int nbytes; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc != 3) return CMD_RET_USAGE; @@ -601,19 +773,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif + /* * 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, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, (uchar *)&data, size); +#else + ret = i2c_read(chip, addr, alen, (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { data = cpu_to_be32(data); if (size == 1) @@ -655,8 +840,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg * good enough to not time out */ bootretry_reset_cmd_timeout(); - if (i2c_write(chip, addr, alen, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_WRITE); +#ifdef CONFIG_DM_I2C + ret = i2c_write(dev, addr, (uchar *)&data, + size); +#else + ret = i2c_write(chip, addr, alen, + (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_WRITE); #ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS udelay(CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS * 1000); #endif @@ -697,6 +889,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv int k, skip; unsigned int bus = GET_BUS_NUM; #endif /* NOPROBES */ + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *bus, *dev; + + if (i2c_get_cur_bus(&bus)) + return CMD_RET_FAILURE; +#endif if (argc == 2) addr = simple_strtol(argv[1], 0, 16); @@ -717,7 +916,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv if (skip) continue; #endif - if (i2c_probe(j) == 0) { +#ifdef CONFIG_DM_I2C + ret = i2c_probe(bus, j, 0, &dev); +#else + ret = i2c_probe(j); +#endif + if (ret == 0) { printf(" %02X", j); found++; } @@ -754,11 +958,15 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; - ulong alen; + int alen; uint addr; uint length; u_char bytes[16]; int delay; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 3) return CMD_RET_USAGE; @@ -772,9 +980,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Address is always specified. */ addr = simple_strtoul(argv[2], NULL, 16); - alen = get_alen(argv[2]); + alen = get_alen(argv[2], DEFAULT_ADDR_LEN); if (alen > 3) return CMD_RET_USAGE; +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret && alen != -1) + ret = i2c_set_chip_offset_len(dev, alen); + if (ret) + return i2c_report_err(ret, I2C_ERR_WRITE); +#endif /* * Length is the number of objects, not number of bytes. @@ -794,8 +1009,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] * Run the loop... */ while (1) { - if (i2c_read(chip, addr, alen, bytes, length) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, bytes, length); +#else + ret = i2c_read(chip, addr, alen, bytes, length); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); udelay(delay); } @@ -1345,6 +1565,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { u_char chip; struct edid1_info edid; + int ret; +#ifdef CONFIG_DM_I2C + struct udevice *dev; +#endif if (argc < 2) { cmd_usage(cmdtp); @@ -1352,10 +1576,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) } chip = simple_strtoul(argv[1], NULL, 16); - if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { - i2c_report_err(-1, I2C_ERR_READ); - return 1; - } +#ifdef CONFIG_DM_I2C + ret = i2c_get_cur_bus_chip(chip, &dev); + if (!ret) + ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid)); +#else + ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)); +#endif + if (ret) + return i2c_report_err(ret, I2C_ERR_READ); if (edid_check_info(&edid)) { puts("Content isn't valid EDID.\n"); @@ -1437,17 +1666,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc, * 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) +#if defined(CONFIG_SYS_I2C) || defined(CONFIG_I2C_MULTI_BUS) || \ + defined(CONFIG_DM_I2C) static int do_i2c_bus_num(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; - unsigned int bus_no; + int bus_no; - if (argc == 1) + if (argc == 1) { /* querying current setting */ - printf("Current bus is %d\n", i2c_get_bus_num()); - else { +#ifdef CONFIG_DM_I2C + struct udevice *bus; + + if (!i2c_get_cur_bus(&bus)) + bus_no = bus->seq; + else + bus_no = -1; +#else + bus_no = i2c_get_bus_num(); +#endif + printf("Current bus is %d\n", bus_no); + } else { bus_no = simple_strtoul(argv[1], NULL, 10); #if defined(CONFIG_SYS_I2C) if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES) { @@ -1478,13 +1718,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const { int speed, ret=0; - if (argc == 1) +#ifdef CONFIG_DM_I2C + struct udevice *bus; + + if (i2c_get_cur_bus(&bus)) + return 1; +#endif + if (argc == 1) { +#ifdef CONFIG_DM_I2C + speed = i2c_get_bus_speed(bus); +#else + speed = i2c_get_bus_speed(); +#endif /* querying current speed */ - printf("Current bus speed=%d\n", i2c_get_bus_speed()); - else { + printf("Current bus speed=%d\n", speed); + } else { speed = simple_strtoul(argv[1], NULL, 10); printf("Setting bus speed to %d Hz\n", speed); +#ifdef CONFIG_DM_I2C + ret = i2c_set_bus_speed(bus, speed); +#else ret = i2c_set_bus_speed(speed); +#endif if (ret) printf("Failure changing bus speed (%d)\n", ret); } @@ -1532,7 +1787,16 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) */ static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { -#if defined(CONFIG_SYS_I2C) +#if defined(CONFIG_DM_I2C) + struct udevice *bus; + + if (i2c_get_cur_bus(&bus)) + return CMD_RET_FAILURE; + if (i2c_deblock(bus)) { + printf("Error: Not supported by the driver\n"); + return CMD_RET_FAILURE; + } +#elif defined(CONFIG_SYS_I2C) i2c_init(I2C_ADAP->speed, I2C_ADAP->slaveaddr); #else i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -1546,7 +1810,7 @@ static cmd_tbl_t cmd_i2c_sub[] = { #endif U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""), #if defined(CONFIG_SYS_I2C) || \ - defined(CONFIG_I2C_MULTI_BUS) + defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""), #endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID) @@ -1560,6 +1824,9 @@ static cmd_tbl_t cmd_i2c_sub[] = { 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, "", ""), +#ifdef CONFIG_DM_I2C + U_BOOT_CMD_MKENT(flags, 2, 1, do_i2c_flags, "", ""), +#endif U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""), #if defined(CONFIG_CMD_SDRAM) U_BOOT_CMD_MKENT(sdram, 1, 1, do_sdram, "", ""), @@ -1610,7 +1877,7 @@ static char i2c_help_text[] = #endif "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n" #if defined(CONFIG_SYS_I2C) || \ - defined(CONFIG_I2C_MULTI_BUS) + defined(CONFIG_I2C_MULTI_BUS) || defined(CONFIG_DM_I2C) "i2c dev [dev] - show or set current I2C bus\n" #endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID) @@ -1622,8 +1889,11 @@ static char i2c_help_text[] = "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 [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 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" +#ifdef CONFIG_DM_I2C + "i2c flags chip [flags] - set or get chip flags\n" +#endif "i2c reset - re-init the I2C Controller\n" #if defined(CONFIG_CMD_SDRAM) "i2c sdram chip - print SDRAM configuration information\n" From c70c71d8334216e272c33c35aff39e42d7c5185e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:49 -0700 Subject: [PATCH 08/19] dm: i2c: Add I2C emulation driver for sandbox In order to test I2C we need some sort of emulation interface. Add hooks to allow a driver to emulate an I2C device for sandbox. Signed-off-by: Simon Glass Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada --- drivers/i2c/Makefile | 1 + drivers/i2c/i2c-emul-uclass.c | 14 ++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 16 insertions(+) create mode 100644 drivers/i2c/i2c-emul-uclass.c diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 063e097603..5a93473edc 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o +obj-$(CONFIG_SYS_I2C_SANDBOX) += i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c new file mode 100644 index 0000000000..aa89f95953 --- /dev/null +++ b/drivers/i2c/i2c-emul-uclass.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +UCLASS_DRIVER(i2c_emul) = { + .id = UCLASS_I2C_EMUL, + .name = "i2c_emul", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 01866c3a9c..16e4224c16 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -19,6 +19,7 @@ enum uclass_id { UCLASS_TEST_FDT, UCLASS_TEST_BUS, UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ + UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_SIMPLE_BUS, /* U-Boot uclasses start here */ From d19de0d314010ac8566ac363ce85f2d3707d5c72 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:50 -0700 Subject: [PATCH 09/19] dm: i2c: Add a sandbox I2C driver This driver includes some test features such as only supporting certain bus speeds. It passes its I2C traffic through to an emulator. Acked-by: Heiko Schocher Signed-off-by: Simon Glass Reviewed-by: Masahiro Yamada --- drivers/i2c/Makefile | 2 +- drivers/i2c/sandbox_i2c.c | 111 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/sandbox_i2c.c diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5a93473edc..6f3c86c038 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o -obj-$(CONFIG_SYS_I2C_SANDBOX) += i2c-emul-uclass.o +obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c new file mode 100644 index 0000000000..f0e9f51a1f --- /dev/null +++ b/drivers/i2c/sandbox_i2c.c @@ -0,0 +1,111 @@ +/* + * Simulate an I2C port + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct dm_sandbox_i2c_emul_priv { + struct udevice *emul; +}; + +static int get_emul(struct udevice *dev, struct udevice **devp, + struct dm_i2c_ops **opsp) +{ + struct dm_i2c_chip *priv; + int ret; + + *devp = NULL; + *opsp = NULL; + priv = dev_get_parentdata(dev); + if (!priv->emul) { + ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, + false); + if (ret) + return ret; + + ret = device_get_child(dev, 0, &priv->emul); + if (ret) + return ret; + } + *devp = priv->emul; + *opsp = i2c_get_ops(priv->emul); + + return 0; +} + +static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, + int nmsgs) +{ + struct dm_i2c_bus *i2c = bus->uclass_priv; + struct dm_i2c_ops *ops; + struct udevice *emul, *dev; + bool is_read; + int ret; + + /* Special test code to return success but with no emulation */ + if (msg->addr == SANDBOX_I2C_TEST_ADDR) + return 0; + + ret = i2c_get_chip(bus, msg->addr, &dev); + if (ret) + return ret; + + ret = get_emul(dev, &emul, &ops); + if (ret) + return ret; + + /* + * For testing, don't allow writing above 100KHz for writes and + * 400KHz for reads + */ + is_read = nmsgs > 1; + if (i2c->speed_hz > (is_read ? 400000 : 100000)) + return -EINVAL; + return ops->xfer(emul, msg, nmsgs); +} + +static const struct dm_i2c_ops sandbox_i2c_ops = { + .xfer = sandbox_i2c_xfer, +}; + +static int sandbox_i2c_child_pre_probe(struct udevice *dev) +{ + struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev); + + /* Ignore our test address */ + if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR) + return 0; + if (dev->of_offset == -1) + return 0; + + return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, + i2c_chip); +} + +static const struct udevice_id sandbox_i2c_ids[] = { + { .compatible = "sandbox,i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_sandbox) = { + .name = "i2c_sandbox", + .id = UCLASS_I2C, + .of_match = sandbox_i2c_ids, + .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), + .child_pre_probe = sandbox_i2c_child_pre_probe, + .ops = &sandbox_i2c_ops, +}; From 6ec1b7535873dee4c73895e430494e12be4e3e4d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:51 -0700 Subject: [PATCH 10/19] dm: i2c: Add an I2C EEPROM simulator To enable testing of I2C, add a simple I2C EEPROM simulator for sandbox. It supports reading and writing from a small data store. Signed-off-by: Simon Glass Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada --- arch/sandbox/include/asm/test.h | 26 +++++ drivers/misc/Makefile | 3 + drivers/misc/i2c_eeprom_emul.c | 168 ++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 arch/sandbox/include/asm/test.h create mode 100644 drivers/misc/i2c_eeprom_emul.c diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h new file mode 100644 index 0000000000..25a0c85971 --- /dev/null +++ b/arch/sandbox/include/asm/test.h @@ -0,0 +1,26 @@ +/* + * Test-related constants for sandbox + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_TEST_H +#define __ASM_TEST_H + +/* The sandbox driver always permits an I2C device with this address */ +#define SANDBOX_I2C_TEST_ADDR 0x59 + +enum sandbox_i2c_eeprom_test_mode { + SIE_TEST_MODE_NONE, + /* Permits read/write of only one byte per I2C transaction */ + SIE_TEST_MODE_SINGLE_BYTE, +}; + +void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, + enum sandbox_i2c_eeprom_test_mode mode); + +void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); + +#endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 2f2e48f979..ff0218489a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,6 +20,9 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o +ifdef CONFIG_DM_I2C +obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o +endif obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c new file mode 100644 index 0000000000..7343445d42 --- /dev/null +++ b/drivers/misc/i2c_eeprom_emul.c @@ -0,0 +1,168 @@ +/* + * Simulate an I2C eeprom + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define debug_buffer print_buffer +#else +#define debug_buffer(x, ...) +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct sandbox_i2c_flash_plat_data { + enum sandbox_i2c_eeprom_test_mode test_mode; + const char *filename; + int offset_len; /* Length of an offset in bytes */ + int size; /* Size of data buffer */ +}; + +struct sandbox_i2c_flash { + uint8_t *data; +}; + +void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, + enum sandbox_i2c_eeprom_test_mode mode) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->test_mode = mode; +} + +void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->offset_len = offset_len; +} + +static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, + int nmsgs) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(emul); + uint offset = 0; + + debug("\n%s\n", __func__); + debug_buffer(0, priv->data, 1, 16, 0); + for (; nmsgs > 0; nmsgs--, msg++) { + struct sandbox_i2c_flash_plat_data *plat = + dev_get_platdata(emul); + int len; + u8 *ptr; + + if (!plat->size) + return -ENODEV; + if (msg->addr + msg->len > plat->size) { + debug("%s: Address %x, len %x is outside range 0..%x\n", + __func__, msg->addr, msg->len, plat->size); + return -EINVAL; + } + len = msg->len; + debug(" %s: msg->len=%d", + msg->flags & I2C_M_RD ? "read" : "write", + msg->len); + if (msg->flags & I2C_M_RD) { + if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) + len = 1; + debug(", offset %x, len %x: ", offset, len); + memcpy(msg->buf, priv->data + offset, len); + memset(msg->buf + len, '\xff', msg->len - len); + debug_buffer(0, msg->buf, 1, msg->len, 0); + } else if (len >= plat->offset_len) { + int i; + + ptr = msg->buf; + for (i = 0; i < plat->offset_len; i++, len--) + offset = (offset << 8) | *ptr++; + debug(", set offset %x: ", offset); + debug_buffer(0, msg->buf, 1, msg->len, 0); + if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) + len = min(len, 1); + + /* For testing, map offsets into our limited buffer */ + for (i = 24; i > 0; i -= 8) { + if (offset > (1 << i)) { + offset = (offset >> i) | + (offset & ((1 << i) - 1)); + offset += i; + } + } + memcpy(priv->data + offset, ptr, len); + } + } + debug_buffer(0, priv->data, 1, 16, 0); + + return 0; +} + +struct dm_i2c_ops sandbox_i2c_emul_ops = { + .xfer = sandbox_i2c_eeprom_xfer, +}; + +static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + + plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "sandbox,size", 32); + plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset, + "sandbox,filename", NULL); + if (!plat->filename) { + debug("%s: No filename for device '%s'\n", __func__, + dev->name); + return -EINVAL; + } + plat->test_mode = SIE_TEST_MODE_NONE; + plat->offset_len = 1; + + return 0; +} + +static int sandbox_i2c_eeprom_probe(struct udevice *dev) +{ + struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + priv->data = calloc(1, plat->size); + if (!priv->data) + return -ENOMEM; + + return 0; +} + +static int sandbox_i2c_eeprom_remove(struct udevice *dev) +{ + struct sandbox_i2c_flash *priv = dev_get_priv(dev); + + free(priv->data); + + return 0; +} + +static const struct udevice_id sandbox_i2c_ids[] = { + { .compatible = "sandbox,i2c-eeprom" }, + { } +}; + +U_BOOT_DRIVER(sandbox_i2c_emul) = { + .name = "sandbox_i2c_eeprom_emul", + .id = UCLASS_I2C_EMUL, + .of_match = sandbox_i2c_ids, + .ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata, + .probe = sandbox_i2c_eeprom_probe, + .remove = sandbox_i2c_eeprom_remove, + .priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash), + .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data), + .ops = &sandbox_i2c_emul_ops, +}; From ac395f088ff2eb8359900897d858c67f1e2c9ea0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:52 -0700 Subject: [PATCH 11/19] dm: i2c: config: Enable I2C for sandbox using driver model Enable the options to bring up I2C on sandbox. Also enable all the available I2C commands for testing purposes. Signed-off-by: Simon Glass Acked-by: Heiko Schocher --- include/configs/sandbox.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 2b03841d9d..657f751f3c 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -112,6 +112,12 @@ #define CONFIG_SPI_FLASH_STMICRO #define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_DM_I2C +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C_SANDBOX +#define CONFIG_I2C_EDID +#define CONFIG_I2C_EEPROM + /* Memory things - we don't really want a memory test */ #define CONFIG_SYS_LOAD_ADDR 0x00000000 #define CONFIG_SYS_MEMTEST_START 0x00100000 From 776f96f513869a784c3c0bd5a972f408c10e067a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:53 -0700 Subject: [PATCH 12/19] dm: i2c: dts: Add an I2C bus for sandbox Add an I2C bus to the device tree, with an EEPROM emulator attached to one of the addresses. Signed-off-by: Simon Glass Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada --- arch/sandbox/dts/sandbox.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 76147154c2..11748aec79 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -134,6 +134,23 @@ num-gpios = <20>; }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <400000>; + eeprom@2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <128>; + }; + }; + }; + spi@0 { #address-cells = <1>; #size-cells = <0>; From 20142019a96a72bf1516be93a86fc10d028fd136 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:54 -0700 Subject: [PATCH 13/19] dm: Add a simple EEPROM driver There seem to be a few EEPROM drivers around - perhaps we should have a single standard one? This simple driver is used for sandbox testing, but could be pressed into more active service. Signed-off-by: Simon Glass Acked-by: Heiko Schocher Reviewed-by: Masahiro Yamada --- drivers/misc/Makefile | 1 + drivers/misc/i2c_eeprom.c | 51 +++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/i2c_eeprom.h | 19 +++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 drivers/misc/i2c_eeprom.c create mode 100644 include/i2c_eeprom.h diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ff0218489a..6fa836f206 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_GPIO_LED) += gpio_led.o +obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c new file mode 100644 index 0000000000..d0548ecc4e --- /dev/null +++ b/drivers/misc/i2c_eeprom.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, + int size) +{ + return -ENODEV; +} + +static int i2c_eeprom_write(struct udevice *dev, int offset, + const uint8_t *buf, int size) +{ + return -ENODEV; +} + +struct i2c_eeprom_ops i2c_eeprom_std_ops = { + .read = i2c_eeprom_read, + .write = i2c_eeprom_write, +}; + +int i2c_eeprom_std_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id i2c_eeprom_std_ids[] = { + { .compatible = "i2c-eeprom" }, + { } +}; + +U_BOOT_DRIVER(i2c_eeprom_std) = { + .name = "i2c_eeprom", + .id = UCLASS_I2C_EEPROM, + .of_match = i2c_eeprom_std_ids, + .probe = i2c_eeprom_std_probe, + .priv_auto_alloc_size = sizeof(struct i2c_eeprom), + .ops = &i2c_eeprom_std_ops, +}; + +UCLASS_DRIVER(i2c_eeprom) = { + .id = UCLASS_I2C_EEPROM, + .name = "i2c_eeprom", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 16e4224c16..f17c3c2b38 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -32,6 +32,7 @@ enum uclass_id { UCLASS_THERMAL, /* Thermal sensor */ UCLASS_I2C, /* I2C bus */ UCLASS_I2C_GENERIC, /* Generic I2C device */ + UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_COUNT, UCLASS_INVALID = -1, diff --git a/include/i2c_eeprom.h b/include/i2c_eeprom.h new file mode 100644 index 0000000000..ea6c962a39 --- /dev/null +++ b/include/i2c_eeprom.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __I2C_EEPROM +#define __I2C_EEPROM + +struct i2c_eeprom_ops { + int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size); + int (*write)(struct udevice *dev, int offset, const uint8_t *buf, + int size); +}; + +struct i2c_eeprom { +}; + +#endif From ecc2ed55ee09814d16e81a9d1030a95f98eaf940 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:55 -0700 Subject: [PATCH 14/19] dm: i2c: Add tests for I2C Add some basic tests to check that the system works as expected. Signed-off-by: Simon Glass Acked-by: Heiko Schocher --- include/dm/ut.h | 12 +++ test/dm/Makefile | 1 + test/dm/i2c.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 17 ++++ 4 files changed, 246 insertions(+) create mode 100644 test/dm/i2c.c diff --git a/include/dm/ut.h b/include/dm/ut.h index fa9eac0226..ec6146545b 100644 --- a/include/dm/ut.h +++ b/include/dm/ut.h @@ -89,6 +89,18 @@ void ut_failf(struct dm_test_state *dms, const char *fname, int line, } \ } +/* Assert that a pointer is not NULL */ +#define ut_assertnonnull(expr) { \ + const void *val = (expr); \ + \ + if (val == NULL) { \ + ut_failf(dms, __FILE__, __LINE__, __func__, \ + #expr " = NULL", \ + "Expected non-null, got NULL"); \ + return -1; \ + } \ +} + /* Assert that an operation succeeds (returns 0) */ #define ut_assertok(cond) ut_asserteq(0, cond) diff --git a/test/dm/Makefile b/test/dm/Makefile index 75d3d41536..612aa957fa 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -20,4 +20,5 @@ ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_I2C) += i2c.o endif diff --git a/test/dm/i2c.c b/test/dm/i2c.c new file mode 100644 index 0000000000..a53e28dbe5 --- /dev/null +++ b/test/dm/i2c.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Note: Test coverage does not include 10-bit addressing + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int busnum; +static const int chip = 0x2c; + +/* Test that we can find buses and chips */ +static int dm_test_i2c_find(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + const int no_chip = 0x10; + + ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_I2C, busnum, + false, &bus)); + + /* + * i2c_post_bind() will bind devices to chip selects. Check this then + * remove the emulation and the slave device. + */ + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_probe(bus, chip, 0, &dev)); + ut_asserteq(-ENODEV, i2c_probe(bus, no_chip, 0, &dev)); + ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_I2C, 1, &bus)); + + return 0; +} +DM_TEST(dm_test_i2c_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_read_write(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0AB\0", sizeof(buf))); + + return 0; +} +DM_TEST(dm_test_i2c_read_write, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_speed(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_set_bus_speed(bus, 100000)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(i2c_set_bus_speed(bus, 400000)); + ut_asserteq(400000, i2c_get_bus_speed(bus)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_asserteq(-EINVAL, i2c_write(dev, 0, buf, 5)); + + return 0; +} +DM_TEST(dm_test_i2c_speed, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_offset_len(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_set_chip_offset_len(dev, 1)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + + /* This is not supported by the uclass */ + ut_asserteq(-EINVAL, i2c_set_chip_offset_len(dev, 5)); + + return 0; +} +DM_TEST(dm_test_i2c_offset_len, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_probe_empty(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev)); + + return 0; +} +DM_TEST(dm_test_i2c_probe_empty, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_bytewise(struct dm_test_state *dms) +{ + struct udevice *bus, *dev; + struct udevice *eeprom; + uint8_t buf[5]; + + ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + ut_assertok(i2c_get_chip(bus, chip, &dev)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + + /* Tell the EEPROM to only read/write one register at a time */ + ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom)); + ut_assertnonnull(eeprom); + sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_SINGLE_BYTE); + + /* Now we only get the first byte - the rest will be 0xff */ + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + /* If we do a separate transaction for each byte, it works */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf))); + + /* This will only write A */ + ut_assertok(i2c_set_chip_flags(dev, 0)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + /* Check that the B was ignored */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0A\0\0\0", sizeof(buf))); + + /* Now write it again with the new flags, it should work */ + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf))); + + ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS | + DM_I2C_CHIP_RD_ADDRESS)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "\0\0AB\0\0", sizeof(buf))); + + /* Restore defaults */ + sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_NONE); + ut_assertok(i2c_set_chip_flags(dev, 0)); + + return 0; +} +DM_TEST(dm_test_i2c_bytewise, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static int dm_test_i2c_offset(struct dm_test_state *dms) +{ + struct udevice *eeprom; + struct udevice *dev; + uint8_t buf[5]; + + ut_assertok(i2c_get_chip_for_busnum(busnum, chip, &dev)); + + /* Do a transfer so we can find the emulator */ + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom)); + + /* Offset length 0 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 0); + ut_assertok(i2c_set_chip_offset_len(dev, 0)); + ut_assertok(i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf))); + + /* Offset length 1 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 1); + ut_assertok(i2c_set_chip_offset_len(dev, 1)); + ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0, buf, 5)); + ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf))); + + /* Offset length 2 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x210, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x210, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Offset length 3 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x410, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x410, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Offset length 4 */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 2); + ut_assertok(i2c_set_chip_offset_len(dev, 2)); + ut_assertok(i2c_write(dev, 0x420, (uint8_t *)"AB", 2)); + ut_assertok(i2c_read(dev, 0x420, buf, 5)); + ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); + + /* Restore defaults */ + sandbox_i2c_eeprom_set_offset_len(eeprom, 1); + + return 0; +} +DM_TEST(dm_test_i2c_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index 1fba792564..fb0272a59c 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -93,6 +93,23 @@ num-gpios = <10>; }; + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <100000>; + eeprom@2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <256>; + }; + }; + }; + spi@0 { #address-cells = <1>; #size-cells = <0>; From 964d153c0e2caa620ffcbe096f3ff85fdb1158e5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:56 -0700 Subject: [PATCH 15/19] dm: device: Add newline to debug() messages Some of these are missing a newline. Add it. Signed-off-by: Simon Glass --- drivers/core/device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/core/device.c b/drivers/core/device.c index 6793e1c4f9..963b16f26f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -234,7 +234,7 @@ int device_probe(struct udevice *dev) void *dev_get_platdata(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } @@ -244,7 +244,7 @@ void *dev_get_platdata(struct udevice *dev) void *dev_get_priv(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } @@ -254,7 +254,7 @@ void *dev_get_priv(struct udevice *dev) void *dev_get_parentdata(struct udevice *dev) { if (!dev) { - dm_warn("%s: null device", __func__); + dm_warn("%s: null device\n", __func__); return NULL; } From 6ee350bb93e4672575a333725690a7935f3c3b47 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Dec 2014 06:36:28 -0700 Subject: [PATCH 16/19] dts: Bring in Chrome OS keyboard device tree definition This will be used by nyan-big, but bring it in in a separate patch since it will be common to other boards. Signed-off-by: Simon Glass --- arch/arm/dts/cros-ec-keyboard.dtsi | 105 +++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 arch/arm/dts/cros-ec-keyboard.dtsi diff --git a/arch/arm/dts/cros-ec-keyboard.dtsi b/arch/arm/dts/cros-ec-keyboard.dtsi new file mode 100644 index 0000000000..9c7fb0acae --- /dev/null +++ b/arch/arm/dts/cros-ec-keyboard.dtsi @@ -0,0 +1,105 @@ +/* + * Keyboard dts fragment for devices that use cros-ec-keyboard + * + * Copyright (c) 2014 Google, Inc + * + * 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. +*/ + +#include + +&cros_ec { + keyboard-controller { + compatible = "google,cros-ec-keyb"; + keypad,num-rows = <8>; + keypad,num-columns = <13>; + google,needs-ghost-filter; + + linux,keymap = < + MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) + MATRIX_KEY(0x00, 0x02, KEY_F1) + MATRIX_KEY(0x00, 0x03, KEY_B) + MATRIX_KEY(0x00, 0x04, KEY_F10) + MATRIX_KEY(0x00, 0x06, KEY_N) + MATRIX_KEY(0x00, 0x08, KEY_EQUAL) + MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT) + + MATRIX_KEY(0x01, 0x01, KEY_ESC) + MATRIX_KEY(0x01, 0x02, KEY_F4) + MATRIX_KEY(0x01, 0x03, KEY_G) + MATRIX_KEY(0x01, 0x04, KEY_F7) + MATRIX_KEY(0x01, 0x06, KEY_H) + MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE) + MATRIX_KEY(0x01, 0x09, KEY_F9) + MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE) + + MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL) + MATRIX_KEY(0x02, 0x01, KEY_TAB) + MATRIX_KEY(0x02, 0x02, KEY_F3) + MATRIX_KEY(0x02, 0x03, KEY_T) + MATRIX_KEY(0x02, 0x04, KEY_F6) + MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE) + MATRIX_KEY(0x02, 0x06, KEY_Y) + MATRIX_KEY(0x02, 0x07, KEY_102ND) + MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) + MATRIX_KEY(0x02, 0x09, KEY_F8) + + MATRIX_KEY(0x03, 0x01, KEY_GRAVE) + MATRIX_KEY(0x03, 0x02, KEY_F2) + MATRIX_KEY(0x03, 0x03, KEY_5) + MATRIX_KEY(0x03, 0x04, KEY_F5) + MATRIX_KEY(0x03, 0x06, KEY_6) + MATRIX_KEY(0x03, 0x08, KEY_MINUS) + MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH) + + MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL) + MATRIX_KEY(0x04, 0x01, KEY_A) + MATRIX_KEY(0x04, 0x02, KEY_D) + MATRIX_KEY(0x04, 0x03, KEY_F) + MATRIX_KEY(0x04, 0x04, KEY_S) + MATRIX_KEY(0x04, 0x05, KEY_K) + MATRIX_KEY(0x04, 0x06, KEY_J) + MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON) + MATRIX_KEY(0x04, 0x09, KEY_L) + MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH) + MATRIX_KEY(0x04, 0x0b, KEY_ENTER) + + MATRIX_KEY(0x05, 0x01, KEY_Z) + MATRIX_KEY(0x05, 0x02, KEY_C) + MATRIX_KEY(0x05, 0x03, KEY_V) + MATRIX_KEY(0x05, 0x04, KEY_X) + MATRIX_KEY(0x05, 0x05, KEY_COMMA) + MATRIX_KEY(0x05, 0x06, KEY_M) + MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT) + MATRIX_KEY(0x05, 0x08, KEY_SLASH) + MATRIX_KEY(0x05, 0x09, KEY_DOT) + MATRIX_KEY(0x05, 0x0b, KEY_SPACE) + + MATRIX_KEY(0x06, 0x01, KEY_1) + MATRIX_KEY(0x06, 0x02, KEY_3) + MATRIX_KEY(0x06, 0x03, KEY_4) + MATRIX_KEY(0x06, 0x04, KEY_2) + MATRIX_KEY(0x06, 0x05, KEY_8) + MATRIX_KEY(0x06, 0x06, KEY_7) + MATRIX_KEY(0x06, 0x08, KEY_0) + MATRIX_KEY(0x06, 0x09, KEY_9) + MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT) + MATRIX_KEY(0x06, 0x0b, KEY_DOWN) + MATRIX_KEY(0x06, 0x0c, KEY_RIGHT) + + MATRIX_KEY(0x07, 0x01, KEY_Q) + MATRIX_KEY(0x07, 0x02, KEY_E) + MATRIX_KEY(0x07, 0x03, KEY_R) + MATRIX_KEY(0x07, 0x04, KEY_W) + MATRIX_KEY(0x07, 0x05, KEY_I) + MATRIX_KEY(0x07, 0x06, KEY_U) + MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT) + MATRIX_KEY(0x07, 0x08, KEY_P) + MATRIX_KEY(0x07, 0x09, KEY_O) + MATRIX_KEY(0x07, 0x0b, KEY_UP) + MATRIX_KEY(0x07, 0x0c, KEY_LEFT) + >; + }; +}; From 754204b5c2bbb810c4f332227227af086f935686 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 4 Dec 2014 06:36:29 -0700 Subject: [PATCH 17/19] tegra: dts: Sync tegra124.dtsi with linux kernel Sync this up with Linux v3.18-rc5. Exclude features that are unlikely to supported in U-Boot soon (regulators, pinmux). Also the addresses are updated to 32-bit. Otherwise it is the same. Also bring in the dt-bindings for pinctrl. Signed-off-by: Simon Glass Acked-by: Stephen Warren --- arch/arm/dts/tegra124.dtsi | 114 ++++++++++++++++++++ include/dt-bindings/pinctrl/pinctrl-tegra.h | 45 ++++++++ 2 files changed, 159 insertions(+) create mode 100644 include/dt-bindings/pinctrl/pinctrl-tegra.h diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi index 3288f28dae..6b5c2bea63 100644 --- a/arch/arm/dts/tegra124.dtsi +++ b/arch/arm/dts/tegra124.dtsi @@ -1,5 +1,6 @@ #include #include +#include #include #include "skeleton.dtsi" @@ -192,6 +193,16 @@ status = "disabled"; }; + pwm: pwm@7000a000 { + compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + clocks = <&tegra_car TEGRA124_CLK_PWM>; + resets = <&tegra_car 17>; + reset-names = "pwm"; + status = "disabled"; + }; + spi@7000d400 { compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi"; reg = <0x7000d400 0x200>; @@ -290,6 +301,109 @@ status = "disabled"; }; + ahub@70300000 { + compatible = "nvidia,tegra124-ahub"; + reg = <0x70300000 0x200>, + <0x70300800 0x800>, + <0x70300200 0x600>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_D_AUDIO>, + <&tegra_car TEGRA124_CLK_APBIF>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, /* d_audio */ + <&tegra_car 107>, /* apbif */ + <&tegra_car 30>, /* i2s0 */ + <&tegra_car 11>, /* i2s1 */ + <&tegra_car 18>, /* i2s2 */ + <&tegra_car 101>, /* i2s3 */ + <&tegra_car 102>, /* i2s4 */ + <&tegra_car 108>, /* dam0 */ + <&tegra_car 109>, /* dam1 */ + <&tegra_car 110>, /* dam2 */ + <&tegra_car 10>, /* spdif */ + <&tegra_car 153>, /* amx */ + <&tegra_car 185>, /* amx1 */ + <&tegra_car 154>, /* adx */ + <&tegra_car 180>, /* adx1 */ + <&tegra_car 186>, /* afc0 */ + <&tegra_car 187>, /* afc1 */ + <&tegra_car 188>, /* afc2 */ + <&tegra_car 189>, /* afc3 */ + <&tegra_car 190>, /* afc4 */ + <&tegra_car 191>; /* afc5 */ + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif", "amx", "amx1", "adx", "adx1", + "afc0", "afc1", "afc2", "afc3", "afc4", "afc5"; + dmas = <&apbdma 1>, <&apbdma 1>, + <&apbdma 2>, <&apbdma 2>, + <&apbdma 3>, <&apbdma 3>, + <&apbdma 4>, <&apbdma 4>, + <&apbdma 6>, <&apbdma 6>, + <&apbdma 7>, <&apbdma 7>, + <&apbdma 12>, <&apbdma 12>, + <&apbdma 13>, <&apbdma 13>, + <&apbdma 14>, <&apbdma 14>, + <&apbdma 29>, <&apbdma 29>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", + "rx3", "tx3", "rx4", "tx4", "rx5", "tx5", + "rx6", "tx6", "rx7", "tx7", "rx8", "tx8", + "rx9", "tx9"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + + tegra_i2s0: i2s@70301000 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301000 0x100>; + nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car TEGRA124_CLK_I2S0>; + resets = <&tegra_car 30>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s1: i2s@70301100 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301100 0x100>; + nvidia,ahub-cif-ids = <5 5>; + clocks = <&tegra_car TEGRA124_CLK_I2S1>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s2: i2s@70301200 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301200 0x100>; + nvidia,ahub-cif-ids = <6 6>; + clocks = <&tegra_car TEGRA124_CLK_I2S2>; + resets = <&tegra_car 18>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s3: i2s@70301300 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301300 0x100>; + nvidia,ahub-cif-ids = <7 7>; + clocks = <&tegra_car TEGRA124_CLK_I2S3>; + resets = <&tegra_car 101>; + reset-names = "i2s"; + status = "disabled"; + }; + + tegra_i2s4: i2s@70301400 { + compatible = "nvidia,tegra124-i2s"; + reg = <0x70301400 0x100>; + nvidia,ahub-cif-ids = <8 8>; + clocks = <&tegra_car TEGRA124_CLK_I2S4>; + resets = <&tegra_car 102>; + reset-names = "i2s"; + status = "disabled"; + }; + }; + usb@7d000000 { compatible = "nvidia,tegra124-ehci", "nvidia,tegra30-ehci"; reg = <0x7d000000 0x4000>; diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra.h b/include/dt-bindings/pinctrl/pinctrl-tegra.h new file mode 100644 index 0000000000..ebafa498be --- /dev/null +++ b/include/dt-bindings/pinctrl/pinctrl-tegra.h @@ -0,0 +1,45 @@ +/* + * This header provides constants for Tegra pinctrl bindings. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * + * Author: Laxman Dewangan + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#ifndef _DT_BINDINGS_PINCTRL_TEGRA_H +#define _DT_BINDINGS_PINCTRL_TEGRA_H + +/* + * Enable/disable for diffeent dt properties. This is applicable for + * properties nvidia,enable-input, nvidia,tristate, nvidia,open-drain, + * nvidia,lock, nvidia,rcv-sel, nvidia,high-speed-mode, nvidia,schmitt. + */ +#define TEGRA_PIN_DISABLE 0 +#define TEGRA_PIN_ENABLE 1 + +#define TEGRA_PIN_PULL_NONE 0 +#define TEGRA_PIN_PULL_DOWN 1 +#define TEGRA_PIN_PULL_UP 2 + +/* Low power mode driver */ +#define TEGRA_PIN_LP_DRIVE_DIV_8 0 +#define TEGRA_PIN_LP_DRIVE_DIV_4 1 +#define TEGRA_PIN_LP_DRIVE_DIV_2 2 +#define TEGRA_PIN_LP_DRIVE_DIV_1 3 + +/* Rising/Falling slew rate */ +#define TEGRA_PIN_SLEW_RATE_FASTEST 0 +#define TEGRA_PIN_SLEW_RATE_FAST 1 +#define TEGRA_PIN_SLEW_RATE_SLOW 2 +#define TEGRA_PIN_SLEW_RATE_SLOWEST 3 + +#endif From a6c7b461814028870697182d19383ef5b370c257 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Thu, 4 Dec 2014 06:36:30 -0700 Subject: [PATCH 18/19] ARM: tegra: Add support for nyan-big board Nyan-big is a Tegra124 clamshell board that is very similar to venice2, but it has a different panel, the sdcard cd and wp sense are flipped, and it has a different revision of the AS3722 PMIC. This is the Acer Chromebook 13 CB5-311-T7NN (13.3-inch HD, NVIDIA Tegra K1, 2GB). The display is not currently supported, so it should boot on other nyan-based Chromebooks also, but only the device tree for nyan-big is provided here. The device tree file is from Linux but with features removed which are unlikely to be supported in U-Boot soon (regulators, pinmux). Also the addresses are updated to 32-bit. Signed-off-by: Allen Martin Signed-off-by: Simon Glass (rebase, change to 'nyan-big', fix pinmux that resets nyan-big) --- arch/arm/cpu/armv7/tegra124/Kconfig | 10 + arch/arm/dts/Makefile | 1 + arch/arm/dts/tegra124-nyan-big.dts | 365 ++++++++++++++++++ board/nvidia/nyan-big/Kconfig | 24 ++ board/nvidia/nyan-big/MAINTAINERS | 6 + board/nvidia/nyan-big/Makefile | 9 + board/nvidia/nyan-big/nyan-big.c | 27 ++ .../nvidia/nyan-big/pinmux-config-nyan-big.h | 287 ++++++++++++++ board/nvidia/venice2/as3722_init.h | 2 +- configs/nyan-big_defconfig | 5 + include/configs/nyan-big.h | 79 ++++ 11 files changed, 814 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/tegra124-nyan-big.dts create mode 100644 board/nvidia/nyan-big/Kconfig create mode 100644 board/nvidia/nyan-big/MAINTAINERS create mode 100644 board/nvidia/nyan-big/Makefile create mode 100644 board/nvidia/nyan-big/nyan-big.c create mode 100644 board/nvidia/nyan-big/pinmux-config-nyan-big.h create mode 100644 configs/nyan-big_defconfig create mode 100644 include/configs/nyan-big.h diff --git a/arch/arm/cpu/armv7/tegra124/Kconfig b/arch/arm/cpu/armv7/tegra124/Kconfig index 6a1c83a27b..88f627c932 100644 --- a/arch/arm/cpu/armv7/tegra124/Kconfig +++ b/arch/arm/cpu/armv7/tegra124/Kconfig @@ -6,6 +6,15 @@ choice config TARGET_JETSON_TK1 bool "NVIDIA Tegra124 Jetson TK1 board" +config TARGET_NYAN_BIG + bool "Google/NVIDIA Nyan-big Chrombook" + help + Nyan Big is a Tegra124 clamshell board that is very similar + to venice2, but it has a different panel, the sdcard CD and WP + sense are flipped, and it has a different revision of the AS3722 + PMIC. The retail name is the Acer Chromebook 13 CB5-311-T7NN + (13.3-inch HD, NVIDIA Tegra K1, 2GB). + config TARGET_VENICE2 bool "NVIDIA Tegra124 Venice2" @@ -15,6 +24,7 @@ config SYS_SOC default "tegra124" source "board/nvidia/jetson-tk1/Kconfig" +source "board/nvidia/nyan-big/Kconfig" source "board/nvidia/venice2/Kconfig" endif diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 187d58c498..e6a495cb0d 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -31,6 +31,7 @@ dtb-$(CONFIG_TEGRA) += tegra20-harmony.dtb \ tegra30-tec-ng.dtb \ tegra114-dalmore.dtb \ tegra124-jetson-tk1.dtb \ + tegra124-nyan-big.dtb \ tegra124-venice2.dtb dtb-$(CONFIG_ARCH_UNIPHIER) += \ uniphier-ph1-sld3-ref.dtb \ diff --git a/arch/arm/dts/tegra124-nyan-big.dts b/arch/arm/dts/tegra124-nyan-big.dts new file mode 100644 index 0000000000..c1f35a07bd --- /dev/null +++ b/arch/arm/dts/tegra124-nyan-big.dts @@ -0,0 +1,365 @@ +/dts-v1/; + +#include +#include "tegra124.dtsi" + +/ { + model = "Acer Chromebook 13 CB5-311"; + compatible = "google,nyan-big", "nvidia,tegra124"; + + aliases { + console = &uarta; + i2c0 = "/i2c@7000d000"; + i2c1 = "/i2c@7000c000"; + i2c2 = "/i2c@7000c400"; + i2c3 = "/i2c@7000c500"; + i2c4 = "/i2c@7000c700"; + i2c5 = "/i2c@7000d100"; + rtc0 = "/i2c@0,7000d000/pmic@40"; + rtc1 = "/rtc@0,7000e000"; + sdhci0 = "/sdhci@700b0600"; + sdhci1 = "/sdhci@700b0400"; + spi0 = "/spi@7000d400"; + spi1 = "/spi@7000da00"; + usb0 = "/usb@7d000000"; + usb1 = "/usb@7d008000"; + }; + + memory { + reg = <0x80000000 0x80000000>; + }; + + serial@70006000 { + /* Debug connector on the bottom of the board near SD card. */ + status = "okay"; + }; + + pwm@7000a000 { + status = "okay"; + }; + + i2c@7000c000 { + status = "okay"; + clock-frequency = <100000>; + + acodec: audio-codec@10 { + compatible = "maxim,max98090"; + reg = <0x10>; + interrupt-parent = <&gpio>; + interrupts = ; + }; + + temperature-sensor@4c { + compatible = "ti,tmp451"; + reg = <0x4c>; + interrupt-parent = <&gpio>; + interrupts = ; + + #thermal-sensor-cells = <1>; + }; + }; + + i2c@7000c400 { + status = "okay"; + clock-frequency = <100000>; + }; + + i2c@7000c500 { + status = "okay"; + clock-frequency = <400000>; + + tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + }; + }; + + hdmi_ddc: i2c@7000c700 { + status = "okay"; + clock-frequency = <100000>; + }; + + i2c@7000d000 { + status = "okay"; + clock-frequency = <400000>; + + pmic: pmic@40 { + compatible = "ams,as3722"; + reg = <0x40>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + + ams,system-power-controller; + + #interrupt-cells = <2>; + interrupt-controller; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&as3722_default>; + + as3722_default: pinmux { + gpio0 { + pins = "gpio0"; + function = "gpio"; + bias-pull-down; + }; + + gpio1 { + pins = "gpio1"; + function = "gpio"; + bias-pull-up; + }; + + gpio2_4_7 { + pins = "gpio2", "gpio4", "gpio7"; + function = "gpio"; + bias-pull-up; + }; + + gpio3_6 { + pins = "gpio3", "gpio6"; + bias-high-impedance; + }; + + gpio5 { + pins = "gpio5"; + function = "clk32k-out"; + bias-pull-down; + }; + }; + }; + }; + + spi@7000d400 { + status = "okay"; + + cros_ec: cros-ec@0 { + compatible = "google,cros-ec-spi"; + spi-max-frequency = <3000000>; + interrupt-parent = <&gpio>; + interrupts = ; + reg = <0>; + + google,cros-ec-spi-msg-delay = <2000>; + + i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + #address-cells = <1>; + #size-cells = <0>; + + google,remote-bus = <0>; + + charger: bq24735@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + interrupt-parent = <&gpio>; + interrupts = ; + ti,ac-detect-gpios = <&gpio + TEGRA_GPIO(J, 0) + GPIO_ACTIVE_HIGH>; + }; + + battery: sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,i2c-retry-count = <2>; + sbs,poll-retry-count = <10>; + power-supplies = <&charger>; + }; + }; + }; + }; + + spi@7000da00 { + status = "okay"; + spi-max-frequency = <25000000>; + + flash@0 { + compatible = "winbond,w25q32dw"; + reg = <0>; + }; + }; + + pmc@7000e400 { + nvidia,invert-interrupt; + nvidia,suspend-mode = <0>; + nvidia,cpu-pwr-good-time = <500>; + nvidia,cpu-pwr-off-time = <300>; + nvidia,core-pwr-good-time = <641 3845>; + nvidia,core-pwr-off-time = <61036>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + }; + + hda@70030000 { + status = "okay"; + }; + + sdhci@700b0000 { /* WiFi/BT on this bus */ + status = "okay"; + power-gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_HIGH>; + bus-width = <4>; + no-1-8-v; + non-removable; + }; + + sdhci@700b0400 { /* SD Card on this bus */ + status = "okay"; + cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; + power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; + wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>; + bus-width = <4>; + no-1-8-v; + }; + + sdhci@700b0600 { /* eMMC on this bus */ + status = "okay"; + bus-width = <8>; + no-1-8-v; + non-removable; + }; + + ahub@70300000 { + i2s@70301100 { + status = "okay"; + }; + }; + + usb@7d000000 { /* Rear external USB port. */ + status = "okay"; + }; + + usb-phy@7d000000 { + status = "okay"; + }; + + usb@7d004000 { /* Internal webcam. */ + status = "okay"; + }; + + usb-phy@7d004000 { + status = "okay"; + }; + + usb@7d008000 { /* Left external USB port. */ + status = "okay"; + }; + + usb-phy@7d008000 { + status = "okay"; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + + enable-gpios = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_HIGH>; + pwms = <&pwm 1 1000000>; + + default-brightness-level = <224>; + brightness-levels = + < 0 1 2 3 4 5 6 7 + 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 + 24 25 26 27 28 29 30 31 + 32 33 34 35 36 37 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255 + 256>; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + lid { + label = "Lid"; + gpios = <&gpio TEGRA_GPIO(R, 4) GPIO_ACTIVE_LOW>; + linux,input-type = <5>; + linux,code = ; + debounce-interval = <1>; + gpio-key,wakeup; + }; + + power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <30>; + gpio-key,wakeup; + }; + }; + + panel: panel { + compatible = "auo,b133xtn01"; + + backlight = <&backlight>; + }; + + sound { + compatible = "nvidia,tegra-audio-max98090-nyan-big", + "nvidia,tegra-audio-max98090"; + nvidia,model = "Acer Chromebook 13"; + + nvidia,audio-routing = + "Headphones", "HPR", + "Headphones", "HPL", + "Speakers", "SPKR", + "Speakers", "SPKL", + "Mic Jack", "MICBIAS", + "DMICL", "Int Mic", + "DMICR", "Int Mic", + "IN34", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&acodec>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(I, 7) GPIO_ACTIVE_HIGH>; + }; +}; + +#include "cros-ec-keyboard.dtsi" diff --git a/board/nvidia/nyan-big/Kconfig b/board/nvidia/nyan-big/Kconfig new file mode 100644 index 0000000000..6c42bb941a --- /dev/null +++ b/board/nvidia/nyan-big/Kconfig @@ -0,0 +1,24 @@ +if TARGET_NYAN_BIG + +config SYS_CPU + string + default "arm720t" if SPL_BUILD + default "armv7" if !SPL_BUILD + +config SYS_BOARD + string + default "nyan-big" + +config SYS_VENDOR + string + default "nvidia" + +config SYS_SOC + string + default "tegra124" + +config SYS_CONFIG_NAME + string + default "nyan-big" + +endif diff --git a/board/nvidia/nyan-big/MAINTAINERS b/board/nvidia/nyan-big/MAINTAINERS new file mode 100644 index 0000000000..ff74627af2 --- /dev/null +++ b/board/nvidia/nyan-big/MAINTAINERS @@ -0,0 +1,6 @@ +NORRIN BOARD +M: Allen Martin +S: Maintained +F: board/nvidia/nyan-big/ +F: include/configs/nyan-big.h +F: configs/nyan-big_defconfig diff --git a/board/nvidia/nyan-big/Makefile b/board/nvidia/nyan-big/Makefile new file mode 100644 index 0000000000..cd2f61dc9d --- /dev/null +++ b/board/nvidia/nyan-big/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2014 +# NVIDIA Corporation +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += ../venice2/as3722_init.o +obj-y += nyan-big.o diff --git a/board/nvidia/nyan-big/nyan-big.c b/board/nvidia/nyan-big/nyan-big.c new file mode 100644 index 0000000000..d4d2496639 --- /dev/null +++ b/board/nvidia/nyan-big/nyan-big.c @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2014 + * NVIDIA Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include "pinmux-config-nyan-big.h" + +/* + * Routine: pinmux_init + * Description: Do individual peripheral pinmux configs + */ +void pinmux_init(void) +{ + gpio_config_table(nyan_big_gpio_inits, + ARRAY_SIZE(nyan_big_gpio_inits)); + + pinmux_config_pingrp_table(nyan_big_pingrps, + ARRAY_SIZE(nyan_big_pingrps)); + + pinmux_config_drvgrp_table(nyan_big_drvgrps, + ARRAY_SIZE(nyan_big_drvgrps)); +} diff --git a/board/nvidia/nyan-big/pinmux-config-nyan-big.h b/board/nvidia/nyan-big/pinmux-config-nyan-big.h new file mode 100644 index 0000000000..9c5fbaa7aa --- /dev/null +++ b/board/nvidia/nyan-big/pinmux-config-nyan-big.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _PINMUX_CONFIG_NYAN_BIG_H_ +#define _PINMUX_CONFIG_NYAN_BIG_H_ + +#define GPIO_INIT(_gpio, _init) \ + { \ + .gpio = GPIO_P##_gpio, \ + .init = TEGRA_GPIO_INIT_##_init, \ + } + +static const struct tegra_gpio_config nyan_big_gpio_inits[] = { + /* gpio, init_val */ + GPIO_INIT(A0, IN), + GPIO_INIT(C7, IN), + GPIO_INIT(G0, IN), + GPIO_INIT(G1, IN), + GPIO_INIT(G2, IN), + GPIO_INIT(G3, IN), + GPIO_INIT(H2, IN), + GPIO_INIT(H4, IN), + GPIO_INIT(H6, IN), + GPIO_INIT(H7, OUT1), + GPIO_INIT(I0, IN), + GPIO_INIT(I1, IN), + GPIO_INIT(I5, OUT1), + GPIO_INIT(I6, IN), + GPIO_INIT(I7, IN), + GPIO_INIT(J0, IN), + GPIO_INIT(J7, IN), + GPIO_INIT(K1, OUT0), + GPIO_INIT(K2, IN), + GPIO_INIT(K4, OUT0), + GPIO_INIT(K6, OUT0), + GPIO_INIT(K7, IN), + GPIO_INIT(N7, IN), + GPIO_INIT(P2, OUT0), + GPIO_INIT(Q0, IN), + GPIO_INIT(Q2, IN), + GPIO_INIT(Q3, IN), + GPIO_INIT(Q6, IN), + GPIO_INIT(Q7, IN), + GPIO_INIT(R0, OUT0), + GPIO_INIT(R1, IN), + GPIO_INIT(R4, IN), + GPIO_INIT(R7, IN), + GPIO_INIT(S3, OUT0), + GPIO_INIT(S4, OUT0), + GPIO_INIT(S7, IN), + GPIO_INIT(T1, IN), + GPIO_INIT(U4, IN), + GPIO_INIT(U5, IN), + GPIO_INIT(U6, IN), + GPIO_INIT(V0, IN), + GPIO_INIT(W3, IN), + GPIO_INIT(X1, IN), + GPIO_INIT(X4, IN), + GPIO_INIT(X7, OUT0), +}; + +#define PINCFG(_pingrp, _mux, _pull, _tri, _io, _od, _rcv_sel) \ + { \ + .pingrp = PMUX_PINGRP_##_pingrp, \ + .func = PMUX_FUNC_##_mux, \ + .pull = PMUX_PULL_##_pull, \ + .tristate = PMUX_TRI_##_tri, \ + .io = PMUX_PIN_##_io, \ + .od = PMUX_PIN_OD_##_od, \ + .rcv_sel = PMUX_PIN_RCV_SEL_##_rcv_sel, \ + .lock = PMUX_PIN_LOCK_DEFAULT, \ + .ioreset = PMUX_PIN_IO_RESET_DEFAULT, \ + } + +static const struct pmux_pingrp_config nyan_big_pingrps[] = { + /* pingrp, mux, pull, tri, e_input, od, rcv_sel */ + PINCFG(CLK_32K_OUT_PA0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(UART3_CTS_N_PA1, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_FS_PA2, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_SCLK_PA3, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_DIN_PA4, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP2_DOUT_PA5, I2S1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CLK_PA6, SDMMC3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CMD_PA7, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PB0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PB1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT3_PB4, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT2_PB5, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT1_PB6, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_DAT0_PB7, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(UART3_RTS_N_PC0, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_TXD_PC2, IRDA, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_RXD_PC3, IRDA, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GEN1_I2C_SCL_PC4, I2C1, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(GEN1_I2C_SDA_PC5, I2C1, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(PC7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PG4, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG5, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG6, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PG7, SPI4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH0, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH1, PWM1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PH6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PH7, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI2, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI3, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI4, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI5, DEFAULT, UP, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PI6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PI7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PJ0, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PJ2, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_CTS_N_PJ5, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART2_RTS_N_PJ6, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PJ7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PK0, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK1, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PK3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK4, DEFAULT, UP, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SPDIF_OUT_PK5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SPDIF_IN_PK6, DEFAULT, DOWN, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PK7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_FS_PN0, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_DIN_PN1, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_DOUT_PN2, I2S0, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP1_SCLK_PN3, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(USB_VBUS_EN0_PN4, USB, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(USB_VBUS_EN1_PN5, USB, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(HDMI_INT_PN7, DEFAULT, DOWN, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(ULPI_DATA7_PO0, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA0_PO1, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA1_PO2, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA2_PO3, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA3_PO4, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA4_PO5, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA5_PO6, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DATA6_PO7, ULPI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_FS_PP0, I2S2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_DIN_PP1, I2S2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_DOUT_PP2, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP3_SCLK_PP3, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_FS_PP4, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_DIN_PP5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_DOUT_PP6, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP4_SCLK_PP7, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL0_PQ0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL1_PQ1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL2_PQ2, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL3_PQ3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL4_PQ4, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL5_PQ5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL6_PQ6, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_COL7_PQ7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW0_PR0, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW1_PR1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW2_PR2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW3_PR3, KBC, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW4_PR4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW5_PR5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW6_PR6, KBC, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW7_PR7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW8_PS0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW9_PS1, UARTA, DOWN, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW10_PS2, UARTA, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW11_PS3, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW12_PS4, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW13_PS5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW14_PS6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW15_PS7, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW16_PT0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(KB_ROW17_PT1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(GEN2_I2C_SCL_PT5, I2C2, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(GEN2_I2C_SDA_PT6, I2C2, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC4_CMD_PT7, SDMMC4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU0, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU1, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU2, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU3, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PU4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU5, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PU6, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PV0, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PV1, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CD_N_PV2, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_WP_N_PV3, SDMMC1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DDC_SCL_PV4, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(DDC_SDA_PV5, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, NORMAL), + PINCFG(GPIO_W2_AUD_PW2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_W3_AUD_PW3, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DAP_MCLK1_PW4, EXTPERIPH1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK2_OUT_PW5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART3_TXD_PW6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(UART3_RXD_PW7, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DVFS_PWM_PX0, CLDVFS, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X1_AUD_PX1, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DVFS_CLK_PX2, CLDVFS, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X3_AUD_PX3, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X4_AUD_PX4, DEFAULT, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X5_AUD_PX5, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X6_AUD_PX6, GMI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(GPIO_X7_AUD_PX7, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_CLK_PY0, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_DIR_PY1, SPI1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_NXT_PY2, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(ULPI_STP_PY3, SPI1, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT3_PY4, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT2_PY5, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT1_PY6, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_DAT0_PY7, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_CLK_PZ0, SDMMC1, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC1_CMD_PZ1, SDMMC1, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PWR_I2C_SCL_PZ6, I2CPWR, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(PWR_I2C_SDA_PZ7, I2CPWR, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC4_DAT0_PAA0, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT1_PAA1, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT2_PAA2, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT3_PAA3, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT4_PAA4, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT5_PAA5, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT6_PAA6, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_DAT7_PAA7, SDMMC4, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(PBB0, VGP6, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CAM_I2C_SCL_PBB1, RSVD3, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(CAM_I2C_SDA_PBB2, RSVD3, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(PBB3, VGP3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB4, VGP4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB5, RSVD3, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PBB7, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CAM_MCLK_PCC0, VI, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PCC1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PCC2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC4_CLK_PCC4, SDMMC4, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(CLK2_REQ_PCC5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L0_RST_N_PDD1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L0_CLKREQ_N_PDD2, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_WAKE_N_PDD3, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L1_RST_N_PDD5, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PEX_L1_CLKREQ_N_PDD6, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK3_OUT_PEE0, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CLK3_REQ_PEE1, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(DAP_MCLK1_REQ_PEE2, RSVD4, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT), + PINCFG(HDMI_CEC_PEE3, CEC, NORMAL, NORMAL, INPUT, ENABLE, DEFAULT), + PINCFG(SDMMC3_CLK_LB_OUT_PEE4, SDMMC3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(SDMMC3_CLK_LB_IN_PEE5, SDMMC3, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(DP_HPD_PFF0, DP, UP, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(USB_VBUS_EN2_PFF1, RSVD2, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(PFF2, RSVD2, DOWN, TRISTATE, OUTPUT, DISABLE, DEFAULT), + PINCFG(CORE_PWR_REQ, PWRON, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(CPU_PWR_REQ, CPU, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(PWR_INT_N, PMI, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(RESET_OUT_N, RESET_OUT_N, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), + PINCFG(OWR, RSVD2, DOWN, TRISTATE, OUTPUT, DEFAULT, NORMAL), + PINCFG(CLK_32K_IN, CLK, NORMAL, NORMAL, INPUT, DEFAULT, DEFAULT), + PINCFG(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT), +}; + +#define DRVCFG(_drvgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, _hsm) \ + { \ + .drvgrp = PMUX_DRVGRP_##_drvgrp, \ + .slwf = _slwf, \ + .slwr = _slwr, \ + .drvup = _drvup, \ + .drvdn = _drvdn, \ + .lpmd = PMUX_LPMD_##_lpmd, \ + .schmt = PMUX_SCHMT_##_schmt, \ + .hsm = PMUX_HSM_##_hsm, \ + } + +static const struct pmux_drvgrp_config nyan_big_drvgrps[] = { +}; + +#endif /* PINMUX_CONFIG_NYAN_BIG_H */ diff --git a/board/nvidia/venice2/as3722_init.h b/board/nvidia/venice2/as3722_init.h index 06c366e0d0..992b11f643 100644 --- a/board/nvidia/venice2/as3722_init.h +++ b/board/nvidia/venice2/as3722_init.h @@ -18,7 +18,7 @@ #define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC */ #define AS3722_LDCONTROL_REG 0x4E -#ifdef CONFIG_TARGET_JETSON_TK1 +#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_NYAN_BIG) #define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) #else #define AS3722_SD0VOLTAGE_DATA (0x2800 | AS3722_SD0VOLTAGE_REG) diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig new file mode 100644 index 0000000000..ec79b5b5f0 --- /dev/null +++ b/configs/nyan-big_defconfig @@ -0,0 +1,5 @@ ++S:CONFIG_ARM=y ++S:CONFIG_TEGRA=y ++S:CONFIG_TEGRA124=y ++S:CONFIG_TARGET_NYAN_BIG=y +CONFIG_DEFAULT_DEVICE_TREE="tegra124-nyan-big" diff --git a/include/configs/nyan-big.h b/include/configs/nyan-big.h new file mode 100644 index 0000000000..a62bc4e018 --- /dev/null +++ b/include/configs/nyan-big.h @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2014 + * NVIDIA Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +#include "tegra124-common.h" + +/* High-level configuration options */ +#define V_PROMPT "Tegra124 (Nyan-big) # " +#define CONFIG_TEGRA_BOARD_STRING "Google/NVIDIA Nyan-big" + +/* Board-specific serial config */ +#define CONFIG_SERIAL_MULTI +#define CONFIG_TEGRA_ENABLE_UARTA +#define CONFIG_SYS_NS16550_COM1 NV_PA_APB_UARTA_BASE + +#define CONFIG_BOARD_EARLY_INIT_F + +/* I2C */ +#define CONFIG_SYS_I2C_TEGRA +#define CONFIG_SYS_I2C_INIT_BOARD +#define CONFIG_I2C_MULTI_BUS +#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS +#define CONFIG_SYS_I2C_SPEED 100000 +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C + +/* SD/MMC */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_TEGRA_MMC +#define CONFIG_CMD_MMC + +/* Environment in eMMC, at the end of 2nd "boot sector" */ +#define CONFIG_ENV_IS_IN_MMC +#define CONFIG_SYS_MMC_ENV_DEV 0 +#define CONFIG_SYS_MMC_ENV_PART 2 +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) + +/* SPI */ +#define CONFIG_TEGRA114_SPI /* Compatible w/ Tegra114 SPI */ +#define CONFIG_TEGRA114_SPI_CTRLS 6 +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED 24000000 +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH_SIZE (4 << 20) + +/* USB Host support */ +#define CONFIG_USB_EHCI +#define CONFIG_USB_EHCI_TEGRA +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 +#define CONFIG_USB_STORAGE +#define CONFIG_CMD_USB + +/* USB networking support */ +#define CONFIG_USB_HOST_ETHER +#define CONFIG_USB_ETHER_ASIX + +/* General networking support */ +#define CONFIG_CMD_NET +#define CONFIG_CMD_DHCP + +#define CONFIG_FIT +#define CONFIG_OF_LIBFDT + +#include "tegra-common-usb-gadget.h" +#include "tegra-common-post.h" + +#endif /* __CONFIG_H */ From b0e6ef46405353270595ffa35c21f4334c541189 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 10 Dec 2014 08:55:57 -0700 Subject: [PATCH 19/19] dm: i2c: tegra: Convert to driver model This converts all Tegra boards over to use driver model for I2C. The driver is adjusted to use driver model and the following obsolete CONFIGs are removed: - CONFIG_SYS_I2C_INIT_BOARD - CONFIG_I2C_MULTI_BUS - CONFIG_SYS_MAX_I2C_BUS - CONFIG_SYS_I2C_SPEED - CONFIG_SYS_I2C This has been tested on: - trimslice (no I2C) - beaver - Jetson-TK1 It has not been tested on Tegra 114 as I don't have that board. Acked-by: Heiko Schocher Signed-off-by: Simon Glass --- arch/arm/cpu/tegra20-common/pmu.c | 21 +- arch/arm/dts/tegra124-jetson-tk1.dts | 1 - arch/arm/dts/tegra30-tec-ng.dts | 4 + arch/arm/include/asm/arch-tegra/tegra_i2c.h | 2 +- board/avionic-design/common/tamonten-ng.c | 12 +- board/nvidia/cardhu/cardhu.c | 13 +- board/nvidia/common/board.c | 4 - board/nvidia/dalmore/dalmore.c | 21 +- board/nvidia/whistler/whistler.c | 29 +- board/toradex/apalis_t30/apalis_t30.c | 19 +- drivers/i2c/tegra_i2c.c | 366 +++++++------------- drivers/power/tps6586x.c | 27 +- include/configs/apalis_t30.h | 3 - include/configs/beaver.h | 3 - include/configs/cardhu.h | 5 - include/configs/colibri_t30.h | 3 - include/configs/dalmore.h | 5 - include/configs/jetson-tk1.h | 5 - include/configs/nyan-big.h | 5 - include/configs/seaboard.h | 3 - include/configs/tec-ng.h | 5 - include/configs/tegra-common.h | 1 + include/configs/tegra114-common.h | 3 - include/configs/tegra124-common.h | 3 - include/configs/tegra20-common.h | 3 - include/configs/tegra30-common.h | 3 - include/configs/trimslice.h | 3 - include/configs/venice2.h | 5 - include/configs/whistler.h | 3 - include/tps6586x.h | 4 +- 30 files changed, 210 insertions(+), 374 deletions(-) diff --git a/arch/arm/cpu/tegra20-common/pmu.c b/arch/arm/cpu/tegra20-common/pmu.c index c595f70e93..36a76a24d9 100644 --- a/arch/arm/cpu/tegra20-common/pmu.c +++ b/arch/arm/cpu/tegra20-common/pmu.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -23,9 +24,13 @@ #define VDD_TRANSITION_STEP 0x06 /* 150mv */ #define VDD_TRANSITION_RATE 0x06 /* 3.52mv/us */ +#define PMI_I2C_ADDRESS 0x34 /* chip requires this address */ + int pmu_set_nominal(void) { - int core, cpu, bus; + struct udevice *bus, *dev; + int core, cpu; + int ret; /* by default, the table has been filled with T25 settings */ switch (tegra_get_chip_sku()) { @@ -42,12 +47,18 @@ int pmu_set_nominal(void) return -1; } - bus = tegra_i2c_get_dvc_bus_num(); - if (bus == -1) { + ret = tegra_i2c_get_dvc_bus(&bus); + if (ret) { debug("%s: Cannot find DVC I2C bus\n", __func__); - return -1; + return ret; } - tps6586x_init(bus); + ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find DVC I2C chip\n", __func__); + return ret; + } + + tps6586x_init(dev); tps6586x_set_pwm_mode(TPS6586X_PWM_SM1); return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP, VDD_TRANSITION_RATE, VDD_RELATION); diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts index ffad1160cd..f6fe9a050f 100644 --- a/arch/arm/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/dts/tegra124-jetson-tk1.dts @@ -16,7 +16,6 @@ i2c2 = "/i2c@7000c400"; i2c3 = "/i2c@7000c500"; i2c4 = "/i2c@7000c700"; - i2c5 = "/i2c@7000d100"; sdhci0 = "/sdhci@700b0600"; sdhci1 = "/sdhci@700b0400"; spi0 = "/spi@7000d400"; diff --git a/arch/arm/dts/tegra30-tec-ng.dts b/arch/arm/dts/tegra30-tec-ng.dts index 8a69e818ca..e924acc35c 100644 --- a/arch/arm/dts/tegra30-tec-ng.dts +++ b/arch/arm/dts/tegra30-tec-ng.dts @@ -6,6 +6,10 @@ model = "Avionic Design Tamonten™ NG Evaluation Carrier"; compatible = "ad,tec-ng", "nvidia,tegra30"; + aliases { + i2c0 = "/i2c@7000c400"; + }; + /* GEN2 */ i2c@7000c400 { status = "okay"; diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h index 7ca690700c..eeeb247d5d 100644 --- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h +++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h @@ -167,6 +167,6 @@ struct i2c_ctlr { * * @return number of bus, or -1 if there is no DVC active */ -int tegra_i2c_get_dvc_bus_num(void); +int tegra_i2c_get_dvc_bus(struct udevice **busp); #endif /* _TEGRA_I2C_H_ */ diff --git a/board/avionic-design/common/tamonten-ng.c b/board/avionic-design/common/tamonten-ng.c index 5870b95afb..86a0844273 100644 --- a/board/avionic-design/common/tamonten-ng.c +++ b/board/avionic-design/common/tamonten-ng.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -51,8 +52,15 @@ void gpio_early_init(void) void pmu_write(uchar reg, uchar data) { - i2c_set_bus_num(4); /* PMU is on bus 4 */ - i2c_write(PMU_I2C_ADDRESS, reg, 1, &data, 1); + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } + i2c_write(dev, reg, &data, 1); } /* diff --git a/board/nvidia/cardhu/cardhu.c b/board/nvidia/cardhu/cardhu.c index cc0e5e130f..026f45c6c6 100644 --- a/board/nvidia/cardhu/cardhu.c +++ b/board/nvidia/cardhu/cardhu.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include "pinmux-config-cardhu.h" @@ -37,17 +38,23 @@ void pinmux_init(void) */ void board_sdmmc_voltage_init(void) { + struct udevice *dev; uchar reg, data_buffer[1]; + int ret; int i; - i2c_set_bus_num(0); /* PMU is on bus 0 */ + ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } /* TPS659110: LDO5_REG = 3.3v, ACTIVE to SDMMC1 */ data_buffer[0] = 0x65; reg = 0x32; for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1)) + if (i2c_write(dev, reg, data_buffer, 1)) udelay(100); } @@ -56,7 +63,7 @@ void board_sdmmc_voltage_init(void) reg = 0x67; for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1)) + if (i2c_write(dev, reg, data_buffer, 1)) udelay(100); } } diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 0e4a65ad05..4bdbf0194a 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -113,10 +113,6 @@ int board_init(void) power_det_init(); #ifdef CONFIG_SYS_I2C_TEGRA -#ifndef CONFIG_SYS_I2C_INIT_BOARD -#error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards" -#endif - i2c_init_board(); # ifdef CONFIG_TEGRA_PMU if (pmu_set_nominal()) debug("Failed to select nominal voltages\n"); diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c index f2d05afac7..2a737468dd 100644 --- a/board/nvidia/dalmore/dalmore.c +++ b/board/nvidia/dalmore/dalmore.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include "pinmux-config-dalmore.h" @@ -50,18 +51,21 @@ void pinmux_init(void) */ void board_sdmmc_voltage_init(void) { + struct udevice *dev; uchar reg, data_buffer[1]; int ret; - ret = i2c_set_bus_num(0);/* PMU is on bus 0 */ - if (ret) - printf("%s: i2c_set_bus_num returned %d\n", __func__, ret); + ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find PMIC I2C chip\n", __func__); + return; + } /* TPS65913: LDO9_VOLTAGE = 3.3V */ data_buffer[0] = 0x31; reg = 0x61; - ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: PMU i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); @@ -70,7 +74,7 @@ void board_sdmmc_voltage_init(void) data_buffer[0] = 0x01; reg = 0x60; - ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: PMU i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); @@ -79,7 +83,12 @@ void board_sdmmc_voltage_init(void) data_buffer[0] = 0x03; reg = 0x14; - ret = i2c_write(BAT_I2C_ADDRESS, reg, 1, data_buffer, 1); + ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, &dev); + if (ret) { + debug("%s: Cannot find charger I2C chip\n", __func__); + return; + } + ret = i2c_write(dev, reg, data_buffer, 1); if (ret) printf("%s: BAT i2c_write %02X<-%02X returned %d\n", __func__, reg, data_buffer[0], ret); diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c index 3e9d3d9f10..3114b20be0 100644 --- a/board/nvidia/whistler/whistler.c +++ b/board/nvidia/whistler/whistler.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -21,23 +22,26 @@ */ void pin_mux_mmc(void) { + struct udevice *dev; uchar val; int ret; /* Turn on MAX8907B LDO12 to 2.8V for J40 power */ - ret = i2c_set_bus_num(0); - if (ret) - printf("i2c_set_bus_num failed: %d\n", ret); + ret = i2c_get_chip_for_busnum(0, 0x3c, &dev); + if (ret) { + printf("%s: Cannot find MAX8907B I2C chip\n", __func__); + return; + } val = 0x29; - ret = i2c_write(0x3c, 0x46, 1, &val, 1); + ret = i2c_write(dev, 0x46, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x46 failed: %d\n", ret); val = 0x00; - ret = i2c_write(0x3c, 0x45, 1, &val, 1); + ret = i2c_write(dev, 0x45, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x45 failed: %d\n", ret); val = 0x1f; - ret = i2c_write(0x3c, 0x44, 1, &val, 1); + ret = i2c_write(dev, 0x44, &val, 1); if (ret) printf("i2c_write 0 0x3c 0x44 failed: %d\n", ret); @@ -49,6 +53,7 @@ void pin_mux_mmc(void) /* this is a weak define that we are overriding */ void pin_mux_usb(void) { + struct udevice *dev; uchar val; int ret; @@ -59,15 +64,17 @@ void pin_mux_usb(void) */ /* Turn on TAC6416's GPIO 0+1 for USB1/3's VBUS */ - ret = i2c_set_bus_num(0); - if (ret) - printf("i2c_set_bus_num failed: %d\n", ret); + ret = i2c_get_chip_for_busnum(0, 0x20, &dev); + if (ret) { + printf("%s: Cannot find TAC6416 I2C chip\n", __func__); + return; + } val = 0x03; - ret = i2c_write(0x20, 2, 1, &val, 1); + ret = i2c_write(dev, 2, &val, 1); if (ret) printf("i2c_write 0 0x20 2 failed: %d\n", ret); val = 0xfc; - ret = i2c_write(0x20, 6, 1, &val, 1); + ret = i2c_write(dev, 6, &val, 1); if (ret) printf("i2c_write 0 0x20 6 failed: %d\n", ret); } diff --git a/board/toradex/apalis_t30/apalis_t30.c b/board/toradex/apalis_t30/apalis_t30.c index b9d694a268..5d2c024e89 100644 --- a/board/toradex/apalis_t30/apalis_t30.c +++ b/board/toradex/apalis_t30/apalis_t30.c @@ -6,7 +6,7 @@ */ #include - +#include #include #include #include @@ -38,23 +38,20 @@ void pinmux_init(void) #ifdef CONFIG_PCI_TEGRA int tegra_pcie_board_init(void) { - unsigned int old_bus; + struct udevice *dev; u8 addr, data[1]; int err; - old_bus = i2c_get_bus_num(); - - err = i2c_set_bus_num(0); + err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev); if (err) { - debug("failed to set I2C bus\n"); + debug("%s: Cannot find PMIC I2C chip\n", __func__); return err; } - /* TPS659110: VDD2_OP_REG = 1.05V */ data[0] = 0x27; addr = 0x25; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to set VDD supply\n"); return err; @@ -64,7 +61,7 @@ int tegra_pcie_board_init(void) data[0] = 0x0D; addr = 0x24; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to enable VDD supply\n"); return err; @@ -74,14 +71,12 @@ int tegra_pcie_board_init(void) data[0] = 0x0D; addr = 0x35; - err = i2c_write(PMU_I2C_ADDRESS, addr, 1, data, 1); + err = i2c_write(dev, addr, data, 1); if (err) { debug("failed to set AVDD supply\n"); return err; } - i2c_set_bus_num(old_bus); - return 0; } diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 562211e7de..87290c3127 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -19,6 +21,12 @@ DECLARE_GLOBAL_DATA_PTR; +enum i2c_type { + TYPE_114, + TYPE_STD, + TYPE_DVC, +}; + /* Information about i2c controller */ struct i2c_bus { int id; @@ -27,20 +35,17 @@ struct i2c_bus { int pinmux_config; struct i2c_control *control; struct i2c_ctlr *regs; - int is_dvc; /* DVC type, rather than I2C */ - int is_scs; /* single clock source (T114+) */ + enum i2c_type type; int inited; /* bus is inited */ }; -static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS]; - static void set_packet_mode(struct i2c_bus *i2c_bus) { u32 config; config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK; - if (i2c_bus->is_dvc) { + if (i2c_bus->type == TYPE_DVC) { struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs; writel(config, &dvc->cnfg); @@ -65,6 +70,9 @@ static void i2c_reset_controller(struct i2c_bus *i2c_bus) static void i2c_init_controller(struct i2c_bus *i2c_bus) { + if (!i2c_bus->speed) + return; + debug("%s: speed=%d\n", __func__, i2c_bus->speed); /* * Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8 * here, in section 23.3.1, but in fact we seem to need a factor of @@ -73,7 +81,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, i2c_bus->speed * 2 * 8); - if (i2c_bus->is_scs) { + if (i2c_bus->type == TYPE_114) { /* * T114 I2C went to a single clock source for standard/fast and * HS clock speeds. The new clock rate setting calculation is: @@ -98,7 +106,7 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) i2c_reset_controller(i2c_bus); /* Configure I2C controller. */ - if (i2c_bus->is_dvc) { /* only for DVC I2C */ + if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */ struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs; setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); @@ -272,7 +280,7 @@ exit: return error; } -static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, +static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data, u32 len, bool end_with_repeated_start) { int error; @@ -286,14 +294,14 @@ static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data, trans_info.num_bytes = len; trans_info.is_10bit_address = 0; - error = send_recv_packets(bus, &trans_info); + error = send_recv_packets(i2c_bus, &trans_info); if (error) debug("tegra_i2c_write_data: Error (%d) !!!\n", error); return error; } -static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data, +static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data, u32 len) { int error; @@ -305,52 +313,32 @@ static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data, trans_info.num_bytes = len; trans_info.is_10bit_address = 0; - error = send_recv_packets(bus, &trans_info); + error = send_recv_packets(i2c_bus, &trans_info); if (error) debug("tegra_i2c_read_data: Error (%d) !!!\n", error); return error; } -#ifndef CONFIG_OF_CONTROL -#error "Please enable device tree support to use this driver" -#endif - -/** - * Check that a bus number is valid and return a pointer to it - * - * @param bus_num Bus number to check / return - * @return pointer to bus, if valid, else NULL - */ -static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap) +static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { - struct i2c_bus *bus; + struct i2c_bus *i2c_bus = dev_get_priv(dev); - bus = &i2c_controllers[adap->hwadapnr]; - if (!bus->inited) { - debug("%s: Bus %u not available\n", __func__, adap->hwadapnr); - return NULL; - } - - return bus; -} - -static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap, - unsigned int speed) -{ - struct i2c_bus *bus; - - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 0; - bus->speed = speed; - i2c_init_controller(bus); + i2c_bus->speed = speed; + i2c_init_controller(i2c_bus); return 0; } -static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) +static int tegra_i2c_probe(struct udevice *dev) { + struct i2c_bus *i2c_bus = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + bool is_dvc; + + i2c_bus->id = dev->seq; + i2c_bus->type = dev_get_of_data(dev); i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg"); /* @@ -358,7 +346,6 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) * far no one needs anything other than the default. */ i2c_bus->pinmux_config = FUNCMUX_DEFAULT; - i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0); i2c_bus->periph_id = clock_decode_periph_id(blob, node); /* @@ -371,107 +358,25 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus) * i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA; */ if (i2c_bus->periph_id == -1) - return -FDT_ERR_NOTFOUND; + return -EINVAL; - return 0; -} - -/* - * Process a list of nodes, adding them to our list of I2C ports. - * - * @param blob fdt blob - * @param node_list list of nodes to process (any <=0 are ignored) - * @param count number of nodes to process - * @param is_dvc 1 if these are DVC ports, 0 if standard I2C - * @param is_scs 1 if this HW uses a single clock source (T114+) - * @return 0 if ok, -1 on error - */ -static int process_nodes(const void *blob, int node_list[], int count, - int is_dvc, int is_scs) -{ - struct i2c_bus *i2c_bus; - int i; - - /* build the i2c_controllers[] for each controller */ - for (i = 0; i < count; i++) { - int node = node_list[i]; - - if (node <= 0) - continue; - - i2c_bus = &i2c_controllers[i]; - i2c_bus->id = i; - - if (i2c_get_config(blob, node, i2c_bus)) { - printf("i2c_init_board: failed to decode bus %d\n", i); - return -1; - } - - i2c_bus->is_scs = is_scs; - - i2c_bus->is_dvc = is_dvc; - if (is_dvc) { - i2c_bus->control = - &((struct dvc_ctlr *)i2c_bus->regs)->control; - } else { - i2c_bus->control = &i2c_bus->regs->control; - } - debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", - is_dvc ? "dvc" : "i2c", i, i2c_bus->regs, - i2c_bus->periph_id, i2c_bus->speed); - i2c_init_controller(i2c_bus); - debug("ok\n"); - i2c_bus->inited = 1; - - /* Mark position as used */ - node_list[i] = -1; + is_dvc = dev_get_of_data(dev) == TYPE_DVC; + if (is_dvc) { + i2c_bus->control = + &((struct dvc_ctlr *)i2c_bus->regs)->control; + } else { + i2c_bus->control = &i2c_bus->regs->control; } + i2c_init_controller(i2c_bus); + debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", + is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, + i2c_bus->periph_id, i2c_bus->speed); return 0; } -/* Sadly there is no error return from this function */ -void i2c_init_board(void) -{ - int node_list[TEGRA_I2C_NUM_CONTROLLERS]; - const void *blob = gd->fdt_blob; - int count; - - /* First check for newer (T114+) I2C ports */ - count = fdtdec_find_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA114_I2C, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 0, 1)) - return; - - /* Now get the older (T20/T30) normal I2C ports */ - count = fdtdec_find_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA20_I2C, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 0, 0)) - return; - - /* Now look for dvc ports */ - count = fdtdec_add_aliases_for_id(blob, "i2c", - COMPAT_NVIDIA_TEGRA20_DVC, node_list, - TEGRA_I2C_NUM_CONTROLLERS); - if (process_nodes(blob, node_list, count, 1, 0)) - return; -} - -static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) -{ - /* No i2c support prior to relocation */ - if (!(gd->flags & GD_FLG_RELOC)) - return; - - /* This will override the speed selected in the fdt for that port */ - debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr); - i2c_set_bus_speed(speed); -} - /* i2c write version without the register address */ -static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, +static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, int len, bool end_with_repeated_start) { int rc; @@ -484,7 +389,7 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, debug("\n"); /* Shift 7-bit address over for lower-level i2c functions */ - rc = tegra_i2c_write_data(bus, chip << 1, buffer, len, + rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len, end_with_repeated_start); if (rc) debug("i2c_write_data(): rc=%d\n", rc); @@ -493,14 +398,14 @@ static int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, } /* i2c read version without the register address */ -static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, - int len) +static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer, + int len) { int rc; debug("inside i2c_read_data():\n"); /* Shift 7-bit address over for lower-level i2c functions */ - rc = tegra_i2c_read_data(bus, chip << 1, buffer, len); + rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len); if (rc) { debug("i2c_read_data(): rc=%d\n", rc); return rc; @@ -516,132 +421,99 @@ static int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, } /* Probe to see if a chip is present. */ -static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip) +static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) { - struct i2c_bus *bus; + struct i2c_bus *i2c_bus = dev_get_priv(bus); int rc; - uchar reg; + u8 reg; - debug("i2c_probe: addr=0x%x\n", chip); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - reg = 0; - rc = i2c_write_data(bus, chip, ®, 1, false); - if (rc) { - debug("Error probing 0x%x.\n", chip); - return 1; - } - return 0; + /* Shift 7-bit address over for lower-level i2c functions */ + rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, ®, sizeof(reg), + false); + + return rc; } -static int i2c_addr_ok(const uint addr, const int alen) +static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, + int nmsgs) { - /* We support 7 or 10 bit addresses, so one or two bytes each */ - return alen == 1 || alen == 2; -} + struct i2c_bus *i2c_bus = dev_get_priv(bus); + int ret; -/* Read bytes */ -static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - struct i2c_bus *bus; - uint offset; - int i; + debug("i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); - debug("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", - chip, addr, alen, len); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - if (!i2c_addr_ok(addr, alen)) { - debug("i2c_read: Bad address %x.%d.\n", addr, alen); - return 1; - } - for (offset = 0; offset < len; offset++) { - if (alen) { - uchar data[alen]; - for (i = 0; i < alen; i++) { - data[alen - i - 1] = - (addr + offset) >> (8 * i); - } - if (i2c_write_data(bus, chip, data, alen, true)) { - debug("i2c_read: error sending (0x%x)\n", - addr); - return 1; - } + debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); + if (msg->flags & I2C_M_RD) { + ret = i2c_read_data(i2c_bus, msg->addr, msg->buf, + msg->len); + } else { + ret = i2c_write_data(i2c_bus, msg->addr, msg->buf, + msg->len, next_is_read); } - if (i2c_read_data(bus, chip, buffer + offset, 1)) { - debug("i2c_read: error reading (0x%x)\n", addr); - return 1; + if (ret) { + debug("i2c_write: error sending\n"); + return -EREMOTEIO; } } return 0; } -/* Write bytes */ -static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) +int tegra_i2c_get_dvc_bus(struct udevice **busp) { - struct i2c_bus *bus; - uint offset; - int i; + struct udevice *bus; - debug("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x len=0x%x\n", - chip, addr, alen, len); - bus = tegra_i2c_get_bus(adap); - if (!bus) - return 1; - if (!i2c_addr_ok(addr, alen)) { - debug("i2c_write: Bad address %x.%d.\n", addr, alen); - return 1; - } - for (offset = 0; offset < len; offset++) { - uchar data[alen + 1]; - for (i = 0; i < alen; i++) - data[alen - i - 1] = (addr + offset) >> (8 * i); - data[alen] = buffer[offset]; - if (i2c_write_data(bus, chip, data, alen + 1, false)) { - debug("i2c_write: error sending (0x%x)\n", addr); - return 1; + for (uclass_first_device(UCLASS_I2C, &bus); + bus; + uclass_next_device(&bus)) { + if (dev_get_of_data(bus) == TYPE_DVC) { + *busp = bus; + return 0; } } + return -ENODEV; +} + +static const struct dm_i2c_ops tegra_i2c_ops = { + .xfer = tegra_i2c_xfer, + .probe_chip = tegra_i2c_probe_chip, + .set_bus_speed = tegra_i2c_set_bus_speed, +}; + +static int tegra_i2c_child_pre_probe(struct udevice *dev) +{ + struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev); + + if (dev->of_offset == -1) + return 0; + return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, + i2c_chip); +} + +static int tegra_i2c_ofdata_to_platdata(struct udevice *dev) +{ return 0; } -int tegra_i2c_get_dvc_bus_num(void) -{ - int i; +static const struct udevice_id tegra_i2c_ids[] = { + { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 }, + { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD }, + { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC }, + { } +}; - for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) { - struct i2c_bus *bus = &i2c_controllers[i]; - - if (bus->inited && bus->is_dvc) - return i; - } - - return -1; -} - -/* - * Register soft i2c adapters - */ -U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 0) -U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 1) -U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 2) -U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 3) -#if TEGRA_I2C_NUM_CONTROLLERS > 4 -U_BOOT_I2C_ADAP_COMPLETE(tegra4, tegra_i2c_init, tegra_i2c_probe, - tegra_i2c_read, tegra_i2c_write, - tegra_i2c_set_bus_speed, 100000, 0, 4) -#endif +U_BOOT_DRIVER(i2c_tegra) = { + .name = "i2c_tegra", + .id = UCLASS_I2C, + .of_match = tegra_i2c_ids, + .ofdata_to_platdata = tegra_i2c_ofdata_to_platdata, + .probe = tegra_i2c_probe, + .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), + .child_pre_probe = tegra_i2c_child_pre_probe, + .priv_auto_alloc_size = sizeof(struct i2c_bus), + .ops = &tegra_i2c_ops, +}; diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c index d29d969533..29bab4cc00 100644 --- a/drivers/power/tps6586x.c +++ b/drivers/power/tps6586x.c @@ -10,9 +10,7 @@ #include #include -static int bus_num; /* I2C bus we are on */ -#define I2C_ADDRESS 0x34 /* chip requires this address */ -static char inited; /* 1 if we have been inited */ +static struct udevice *tps6586x_dev; enum { /* Registers that we access */ @@ -37,13 +35,9 @@ static int tps6586x_read(int reg) int i; uchar data; int retval = -1; - int old_bus_num; - - old_bus_num = i2c_get_bus_num(); - i2c_set_bus_num(bus_num); for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) { + if (!i2c_read(tps6586x_dev, reg, &data, 1)) { retval = (int)data; goto exit; } @@ -53,7 +47,6 @@ static int tps6586x_read(int reg) } exit: - i2c_set_bus_num(old_bus_num); debug("pmu_read %x=%x\n", reg, retval); if (retval < 0) debug("%s: failed to read register %#x: %d\n", __func__, reg, @@ -65,13 +58,9 @@ static int tps6586x_write(int reg, uchar *data, uint len) { int i; int retval = -1; - int old_bus_num; - - old_bus_num = i2c_get_bus_num(); - i2c_set_bus_num(bus_num); for (i = 0; i < MAX_I2C_RETRY; ++i) { - if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) { + if (!i2c_write(tps6586x_dev, reg, data, len)) { retval = 0; goto exit; } @@ -81,7 +70,6 @@ static int tps6586x_write(int reg, uchar *data, uint len) } exit: - i2c_set_bus_num(old_bus_num); debug("pmu_write %x=%x: ", reg, retval); for (i = 0; i < len; i++) debug("%x ", data[i]); @@ -163,7 +151,7 @@ int tps6586x_set_pwm_mode(int mask) uchar val; int ret; - assert(inited); + assert(tps6586x_dev); ret = tps6586x_read(PFM_MODE); if (ret != -1) { val = (uchar)ret; @@ -184,7 +172,7 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, int sm0, sm1; int bad; - assert(inited); + assert(tps6586x_dev); /* get current voltage settings */ if (read_voltages(&sm0, &sm1)) { @@ -255,10 +243,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, return bad ? -1 : 0; } -int tps6586x_init(int bus) +int tps6586x_init(struct udevice *dev) { - bus_num = bus; - inited = 1; + tps6586x_dev = dev; return 0; } diff --git a/include/configs/apalis_t30.h b/include/configs/apalis_t30.h index 3cde923b5f..61809fcdbe 100644 --- a/include/configs/apalis_t30.h +++ b/include/configs/apalis_t30.h @@ -26,10 +26,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/beaver.h b/include/configs/beaver.h index 164b2dd951..5d765f3d36 100644 --- a/include/configs/beaver.h +++ b/include/configs/beaver.h @@ -40,10 +40,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index 09129c7767..758b7ad392 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -43,12 +43,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/colibri_t30.h b/include/configs/colibri_t30.h index a582e25516..ce6f23b8c4 100644 --- a/include/configs/colibri_t30.h +++ b/include/configs/colibri_t30.h @@ -25,10 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h index ff7ec4a93b..0b04ee67b3 100644 --- a/include/configs/dalmore.h +++ b/include/configs/dalmore.h @@ -36,12 +36,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h index d67c025b9c..a7d76650ce 100644 --- a/include/configs/jetson-tk1.h +++ b/include/configs/jetson-tk1.h @@ -25,12 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/nyan-big.h b/include/configs/nyan-big.h index a62bc4e018..cf331ab207 100644 --- a/include/configs/nyan-big.h +++ b/include/configs/nyan-big.h @@ -25,12 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index 04e4f82759..5f77051d13 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -37,10 +37,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/tec-ng.h b/include/configs/tec-ng.h index 51f87dacdb..e37b23359b 100644 --- a/include/configs/tec-ng.h +++ b/include/configs/tec-ng.h @@ -23,12 +23,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index d690045eb0..06853285a2 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -26,6 +26,7 @@ #endif #define CONFIG_DM_SPI #define CONFIG_DM_SPI_FLASH +#define CONFIG_DM_I2C #define CONFIG_SYS_TIMER_RATE 1000000 #define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE diff --git a/include/configs/tegra114-common.h b/include/configs/tegra114-common.h index 555c237cbf..9eba5d517d 100644 --- a/include/configs/tegra114-common.h +++ b/include/configs/tegra114-common.h @@ -76,9 +76,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra114 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/tegra124-common.h b/include/configs/tegra124-common.h index 61e5026574..f2b3774da8 100644 --- a/include/configs/tegra124-common.h +++ b/include/configs/tegra124-common.h @@ -68,9 +68,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra124 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index 21bf977174..6330281df7 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -97,9 +97,6 @@ #define CONFIG_EHCI_IS_TDI #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 -/* Total I2C ports on Tegra20 */ -#define TEGRA_I2C_NUM_CONTROLLERS 4 - #define CONFIG_SYS_NAND_SELF_INIT #define CONFIG_SYS_NAND_ONFI_DETECTION diff --git a/include/configs/tegra30-common.h b/include/configs/tegra30-common.h index 443c842240..bfdbeb70d2 100644 --- a/include/configs/tegra30-common.h +++ b/include/configs/tegra30-common.h @@ -73,9 +73,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x80090000 #define CONFIG_SPL_STACK 0x800ffffc -/* Total I2C ports on Tegra30 */ -#define TEGRA_I2C_NUM_CONTROLLERS 5 - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 diff --git a/include/configs/trimslice.h b/include/configs/trimslice.h index 7c0064267d..a254f86409 100644 --- a/include/configs/trimslice.h +++ b/include/configs/trimslice.h @@ -34,10 +34,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/venice2.h b/include/configs/venice2.h index 6897aa8aa3..8880de86c4 100644 --- a/include/configs/venice2.h +++ b/include/configs/venice2.h @@ -25,12 +25,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/configs/whistler.h b/include/configs/whistler.h index 10e70d28b1..e083cbd07f 100644 --- a/include/configs/whistler.h +++ b/include/configs/whistler.h @@ -26,10 +26,7 @@ /* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC diff --git a/include/tps6586x.h b/include/tps6586x.h index 78ce428767..eefc95f22e 100644 --- a/include/tps6586x.h +++ b/include/tps6586x.h @@ -44,9 +44,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, * Set up the TPS6586X I2C bus number. This will be used for all operations * on the device. This function must be called before using other functions. * - * @param bus I2C bus number containing the TPS6586X chip + * @param bus I2C bus containing the TPS6586X chip * @return 0 (always succeeds) */ -int tps6586x_init(int bus); +int tps6586x_init(struct udevice *bus); #endif /* _TPS6586X_H_ */