* [U-Boot-Users] [Patch 0/9] U-boot-V2: Introduce I2C support for SDP3430
2008-06-18 20:44 ` Robert Schwebel
@ 2008-06-18 20:52 ` Menon, Nishanth
2008-06-19 15:10 ` Menon, Nishanth
` (9 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-18 20:52 UTC (permalink / raw)
To: u-boot
Robert,
> -----Original Message-----
> From: Robert Schwebel [mailto:r.schwebel at pengutronix.de]
> Sent: Wednesday, June 18, 2008 3:44 PM
> To: Menon, Nishanth
> Cc: Sascha Hauer; Timur Tabi; Laurent Desnogues; Kamat, Nishant; philip.balister at gmail.com; u-boot-
> users at lists.sourceforge.net
> Subject: Re: [U-Boot-Users] [Patch 0/9] U-boot-V2: Introduce I2C support for SDP3430
>
> Yea, looking forward especially for PCI patches :-)
;) not in my immediate future at least :D
> Yes, but I think what we most of all need is the i2c communication with
> the device. We should think about if the abstraction of the devices
> *behind* the bus brings us anything; note that you can do lots of things
> in scripts in u-boot-v2. Linke writing a shell function for your usb
> transceivers which just encapsulates the right predefined i2c_read/write
> operations.
>
> > Are we ok with i2ctools movement here?
>
> Hmm? How do you mean that?
I2cdetect, i2cget, i2cset, i2cdump -> see patch 6. They are handy little tools for debug. I2cdev will be required to provide a device interface.
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 0/9] U-boot-V2: Introduce I2C support for SDP3430
2008-06-18 20:44 ` Robert Schwebel
2008-06-18 20:52 ` Menon, Nishanth
@ 2008-06-19 15:10 ` Menon, Nishanth
2008-06-19 15:11 ` [U-Boot-Users] [Patch 1/9]U-boot-V2:ID: Add i2c_device_id Menon, Nishanth
` (8 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:10 UTC (permalink / raw)
To: u-boot
Hi Folks,
This is the series of redo for the I2C related
patches. This series contains the following:
[Patch 1/9]U-boot-V2:ID: Add i2c_device_id
[Patch 2/9]U-boot-V2:ID: Introduce idr
[Patch 3/9]U-boot-V2:I2C: Introduce core
[Patch 4/9]U-boot-V2:I2C: Introduce i2c-dev
[Patch 5/9]U-boot-V2:cmd: add I2C commands
[Patch 6/9]U-boot-V2:cmd: I2C commands support
[Patch 7/9]U-boot-V2:ARM:OMAP: OMAP classes
[Patch 8/9]U-boot-V2:I2C:Busses: OMAP I2C Adapter
[Patch 9/9]U-boot-V2:Boards:SDP3430 I2C bus1
This series depends on the bitops and __KERNEL__
cleanup patches send earlier today. As discussed,
These patches add only I2C, SMBUS and other
features are to be added at a later point of time.
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 1/9]U-boot-V2:ID: Add i2c_device_id
2008-06-18 20:44 ` Robert Schwebel
2008-06-18 20:52 ` Menon, Nishanth
2008-06-19 15:10 ` Menon, Nishanth
@ 2008-06-19 15:11 ` Menon, Nishanth
2008-06-19 15:11 ` [U-Boot-Users] [Patch 2/9]U-boot-V2:ID: Introduce idr Menon, Nishanth
` (7 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:11 UTC (permalink / raw)
To: u-boot
Introduce device_id for I2C. This will allow for
clients to register at a later stage with
multiple IDs. Currently introduced for i2c-dev's
generic client support
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
include/linux/mod_devicetable.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
Index: u-boot-v2.git/include/linux/mod_devicetable.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/mod_devicetable.h 2008-06-19 08:39:34.000000000 -0500
@@ -0,0 +1,25 @@
+/*
+ * Device tables which are exported via
+ * scripts/mod/file2alias.c. You must keep that file in sync with this
+ * header.
+ */
+
+#ifndef LINUX_MOD_DEVICETABLE_H
+#define LINUX_MOD_DEVICETABLE_H
+
+#ifdef __U_BOOT__
+#include <linux/types.h>
+typedef unsigned long kernel_ulong_t;
+#endif
+
+#define I2C_NAME_SIZE 20
+#define I2C_MODULE_PREFIX "i2c:"
+
+struct i2c_device_id {
+ char name[I2C_NAME_SIZE];
+ kernel_ulong_t driver_data /* Data private to the driver */
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
+
+#endif /* LINUX_MOD_DEVICETABLE_H */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 2/9]U-boot-V2:ID: Introduce idr
2008-06-18 20:44 ` Robert Schwebel
` (2 preceding siblings ...)
2008-06-19 15:11 ` [U-Boot-Users] [Patch 1/9]U-boot-V2:ID: Add i2c_device_id Menon, Nishanth
@ 2008-06-19 15:11 ` Menon, Nishanth
2008-06-19 15:11 ` [U-Boot-Users] [Patch 3/9]U-boot-V2:I2C: Introduce core Menon, Nishanth
` (6 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:11 UTC (permalink / raw)
To: u-boot
Introduce selected ID table translation functions
from Linux kernel.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
include/linux/idr.h | 91 ++++++++++++
lib/Makefile | 1
lib/idr.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 484 insertions(+)
Index: u-boot-v2.git/include/linux/idr.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/idr.h 2008-06-19 08:41:21.000000000 -0500
@@ -0,0 +1,91 @@
+/**
+ * @file
+ * @brief Small id to pointer translation service avoiding fixed sized
+ * tables.
+ *
+ * FileName: include/linux/idr.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ *
+ * 2002-10-18 written by Jim Houston jim.houston at ccur.com
+ * Copyright (C) 2002 by Concurrent Computer Corporation
+ * Distributed under the GNU GPL license version 2.
+ */
+
+#ifndef __IDR_H__
+#define __IDR_H__
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <init.h>
+
+#if BITS_PER_LONG == 32
+# define IDR_BITS 5
+# define IDR_FULL 0xfffffffful
+/** We can only use two of the bits in the top level because there is
+ only one possible bit in the top level (5 bits * 7 levels = 35
+ bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 30)
+#elif BITS_PER_LONG == 64
+# define IDR_BITS 6
+# define IDR_FULL 0xfffffffffffffffful
+/** We can only use two of the bits in the top level because there is
+ only one possible bit in the top level (6 bits * 6 levels = 36
+ bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 62)
+#else
+# error "BITS_PER_LONG is not 32 or 64"
+#endif
+
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK ((1 << IDR_BITS)-1)
+
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+
+/** Leave the possibility of an incomplete final layer */
+#define MAX_LEVEL ((MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS)
+
+/** Number of id_layer structs to leave in free list */
+#define IDR_FREE_MAX (MAX_LEVEL + MAX_LEVEL)
+
+struct idr_layer {
+ unsigned long bitmap; /** A zero bit means "space here" */
+ struct idr_layer *ary[1 << IDR_BITS];
+ int count; /** When zero, we can release it */
+};
+
+struct idr {
+ struct idr_layer *top;
+ struct idr_layer *id_free;
+ int layers;
+ int id_free_cnt;
+};
+
+#define IDR_INIT(name) \
+{ \
+ .top = NULL, \
+ .id_free = NULL, \
+ .layers = 0, \
+ .id_free_cnt = 0, \
+}
+#define DEFINE_IDR(name) struct idr name = IDR_INIT(name)
+
+/**
+ * This is what we export.
+ */
+
+void *idr_find(struct idr *idp, int id);
+int idr_pre_get(struct idr *idp);
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
+void idr_remove(struct idr *idp, int id);
+void idr_init(struct idr *idp);
+
+#endif /* __IDR_H__ */
Index: u-boot-v2.git/lib/idr.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/lib/idr.c 2008-06-19 08:42:27.000000000 -0500
@@ -0,0 +1,392 @@
+/**
+ * @file
+ * @brief Small id to pointer translation service.
+ *
+ * FileName: lib/idr.c
+ *
+ * It uses a radix tree like structure as a sparse array indexed
+ * by the id to obtain the pointer. The bitmap makes allocating
+ * a new id quick.
+ *
+ * You call it to allocate an id (an int) an associate with that id a
+ * pointer or what ever, we treat it as a (void *). You can pass this
+ * id to a user for him to pass back at a later time. You then pass
+ * that id to this code and it returns your pointer.
+
+ * You can release ids@any time. When all ids are released, most of
+ * the memory is returned (we keep IDR_FREE_MAX) in a local pool so we
+ * don't need to go to the memory "store" during an id allocate, just
+ * so you don't need to be too concerned about locking and conflicts
+ * with the slab allocator.
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ * 2002-10-18 written by Jim Houston jim.houston at ccur.com
+ * Copyright (C) 2002 by Concurrent Computer Corporation
+ * Distributed under the GNU GPL license version 2.
+ *
+ * Modified by George Anzinger to reuse immediately and to use
+ * find bit instructions. Also removed _irq on spinlocks.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <string.h>
+#include <init.h>
+#include <malloc.h>
+#include <linux/bitops.h>
+#include <linux/idr.h>
+
+static void idr_remove_warning(int id)
+{
+ printf("idr_remove called for id=%d which is not allocated.\n", id);
+ hang();
+}
+
+static struct idr_layer *alloc_layer(struct idr *idp)
+{
+ struct idr_layer *p;
+ p = idp->id_free;
+ if (p) {
+ idp->id_free = p->ary[0];
+ idp->id_free_cnt--;
+ p->ary[0] = NULL;
+ }
+ return p;
+}
+
+/* only called when idp->lock is held */
+static void __free_layer(struct idr *idp, struct idr_layer *p)
+{
+ p->ary[0] = idp->id_free;
+ idp->id_free = p;
+ idp->id_free_cnt++;
+}
+
+static void free_layer(struct idr *idp, struct idr_layer *p)
+{
+ /*
+ * Depends on the return element being zeroed.
+ */
+ __free_layer(idp, p);
+}
+
+static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
+{
+ int n, m, sh;
+ struct idr_layer *p, *new;
+ int l, id, oid;
+ unsigned long bm;
+
+ id = *starting_id;
+ restart:
+ p = idp->top;
+ l = idp->layers;
+ pa[l--] = NULL;
+ while (1) {
+ /*
+ * We run around this while until we reach the leaf node...
+ */
+ n = (id >> (IDR_BITS*l)) & IDR_MASK;
+ bm = ~p->bitmap;
+ m = find_next_bit(&bm, IDR_SIZE, n);
+ if (m == IDR_SIZE) {
+ /* no space available go back to previous layer. */
+ l++;
+ oid = id;
+ id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
+
+ /* if already@the top layer, we need to grow */
+ p = pa[l];
+ if (!p) {
+ *starting_id = id;
+ return -2;
+ }
+
+ /* If we need to go up one layer, continue the
+ * loop; otherwise, restart from the top.
+ */
+ sh = IDR_BITS * (l + 1);
+ if (oid >> sh == id >> sh)
+ continue;
+ else
+ goto restart;
+ }
+ if (m != n) {
+ sh = IDR_BITS*l;
+ id = ((id >> sh) ^ n ^ m) << sh;
+ }
+ if ((id >= MAX_ID_BIT) || (id < 0))
+ return -3;
+ if (l == 0)
+ break;
+ /*
+ * Create the layer below if it is missing.
+ */
+ if (!p->ary[m]) {
+ new = alloc_layer(idp);
+ if (!new)
+ return -1;
+ p->ary[m] = new;
+ p->count++;
+ }
+ pa[l--] = p;
+ p = p->ary[m];
+ }
+
+ pa[l] = p;
+ return id;
+}
+
+static void sub_remove(struct idr *idp, int shift, int id)
+{
+ struct idr_layer *p = idp->top;
+ struct idr_layer **pa[MAX_LEVEL];
+ struct idr_layer ***paa = &pa[0];
+ int n;
+
+ *paa = NULL;
+ *++paa = &idp->top;
+
+ while ((shift > 0) && p) {
+ n = (id >> shift) & IDR_MASK;
+ __clear_bit(n, &p->bitmap);
+ *++paa = &p->ary[n];
+ p = p->ary[n];
+ shift -= IDR_BITS;
+ }
+ n = id & IDR_MASK;
+ if (p != NULL && test_bit(n, &p->bitmap)) {
+ __clear_bit(n, &p->bitmap);
+ p->ary[n] = NULL;
+ while (*paa && !--((**paa)->count)) {
+ free_layer(idp, **paa);
+ **paa-- = NULL;
+ }
+ if (!*paa)
+ idp->layers = 0;
+ } else
+ idr_remove_warning(id);
+}
+
+static int idr_get_empty_slot(struct idr *idp, int starting_id,
+ struct idr_layer **pa)
+{
+ struct idr_layer *p, *new;
+ int layers, v, id;
+
+ id = starting_id;
+build_up:
+ p = idp->top;
+ layers = idp->layers;
+ if (!p) {
+ p = alloc_layer(idp);
+ if (!p)
+ return -1;
+ layers = 1;
+ }
+ /*
+ * Add a new layer to the top of the tree if the requested
+ * id is larger than the currently allocated space.
+ */
+ while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
+ layers++;
+ if (!p->count)
+ continue;
+ new = alloc_layer(idp);
+ if (!new) {
+ /*
+ * The allocation failed. If we built part of
+ * the structure tear it down.
+ */
+ for (new = p; p && p != idp->top; new = p) {
+ p = p->ary[0];
+ new->ary[0] = NULL;
+ new->bitmap = new->count = 0;
+ __free_layer(idp, new);
+ }
+ return -1;
+ }
+ new->ary[0] = p;
+ new->count = 1;
+ if (p->bitmap == IDR_FULL)
+ __set_bit(0, &new->bitmap);
+ p = new;
+ }
+ idp->top = p;
+ idp->layers = layers;
+ v = sub_alloc(idp, &id, pa);
+ if (v == -2)
+ goto build_up;
+ return v;
+}
+
+static void idr_mark_full(struct idr_layer **pa, int id)
+{
+ struct idr_layer *p = pa[0];
+ int l = 0;
+
+ __set_bit(id & IDR_MASK, &p->bitmap);
+ /*
+ * If this layer is full mark the bit in the layer above to
+ * show that this part of the radix tree is full. This may
+ * complete the layer above and require walking up the radix
+ * tree.
+ */
+ while (p->bitmap == IDR_FULL) {
+ p = pa[++l];
+ if (!p)
+ break;
+ id = id >> IDR_BITS;
+ __set_bit((id & IDR_MASK), &p->bitmap);
+ }
+}
+
+static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
+{
+ struct idr_layer *pa[MAX_LEVEL];
+ int id;
+
+ id = idr_get_empty_slot(idp, starting_id, pa);
+ if (id >= 0) {
+ /*
+ * Successfully found an empty slot. Install the user
+ * pointer and mark the slot full.
+ */
+ pa[0]->ary[id & IDR_MASK] = (struct idr_layer *)ptr;
+ pa[0]->count++;
+ idr_mark_full(pa, id);
+ }
+
+ return id;
+}
+
+
+/**
+ * idr_find - return pointer for given id
+ * @idp: idr handle
+ * @id: lookup key
+ *
+ * Return the pointer given the id it has been registered with. A %NULL
+ * return indicates that @id is not valid or you passed %NULL in
+ * idr_get_new().
+ *
+ * The caller must serialize idr_find() vs idr_get_new() and idr_remove().
+ */
+void *idr_find(struct idr *idp, int id)
+{
+ int n;
+ struct idr_layer *p;
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ if (id >= (1 << n))
+ return NULL;
+
+ while (n > 0 && p) {
+ n -= IDR_BITS;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+ return (void *)p;
+}
+EXPORT_SYMBOL(idr_find);
+
+/**
+ * idr_remove - remove the given id and free it's slot
+ * @idp: idr handle
+ * @id: unique key
+ */
+void idr_remove(struct idr *idp, int id)
+{
+ struct idr_layer *p;
+
+ /* Mask off upper bits we don't use for the search. */
+ id &= MAX_ID_MASK;
+
+ sub_remove(idp, (idp->layers - 1) * IDR_BITS, id);
+ if (idp->top && idp->top->count == 1 &&
+ (idp->layers > 1) &&
+ idp->top->ary[0]) {
+ /* We can drop a layer */
+ p = idp->top->ary[0];
+ idp->top->bitmap = idp->top->count = 0;
+ free_layer(idp, idp->top);
+ idp->top = p;
+ --idp->layers;
+ }
+ while (idp->id_free_cnt >= IDR_FREE_MAX) {
+ p = alloc_layer(idp);
+ free(p);
+ }
+ return;
+}
+EXPORT_SYMBOL(idr_remove);
+
+/**
+ * idr_pre_get - reserver resources for idr allocation
+ * @idp: idr handle
+ * @gfp_mask: memory allocation flags
+ *
+ * This function should be called prior to locking and calling the
+ * following function. It preallocates enough memory to satisfy
+ * the worst possible allocation.
+ *
+ * If the system is REALLY out of memory this function returns 0,
+ * otherwise 1.
+ */
+int idr_pre_get(struct idr *idp)
+{
+ while (idp->id_free_cnt < IDR_FREE_MAX) {
+ struct idr_layer *new;
+ new = malloc(sizeof(struct idr_layer));
+ if (new == NULL)
+ return 0;
+ free_layer(idp, new);
+ }
+ return 1;
+}
+EXPORT_SYMBOL(idr_pre_get);
+
+/**
+ * idr_get_new_above - allocate new idr entry above or equal to a start id
+ * @idp: idr handle
+ * @ptr: pointer you want associated with the ide
+ * @start_id: id to start search at
+ * @id: pointer to the allocated handle
+ *
+ * This is the allocate id function. It should be called with any
+ * required locks.
+ *
+ * If memory is required, it will return -EAGAIN, you should unlock
+ * and go back to the idr_pre_get() call. If the idr is full, it will
+ * return -ENOSPC.
+ *
+ * @id returns a value in the range 0 ... 0x7fffffff
+ */
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
+{
+ int rv;
+
+ rv = idr_get_new_above_int(idp, ptr, starting_id);
+ /*
+ * This is a cheap hack until the IDR code can be fixed to
+ * return proper error values.
+ */
+ if (rv < 0) {
+ if (rv == -1)
+ return -EAGAIN;
+ else /* Will be -3 */
+ return -ENOSPC;
+ }
+ *id = rv;
+ return 0;
+}
+EXPORT_SYMBOL(idr_get_new_above);
Index: u-boot-v2.git/lib/Makefile
===================================================================
--- u-boot-v2.git.orig/lib/Makefile 2008-06-19 08:40:01.000000000 -0500
+++ u-boot-v2.git/lib/Makefile 2008-06-19 08:40:15.000000000 -0500
@@ -16,6 +16,7 @@
obj-y += stringlist.o
obj-y += recursive_action.o
obj-y += make_directory.o
+obj-y += idr.o
obj-$(CONFIG_BZLIB) += bzlib.o bzlib_crctable.o bzlib_decompress.o bzlib_huffman.o bzlib_randtable.o
obj-$(CONFIG_ZLIB) += zlib.o gunzip.o
obj-$(CONFIG_CRC32) += crc32.o
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 3/9]U-boot-V2:I2C: Introduce core
2008-06-18 20:44 ` Robert Schwebel
` (3 preceding siblings ...)
2008-06-19 15:11 ` [U-Boot-Users] [Patch 2/9]U-boot-V2:ID: Introduce idr Menon, Nishanth
@ 2008-06-19 15:11 ` Menon, Nishanth
2008-06-19 15:12 ` [U-Boot-Users] [Patch 4/9]U-boot-V2:I2C: Introduce i2c-dev Menon, Nishanth
` (5 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:11 UTC (permalink / raw)
To: u-boot
First part of this patch introduces i2c-core.
The codebase is sourced from 2.6.25 rc5 kernel
contains ONLY i2c support. SMBUS is to be added
on a need basis
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
drivers/Kconfig | 1
drivers/Makefile | 1
drivers/i2c/Kconfig | 39 ++++
drivers/i2c/Makefile | 10 +
drivers/i2c/busses/Kconfig | 7
drivers/i2c/busses/Makefile | 9 +
drivers/i2c/i2c-core.c | 387 ++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.h | 37 ++++
include/driver.h | 4
include/linux/i2c.h | 299 +++++++++++++++++++++++++++++++++
10 files changed, 793 insertions(+), 1 deletion(-)
Index: u-boot-v2.git/drivers/i2c/i2c-core.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/i2c-core.c 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,387 @@
+/**
+ * @file
+ * @brief a device driver for the iic-bus interface
+ *
+ * FileName: drivers/i2c/i2c-core.c
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2006-2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 1995-99 Simon G. Vogl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Ky??sti M?$lkki <kmalkki@cc.hut.fi>.
+ All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
+ SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
+ Jean Delvare <khali@linux-fr.org> */
+
+#include <common.h>
+#include <errno.h>
+#include <list.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/i2c.h>
+#include <linux/idr.h>
+
+#include "i2c-core.h"
+
+#ifdef CONFIG_I2C_DEBUG_CORE
+#define DBG_MODULE_NAME "i2c-core"
+#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
+#define dev_warn(ARGS...) fprintf(stderr, ARGS);
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#else
+#define dev_dbg(ARGS...)
+#define dev_warn(ARGS...)
+#define dbg_entry(FORMAT, ARGS...)
+#define dbg_exit(FORMAT, ARGS...)
+#endif
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+static DEFINE_IDR(i2c_adapter_idr);
+
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find. Use this function to avoid oopses caused
+ * by wrongly treating some non-I2C device as an i2c_client.
+ *
+ * @param dev device, probably from some driver model iterator
+ *
+ * @return return parameter as i2c_client, or NULL
+ */
+struct i2c_client *i2c_verify_client(struct device_d *dev)
+{
+ dbg_entry("dev=%x", (u32) dev);
+ return (dev->type == DEVICE_TYPE_I2C) ? to_i2c_client(dev) : NULL;
+}
+EXPORT_SYMBOL(i2c_verify_client);
+
+static int i2c_register_adapter(struct i2c_adapter *adap)
+{
+ int res = 0;
+ dbg_entry("adap=%x", (u32) adap);
+
+ INIT_LIST_HEAD(&adap->clients);
+
+ /* Add the adapter to the driver core.
+ * If the parent pointer is not set up,
+ * we add this adapter to the host bus.
+ */
+ res = register_device(&adap->dev);
+ if (res)
+ goto out_list;
+
+ dev_dbg("adapter [%s] registered\n", adap->name);
+
+out_unlock:
+ return res;
+
+out_list:
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ goto out_unlock;
+}
+
+/**
+ * @brief declare i2c adapter, use dynamic bus number
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter. Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * @param adapter the adapter to add
+ *
+ * @return When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adapter)
+{
+ int id, res = 0;
+ dbg_entry("adapter=%x", (u32) adapter);
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr) == 0)
+ return -ENOMEM;
+
+ /* "above" here means "above or equal to", sigh */
+ res = idr_get_new_above(&i2c_adapter_idr, adapter,
+ __i2c_first_dynamic_bus_num, &id);
+
+ if (res < 0) {
+ if (res == -EAGAIN)
+ goto retry;
+ return res;
+ }
+
+ adapter->nr = id;
+ return i2c_register_adapter(adapter);
+}
+EXPORT_SYMBOL(i2c_add_adapter);
+
+/**
+ * @brief declare i2c adapter, use static bus number
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters. For example, use it for I2C adapters from system-on-chip CPUs,
+ * or otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices.
+ *
+ * If no devices have pre-been declared for this bus, then be sure to
+ * register the adapter before any dynamically allocated ones. Otherwise
+ * the required bus ID may not be available.
+ *
+ * @param adap adapter to register (with adap->nr initialized)
+ *
+ * @return When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr. Also, the table
+ * of I2C devices pre-declared using i2c_register_board_info() is scanned,
+ * and the appropriate driver model device nodes are created. Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adap)
+{
+ int id;
+ int status;
+
+ dbg_entry("adap=%x", (u32) adap);
+ if (adap->nr & ~MAX_ID_MASK)
+ return -EINVAL;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr) == 0)
+ return -ENOMEM;
+
+ /* "above" here means "above or equal to", sigh;
+ * we need the "equal to" result to force the result
+ */
+ status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+ if (status == 0 && id != adap->nr) {
+ status = -EBUSY;
+ idr_remove(&i2c_adapter_idr, id);
+ }
+ if (status == -EAGAIN)
+ goto retry;
+
+ if (status == 0)
+ status = i2c_register_adapter(adap);
+ return status;
+}
+EXPORT_SYMBOL(i2c_add_numbered_adapter);
+
+/**
+ * @brief unregister I2C adapter
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ *
+ * @param adap the adapter being unregistered
+ *
+ * @return success or failure in removal
+ */
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+ struct list_head *item, *_n;
+ struct i2c_client *client;
+ int res = 0;
+
+ dbg_entry("adap=%x", (u32) adap);
+ /* First make sure that this adapter was ever added */
+ if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
+ dev_err("i2c-core: attempting to delete unregistered "
+ "adapter [%s]\n", adap->name);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* detach any active clients. This must be done first, because
+ * it can fail; in which case we give up. */
+ list_for_each_safe(item, _n, &adap->clients) {
+ struct i2c_driver *driver;
+
+ client = list_entry(item, struct i2c_client, list);
+ driver = client->driver;
+
+ /* new style, follow standard driver model
+ * Place holder
+ if (!driver) {
+ i2c_unregister_device(client);
+ continue;
+ }
+ */
+
+ }
+
+ /* clean up the sysfs representation */
+ unregister_device(&adap->dev);
+
+ /* free bus id */
+ idr_remove(&i2c_adapter_idr, adap->nr);
+
+ dev_dbg("adapter [%s] unregistered\n", adap->name);
+
+out_unlock:
+ return res;
+}
+EXPORT_SYMBOL(i2c_del_adapter);
+/**
+ * @brief find the adapter for an id
+ * Also increase the adapter refcount
+ *
+ * @param id id to search
+ *
+ * @return adapter else NULL
+ */
+struct i2c_adapter *i2c_get_adapter(int id)
+{
+ struct i2c_adapter *adapter;
+ dbg_entry("id=%x", id);
+
+ adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+
+ return adapter;
+}
+EXPORT_SYMBOL(i2c_get_adapter);
+
+/**
+ * @brief return the usage of get_adapter -> reduce refcount
+ *
+ * @param adap adapter to return
+ *
+ * @return none
+ */
+void i2c_put_adapter(struct i2c_adapter *adap)
+{
+ dbg_entry("adap=%x", (u32) adap);
+ /* Empty function for the timebeing.. */
+}
+EXPORT_SYMBOL(i2c_put_adapter);
+
+/* ------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+/**
+ * @brief do i2c_transfer to an adapter
+ *
+ * @param adap adapter
+ * @param msgs the messages
+ * @param num number of messages
+ *
+ * @return result of transfer
+ */
+int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ int ret;
+
+ dbg_entry("adap=%x msg=%x num=%x", (u32) adap, (u32) msgs, num);
+ if (adap->algo->master_xfer) {
+#ifdef DEBUG
+ for (ret = 0; ret < num; ret++) {
+ dev_dbg("master_xfer[%d] %c, addr=0x%02x, "
+ "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+ ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+ (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+ }
+#endif
+
+ ret = adap->algo->master_xfer(adap, msgs, num);
+ return ret;
+ } else {
+ dev_dbg("I2C level transfers not supported\n");
+ return -ENOSYS;
+ }
+}
+EXPORT_SYMBOL(i2c_transfer);
+
+/**
+ * @brief send few bytes to a client
+ *
+ * @param client client to send data to
+ * @param buf buffer data
+ * @param count num bytes
+ *
+ * @return result of operation
+ */
+int i2c_master_send(struct i2c_client *client, const char *buf, int count)
+{
+ int ret;
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+
+ dbg_entry("client=%x buf=%x count=%x", (u32) client, (u32) buf,
+ (u32) count);
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (char *)buf;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_send);
+
+/**
+ * @brief read a few bytes from client
+ *
+ * @param client client
+ * @param buf buffer
+ * @param count num bytes to read
+ *
+ * @return result of operation
+ */
+int i2c_master_recv(struct i2c_client *client, char *buf, int count)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+ int ret;
+
+ dbg_entry("client=%x buf=%x count=%x", (u32) client, (u32) buf,
+ (u32) count);
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = buf;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_recv);
Index: u-boot-v2.git/drivers/i2c/Kconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/Kconfig 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,39 @@
+#
+# I2C subsystem configuration
+#
+
+menuconfig I2C
+ tristate "I2C support"
+ ---help---
+ I2C (pronounce: I-square-C) is a slow serial bus protocol used in
+ many micro controller applications and developed by Philips. SMBus,
+ or System Management Bus is a subset of the I2C protocol. More
+ information is contained in the directory <file:Documentation/i2c/>,
+ especially in the file called "summary" there.
+
+ If you want I2C support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below.
+
+ This I2C support can also be built as a module. If so, the module
+ will be called i2c-core.
+
+if I2C
+
+source drivers/i2c/busses/Kconfig
+
+config I2C_DEBUG_CORE
+ bool "I2C Core debugging messages"
+ help
+ Say Y here if you want the I2C core to produce a bunch of debug
+ messages to the system log. Select this if you are having a
+ problem with I2C support and want to see more of what is going on.
+
+config I2C_DEBUG_BUS
+ bool "I2C Bus debugging messages"
+ help
+ Say Y here if you want the I2C bus drivers to produce a bunch of
+ debug messages to the system log. Select this if you are having
+ a problem with I2C support and want to see more of what is going
+ on.
+
+endif # I2C
Index: u-boot-v2.git/drivers/i2c/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/Makefile 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,10 @@
+#
+# Makefile for the i2c core.
+#
+
+obj-$(CONFIG_I2C) += i2c-core.o
+obj-y += busses/
+
+ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
Index: u-boot-v2.git/drivers/i2c/busses/Kconfig
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/busses/Kconfig 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,7 @@
+#
+# Sensor device configuration
+#
+
+menu "I2C Hardware Bus support"
+
+endmenu
Index: u-boot-v2.git/drivers/i2c/busses/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/busses/Makefile 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,9 @@
+#
+# Makefile for the i2c bus drivers.
+#
+
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+
+ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
Index: u-boot-v2.git/drivers/i2c/i2c-core.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/i2c-core.h 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,37 @@
+/**
+ * @file
+ * @brief - interfaces internal to the I2C framework
+ *
+ * FileName: drivers/i2c/i2c-core.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __i2C_CORE_H
+#define __i2C_CORE_H
+
+/* board_lock protects board_list and first_dynamic_bus_num.
+ * only i2c core components are allowed to use these symbols.
+ */
+extern struct list_head __i2c_board_list;
+extern int __i2c_first_dynamic_bus_num;
+
+#endif /* __i2C_CORE_H */
Index: u-boot-v2.git/include/linux/i2c.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/i2c.h 2008-06-19 08:42:46.000000000 -0500
@@ -0,0 +1,299 @@
+/**
+ * @file
+ * @brief definitions for the i2c-bus interface
+ *
+ * FileName: include/linux/i2c.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/* Copyright (C) 1995-2000 Simon G. Vogl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Ky??sti M?$lkki <kmalkki@cc.hut.fi> and
+ Frodo Looijaard <frodol@dds.nl> */
+
+#ifndef _LINUX_I2C_H
+#define _LINUX_I2C_H
+
+#include <linux/types.h>
+#ifdef __U_BOOT__
+#include <module.h>
+#include <linux/mod_devicetable.h>
+#include <driver.h>
+
+/* --- General options ------------------------------------------------ */
+
+struct i2c_msg;
+struct i2c_algorithm;
+struct i2c_adapter;
+struct i2c_client;
+struct i2c_driver;
+
+/**
+ * The master routines are the ones normally used to transmit data to devices
+ * on a bus (or read from them). Apart from two basic transfer functions to
+ * transmit one message at a time, a more complex version can be used to
+ * transmit an arbitrary number of messages without interruption.
+ */
+extern int i2c_master_send(struct i2c_client *, const char *, int);
+extern int i2c_master_recv(struct i2c_client *, char *, int);
+
+/** Transfer num messages.
+ */
+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,\
+ int num);
+
+/**
+ * A driver is capable of handling one or more physical devices present on
+ * I2C adapters. This information is used to inform the driver of adapter
+ * events.
+ *
+ * The driver.owner field should be set to the module owner of this driver.
+ * The driver.name field should be set to the name of this driver.
+ *
+ * @warning: U-Boot V2 does not support legacy drivers as defined in Linux
+ * kernel
+ */
+struct i2c_driver {
+ int id;
+
+ /** Standard driver model interfaces, for "new style" i2c drivers.
+ * With the driver model, device enumeration is NEVER done by drivers;
+ * it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
+ */
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *);
+ int (*remove)(struct i2c_client *);
+
+ /** a ioctl like command that can be used to perform specific functions
+ * with the device.
+ */
+ int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
+
+ struct driver_d driver;
+ const struct i2c_device_id *id_table;
+};
+#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
+
+/**
+ * struct i2c_client - represent an I2C slave device
+ * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
+ * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
+ * @addr: Address used on the I2C bus connected to the parent adapter.
+ * @name: Indicates the type of the device, usually a chip name that's
+ * generic enough to hide second-sourcing and compatible revisions.
+ * @adapter: manages the bus segment hosting this I2C device
+ * @driver: device's driver, hence pointer to access routines
+ * @dev: Driver model device node for the slave.
+ * @irq: indicates the IRQ generated by this device (if any)
+ * @list: list of active/busy clients (DEPRECATED)
+ * @released: used to synchronize client releases & detaches and references
+ *
+ * An i2c_client identifies a single device (i.e. chip) connected to an
+ * i2c bus. The behaviour exposed to Linux is defined by the driver
+ * managing the device.
+ */
+struct i2c_client {
+ unsigned short flags; /* div., see below */
+ unsigned short addr; /* chip address - NOTE: 7bit */
+ /* addresses are stored in the */
+ /* _LOWER_ 7 bits */
+ char name[I2C_NAME_SIZE];
+ struct i2c_adapter *adapter; /* the adapter we sit on */
+ struct i2c_driver *driver; /* and our access routines */
+ struct device_d dev; /* the device structure */
+ int irq; /* irq issued by device (or -1) */
+ struct list_head list; /* DEPRECATED */
+};
+#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
+
+extern struct i2c_client *i2c_verify_client(struct device_d *dev);
+
+static inline void *i2c_get_clientdata(struct i2c_client *dev)
+{
+ return (&dev->dev)->platform_data;
+}
+
+static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
+{
+ (&dev->dev)->platform_data = data;
+}
+
+
+/**
+ * The following structs are for those who like to implement new bus drivers:
+ * i2c_algorithm is the interface to a class of hardware solutions which can
+ * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
+ * to name two of the most common.
+ */
+struct i2c_algorithm {
+ /** If an adapter algorithm can't do I2C-level access, set master_xfer
+ to NULL. If an adapter algorithm can do SMBus access, set
+ smbus_xfer. If set to NULL, the SMBus protocol is simulated
+ using common I2C messages */
+ /** master_xfer should return the number of messages successfully
+ processed, or a negative value on error */
+ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num);
+ /* To determine what the adapter supports */
+ u32 (*functionality) (struct i2c_adapter *);
+};
+
+/**
+ * i2c_adapter is the structure used to identify a physical i2c bus along
+ * with the access algorithms necessary to access it.
+ */
+struct i2c_adapter {
+ struct module *owner;
+ unsigned int id;
+ const struct i2c_algorithm *algo; /* the algorithm to access the bus */
+ void *algo_data;
+
+ /* --- administration stuff. */
+ int (*client_register)(struct i2c_client *);
+ int (*client_unregister)(struct i2c_client *);
+
+ int timeout;
+ int retries;
+ struct device_d dev; /* the adapter device */
+
+ int nr;
+ struct list_head clients; /* DEPRECATED */
+ char name[48];
+};
+#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
+
+static inline void *i2c_get_adapdata(struct i2c_adapter *dev)
+{
+ return (&dev->dev)->platform_data;
+}
+
+static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
+{
+ (&dev->dev)->platform_data = data;
+}
+
+/*flags for the client struct: */
+#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
+#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
+ /* Must equal I2C_M_TEN below */
+
+/* ----- functions exported by i2c.o */
+
+/* administration...
+ */
+extern int i2c_add_adapter(struct i2c_adapter *);
+extern int i2c_del_adapter(struct i2c_adapter *);
+extern int i2c_add_numbered_adapter(struct i2c_adapter *);
+
+extern struct i2c_adapter *i2c_get_adapter(int id);
+extern void i2c_put_adapter(struct i2c_adapter *adap);
+
+
+/** Return the functionality mask */
+static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
+{
+ return adap->algo->functionality(adap);
+}
+
+/** Return 1 if adapter supports everything we need, 0 if not. */
+static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
+{
+ return (func & i2c_get_functionality(adap)) == func;
+}
+
+/** Return id number for a specific adapter */
+static inline int i2c_adapter_id(struct i2c_adapter *adap)
+{
+ return adap->nr;
+}
+#endif /* __U_BOOT__ */
+
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ * @addr: Slave address, either seven or ten bits. When this is a ten
+ * bit address, I2C_M_TEN must be set in @flags and the adapter
+ * must support I2C_FUNC_10BIT_ADDR.
+ * @flags: I2C_M_RD is handled by all adapters. No other flags may be
+ * provided unless the adapter exported the relevant I2C_FUNC_*
+ * flags through i2c_check_functionality().
+ * @len: Number of data bytes in @buf being read from or written to the
+ * I2C slave address. For read transactions where I2C_M_RECV_LEN
+ * is set, the caller guarantees that this buffer can hold up to
+ * 32 bytes in addition to the initial length byte sent by the
+ * slave (plus, if used, the SMBus PEC); and this value will be
+ * incremented by the number of block data bytes received.
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction. It is visible to drivers in the @i2c_transfer() procedure,
+ * to userspace from i2c-dev, and to I2C adapter drivers through the
+ * @i2c_adapter. at master_xfer() method.
+ *
+ * Except when I2C "protocol mangling" is used, all I2C adapters implement
+ * the standard rules for I2C transactions. Each transaction begins with a
+ * START. That is followed by the slave address, and a bit encoding read
+ * versus write. Then follow all the data bytes, possibly including a byte
+ * with SMBus PEC. The transfer terminates with a NAK, or when all those
+ * bytes have been transferred and ACKed. If this is the last message in a
+ * group, it is followed by a STOP. Otherwise it is followed by the next
+ * @i2c_msg transaction segment, beginning with a (repeated) START.
+ *
+ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
+ * passing certain @flags may have changed those standard protocol behaviors.
+ * Those flags are only for use with broken/nonconforming slaves, and with
+ * adapters which are known to support the specific mangling options they
+ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
+ */
+struct i2c_msg {
+ __u16 addr; /* slave address */
+ __u16 flags;
+#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
+#define I2C_M_RD 0x0001 /* read data, from slave to master */
+#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
+#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
+ __u16 len; /* msg length */
+ __u8 *buf; /* pointer to msg data */
+};
+
+/** To determine what functionality is present */
+
+#define I2C_FUNC_I2C 0x00000001
+#define I2C_FUNC_10BIT_ADDR 0x00000002
+/** I2C_M_{REV_DIR_ADDR,NOSTART,..} */
+#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004
+
+
+/** SMBus transaction types (size parameter in the above functions)
+ Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
+#define I2C_SMBUS_QUICK 0
+#define I2C_SMBUS_BYTE 1
+#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS_WORD_DATA 3
+#define I2C_SMBUS_PROC_CALL 4
+#define I2C_SMBUS_BLOCK_DATA 5
+#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
+#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA 8
+
+#endif /* _LINUX_I2C_H */
Index: u-boot-v2.git/drivers/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/Kconfig 2008-06-19 08:40:01.000000000 -0500
+++ u-boot-v2.git/drivers/Kconfig 2008-06-19 08:42:46.000000000 -0500
@@ -3,6 +3,7 @@
source "drivers/serial/Kconfig"
source "drivers/net/Kconfig"
source "drivers/spi/Kconfig"
+source "drivers/i2c/Kconfig"
menu "flash drivers "
Index: u-boot-v2.git/drivers/Makefile
===================================================================
--- u-boot-v2.git.orig/drivers/Makefile 2008-06-19 08:40:01.000000000 -0500
+++ u-boot-v2.git/drivers/Makefile 2008-06-19 08:42:46.000000000 -0500
@@ -2,6 +2,7 @@
obj-y += serial/
obj-y += nand/
obj-$(CONFIG_SPI) += spi/
+obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_DRIVER_CFI_OLD) += cfi_flash.o
obj-$(CONFIG_DRIVER_CFI_NEW) += cfi_flash_new.o
obj-$(CONFIG_DRIVER_CFI_INTEL) += cfi_flash_intel.o
Index: u-boot-v2.git/include/driver.h
===================================================================
--- u-boot-v2.git.orig/include/driver.h 2008-06-19 08:40:00.000000000 -0500
+++ u-boot-v2.git/include/driver.h 2008-06-19 08:42:46.000000000 -0500
@@ -34,7 +34,9 @@
#define DEVICE_TYPE_BLOCK 4
#define DEVICE_TYPE_FS 5
#define DEVICE_TYPE_MIIPHY 6
-#define MAX_DEVICE_TYPE 6
+#define DEVICE_TYPE_I2C 7
+#define DEVICE_TYPE_I2CDEV 8
+#define MAX_DEVICE_TYPE 8
#include <param.h>
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 4/9]U-boot-V2:I2C: Introduce i2c-dev
2008-06-18 20:44 ` Robert Schwebel
` (4 preceding siblings ...)
2008-06-19 15:11 ` [U-Boot-Users] [Patch 3/9]U-boot-V2:I2C: Introduce core Menon, Nishanth
@ 2008-06-19 15:12 ` Menon, Nishanth
2008-06-19 15:12 ` [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands Menon, Nishanth
` (4 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:12 UTC (permalink / raw)
To: u-boot
I2C by default does not expose a device interface
for the adapters registering in the system. This
is usually not needed unless we need to debug
something. in which case, this is a handy little
layer when used in conjunction with the i2c
commands.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
drivers/i2c/Kconfig | 10 +
drivers/i2c/Makefile | 1
drivers/i2c/i2c-core.c | 12 +
drivers/i2c/i2c-core.h | 4
drivers/i2c/i2c-dev.c | 439 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-dev.h | 71 +++++++
6 files changed, 537 insertions(+)
Index: u-boot-v2.git/include/linux/i2c-dev.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/i2c-dev.h 2008-06-19 08:42:58.000000000 -0500
@@ -0,0 +1,71 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: include/linux/i2c-dev.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LINUX_I2C_DEV_H
+#define _LINUX_I2C_DEV_H
+
+#include <linux/types.h>
+
+/* /dev/i2c-X ioctl commands. The ioctl's parameter is always an
+ * unsigned long, except for:
+ * - I2C_FUNCS, takes pointer to an unsigned long
+ * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data
+ * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data
+ */
+#define I2C_RETRIES 0x0701 /* number of times a device address should
+ be polled when not acknowledging */
+#define I2C_TIMEOUT 0x0702 /* set timeout in jiffies - call with int */
+
+/* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
+ * are NOT supported! (due to code brokenness)
+ */
+#define I2C_SLAVE 0x0703 /* Use this slave address */
+#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it
+ is already in use by a driver! */
+#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
+
+#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */
+
+#define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */
+
+#define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */
+
+/* This is the structure as used in the I2C_RDWR ioctl call */
+struct i2c_rdwr_ioctl_data {
+ struct i2c_msg *msgs; /* pointers to i2c_msgs */
+ u32 nmsgs; /* number of i2c_msgs */
+};
+
+#define I2C_RDRW_IOCTL_MAX_MSGS 42
+
+#define I2C_DEV_NAME "i2cd"
+
+#endif /* _LINUX_I2C_DEV_H */
Index: u-boot-v2.git/drivers/i2c/i2c-dev.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/i2c-dev.c 2008-06-19 08:42:58.000000000 -0500
@@ -0,0 +1,439 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: drivers/i2c/i2c-dev.c
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+ But I have used so much of his original code and ideas that it seems
+ only fair to recognize him as co-author -- Frodo */
+
+/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
+
+#include <common.h>
+#include <errno.h>
+#include <list.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "i2c-core.h"
+
+#ifdef CONFIG_I2C_DEBUG_DEV
+#define DBG_MODULE_NAME "i2cdev"
+#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
+#define dev_warn(ARGS...) fprintf(stderr, ARGS);
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#else
+#define dev_dbg(ARGS...)
+#define dev_warn(ARGS...)
+#define dbg_entry(FORMAT, ARGS...)
+#define dbg_exit(FORMAT, ARGS...)
+#endif
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+static struct i2c_driver i2cdev_driver;
+
+/*
+ * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ * The list of i2c_dev structures is parallel to the i2c_adapter lists
+ * maintained by the driver model, and is updated using notifications
+ * delivered to the i2cdev_driver.
+ */
+struct i2c_dev {
+ struct list_head list;
+ struct i2c_adapter *adap;
+ struct device_d dev;
+};
+
+#define I2C_MINORS 256
+static LIST_HEAD(i2c_dev_list);
+
+static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+{
+ struct i2c_dev *i2c_dev;
+
+ dbg_entry("index=%x", index);
+
+ list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+ if (i2c_dev->adap->nr == index)
+ goto found;
+ }
+ i2c_dev = NULL;
+found:
+ return i2c_dev;
+}
+
+static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+{
+ struct i2c_dev *i2c_dev;
+ dbg_entry("adap=%x", (u32) adap);
+
+ if (adap->nr >= I2C_MINORS) {
+ dev_err("i2c-dev: Out of device minors (%d)\n", adap->nr);
+ return NULL;
+ }
+
+ i2c_dev = calloc(1, sizeof(*i2c_dev));
+ if (!i2c_dev)
+ return NULL;
+ i2c_dev->adap = adap;
+
+ list_add_tail(&i2c_dev->list, &i2c_dev_list);
+ return i2c_dev;
+}
+
+static void return_i2c_dev(struct i2c_dev *i2c_dev)
+{
+ dbg_entry("i2c_dev=%x", (u32) i2c_dev);
+ list_del(&i2c_dev->list);
+ free(i2c_dev);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * After opening an instance of this character special file, a file
+ * descriptor starts out associated only with an i2c_adapter (and bus).
+ *
+ * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
+ * traffic to any devices on the bus used by that adapter. That's because
+ * the i2c_msg vectors embed all the addressing information they need, and
+ * are submitted directly to an i2c_adapter. However, SMBus-only adapters
+ * don't support that interface.
+ *
+ * To use read()/write() system calls on that file descriptor, or to use
+ * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
+ * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous
+ * (never registered) i2c_client so it holds the addressing information
+ * needed by those system calls and by this SMBus interface.
+ */
+
+static ssize_t i2cdev_read(struct device_d *dev, void *buffer, size_t count,
+ ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+ return i2c_master_recv(client, buffer, count);
+}
+
+static ssize_t i2cdev_write(struct device_d *dev, const void *buffer,
+ size_t count, ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+ return i2c_master_send(client, buffer, count);
+}
+
+static int i2cdev_check(struct device_d *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+
+ dbg_entry("dev=%x addrp=%x", (u32) dev, (u32) addrp);
+ if (!client || client->addr != *(unsigned int *)addrp)
+ return 0;
+
+ return dev->driver ? -EBUSY : 0;
+}
+
+/* This address checking function differs from the one in i2c-core
+ in that it considers an address with a registered device, but no
+ driver bound to it, as NOT busy. */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+ int ret = 0;
+ struct device_d *child;
+ dbg_entry("adapter=%x addr=%x", (u32) adapter, (u32) addr);
+ device_for_each_child((&(adapter->dev)), child) {
+ ret = i2cdev_check(child, &addr);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int i2cdev_ioctl_rdrw(struct i2c_client *client, unsigned long arg)
+{
+ struct i2c_rdwr_ioctl_data rdwr_arg;
+ struct i2c_msg *rdwr_pa;
+ u8 **data_ptrs;
+ int i, res;
+
+ dbg_entry("client=%x arg=%x", (u32) client, (u32) arg);
+ memcpy(&rdwr_arg, (struct i2c_rdwr_ioctl_data *)arg, sizeof(rdwr_arg));
+
+ /* Put an arbitrary limit on the number of messages that can
+ * be sent at once */
+ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+ return -EINVAL;
+
+ rdwr_pa = (struct i2c_msg *)
+ malloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+ if (!rdwr_pa)
+ return -ENOMEM;
+
+ memcpy(rdwr_pa, rdwr_arg.msgs, rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+
+ data_ptrs = malloc(rdwr_arg.nmsgs * sizeof(u8 *));
+ if (data_ptrs == NULL) {
+ free(rdwr_pa);
+ return -ENOMEM;
+ }
+
+ res = 0;
+ for (i = 0; i < rdwr_arg.nmsgs; i++) {
+ /* Limit the size of the message to a sane amount;
+ * and don't let length change either. */
+ if ((rdwr_pa[i].len > 8192) ||
+ (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+ res = -EINVAL;
+ break;
+ }
+ data_ptrs[i] = (u8 *) rdwr_pa[i].buf;
+ rdwr_pa[i].buf = malloc(rdwr_pa[i].len);
+ if (rdwr_pa[i].buf == NULL) {
+ res = -ENOMEM;
+ break;
+ }
+ memcpy(rdwr_pa[i].buf, data_ptrs[i], rdwr_pa[i].len);
+ }
+ if (res < 0) {
+ int j;
+ for (j = 0; j < i; ++j)
+ free(rdwr_pa[j].buf);
+ free(data_ptrs);
+ free(rdwr_pa);
+ return res;
+ }
+
+ res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+ while (i-- > 0) {
+ if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD))
+ memcpy(data_ptrs[i], rdwr_pa[i].buf, rdwr_pa[i].len);
+ free(rdwr_pa[i].buf);
+ }
+ free(data_ptrs);
+ free(rdwr_pa);
+ return res;
+}
+
+
+static int i2cdev_ioctl(struct device_d *dev, int cmd, void *argument)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ unsigned long funcs;
+ unsigned long arg = (unsigned long)argument;
+
+ dbg_entry("dev=%x cmd=%x arg=%x", (u32) dev, (u32) cmd, (u32) arg);
+ dev_dbg("ioctl, cmd=0x%02x, arg=0x%04x\n", cmd, arg);
+
+ switch (cmd) {
+ case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
+ if ((arg > 0x3ff) ||
+ (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+ return -EINVAL;
+ if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
+ return -EBUSY;
+ /* REVISIT: address could become busy later */
+ client->addr = arg;
+ return 0;
+ case I2C_TENBIT:
+ if (arg)
+ client->flags |= I2C_M_TEN;
+ else
+ client->flags &= ~I2C_M_TEN;
+ return 0;
+ case I2C_PEC:
+ if (arg)
+ client->flags |= I2C_CLIENT_PEC;
+ else
+ client->flags &= ~I2C_CLIENT_PEC;
+ return 0;
+ case I2C_FUNCS:
+ funcs = i2c_get_functionality(client->adapter);
+ if (!arg)
+ return -ENOMEM;
+
+ *((unsigned long *)arg) = funcs;
+ return 0;
+
+ case I2C_RDWR:
+ return i2cdev_ioctl_rdrw(client, arg);
+
+ case I2C_RETRIES:
+ client->adapter->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ client->adapter->timeout = arg;
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int i2cdev_open(struct device_d *dev, struct filep *file)
+{
+ struct i2c_client *client;
+ struct i2c_adapter *adap;
+ struct i2c_dev *i2c_dev;
+
+ dbg_entry("dev=%x file=%x", (u32) dev, (u32) file);
+ i2c_dev = i2c_dev_get_by_minor(dev->map_base);
+ if (!i2c_dev)
+ return -ENODEV;
+
+ adap = i2c_get_adapter(i2c_dev->adap->nr);
+ if (!adap)
+ return -ENODEV;
+
+ /* This creates an anonymous i2c_client, which may later be
+ * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
+ *
+ * This client is ** NEVER REGISTERED ** with the driver model
+ * or I2C core code!! It just holds private copies of addressing
+ * information and maybe a PEC flag.
+ */
+ client = calloc(1, sizeof(*client));
+ if (!client) {
+ i2c_put_adapter(adap);
+ return -ENOMEM;
+ }
+ sprintf(client->name, "i2c-dev %d", adap->nr);
+ client->driver = &i2cdev_driver;
+
+ client->adapter = adap;
+ dev->priv = client;
+
+ return 0;
+}
+
+static int i2cdev_release(struct device_d *dev, struct filep *file)
+{
+ struct i2c_client *client = dev->priv;
+
+ dbg_entry("dev=%x file=%x", (u32) dev, (u32) file);
+ i2c_put_adapter(client->adapter);
+ free(client);
+ dev->priv = NULL;
+
+ return 0;
+}
+
+static struct driver_d i2cdev_fops = {
+ .name = I2C_DEV_NAME,
+ .read = i2cdev_read,
+ .probe = dummy_probe,
+ .write = i2cdev_write,
+ .ioctl = i2cdev_ioctl,
+ .open = i2cdev_open,
+ .close = i2cdev_release,
+ .type = DEVICE_TYPE_I2CDEV,
+};
+
+static int i2c_dev_init(void)
+{
+
+ int res = 0;
+ dbg_entry("%s", "none");
+ res = register_driver(&i2cdev_fops);
+ dbg_exit("res=%d", res);
+ return res;
+}
+
+device_initcall(i2c_dev_init);
+
+/* ------------------------------------------------------------------------- */
+
+int i2cdev_attach_adapter(struct i2c_adapter *adap)
+{
+ struct device_d *dev;
+ struct i2c_dev *i2c_dev;
+ int res;
+ dbg_entry("adap=%x", (u32) adap);
+ i2c_dev = get_free_i2c_dev(adap);
+ if (!i2c_dev) {
+ dev_err("Did not get free dev-adap %d\n", adap->nr);
+ return -ENOMEM;
+ }
+ dev = &i2c_dev->dev;
+ /* Store my adapter number in mapbase for retrieval */
+ dev->map_base = adap->nr;
+ /* my i2cdev type */
+ sprintf((char *)&dev->name, "%s", I2C_DEV_NAME);
+ sprintf((char *)&dev->id, "%s%d", I2C_DEV_NAME, adap->nr);
+ dev->type = DEVICE_TYPE_I2CDEV;
+
+ res = register_device(dev);
+ if (res < 0) {
+ dev_err("Device %d registration failed %d\n", adap->nr, res);
+ perror(dev->id);
+ return_i2c_dev(i2c_dev);
+ return res;
+ }
+ return res;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
+
+int i2cdev_detach_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_dev *i2c_dev;
+ int ret = 0;
+ dbg_entry("adap=%x", (u32) adap);
+ i2c_dev = i2c_dev_get_by_minor(adap->nr);
+ if (!i2c_dev) {
+ dev_err("not registered adapter %d with me!\n", adap->nr);
+ return -ENODEV;
+ }
+ ret = unregister_device(&(i2c_dev->dev));
+ if (ret) {
+ dev_err("Adapter %d dev is in use(%d)?\n", adap->nr, ret);
+ return ret;
+ }
+ if (i2c_dev)
+ return_i2c_dev(i2c_dev);
+ return ret;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
Index: u-boot-v2.git/drivers/i2c/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Kconfig 2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Kconfig 2008-06-19 08:42:58.000000000 -0500
@@ -19,6 +19,16 @@
if I2C
+config I2C_CHARDEV
+ tristate "I2C device interface"
+ help
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have applications
+ to use the I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-dev.
+
source drivers/i2c/busses/Kconfig
config I2C_DEBUG_CORE
Index: u-boot-v2.git/drivers/i2c/Makefile
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Makefile 2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Makefile 2008-06-19 08:42:58.000000000 -0500
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
Index: u-boot-v2.git/drivers/i2c/i2c-core.c
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.c 2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.c 2008-06-19 08:42:58.000000000 -0500
@@ -102,6 +102,10 @@
dev_dbg("adapter [%s] registered\n", adap->name);
+#ifdef CONFIG_I2C_CHARDEV
+ i2cdev_attach_adapter(adap);
+#endif
+
out_unlock:
return res;
@@ -222,6 +226,14 @@
goto out_unlock;
}
+#ifdef CONFIG_I2C_CHARDEV
+ res = i2cdev_detach_adapter(adap);
+ if (res) {
+ dev_err("adapter in use\n");
+ goto out_unlock;
+ }
+#endif
+
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
Index: u-boot-v2.git/drivers/i2c/i2c-core.h
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.h 2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.h 2008-06-19 08:42:58.000000000 -0500
@@ -34,4 +34,8 @@
extern struct list_head __i2c_board_list;
extern int __i2c_first_dynamic_bus_num;
+/* Automatically called by i2c-Core..*/
+int i2cdev_attach_adapter(struct i2c_adapter *adap);
+int i2cdev_detach_adapter(struct i2c_adapter *adap);
+
#endif /* __i2C_CORE_H */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-18 20:44 ` Robert Schwebel
` (5 preceding siblings ...)
2008-06-19 15:12 ` [U-Boot-Users] [Patch 4/9]U-boot-V2:I2C: Introduce i2c-dev Menon, Nishanth
@ 2008-06-19 15:12 ` Menon, Nishanth
2008-06-19 20:33 ` Wolfgang Denk
2008-06-20 10:28 ` Sascha Hauer
2008-06-19 15:12 ` [U-Boot-Users] [Patch 6/9]U-boot-V2:cmd: I2C commands support Menon, Nishanth
` (3 subsequent siblings)
10 siblings, 2 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:12 UTC (permalink / raw)
To: u-boot
Introduce I2c commands from i2c-tools.
This allows for Diagnostics capability.
Supports ONLY i2c busses at the moment.
This code is based on
http://www.lm-sensors.org/wiki/I2CTools
This closely follows the functionality, options
and man page documentation
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
commands/i2c.c | 1268 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1268 insertions(+)
Index: u-boot-v2.git/commands/i2c.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/commands/i2c.c 2008-06-19 09:31:37.000000000 -0500
@@ -0,0 +1,1268 @@
+/**
+ * @file
+ * @brief I2C related applications
+ *
+ * FileName: commands/i2c.c
+ * This provides i2cdump, i2cdetect, i2cset and i2cget appplications
+ * The code originates from the i2c-tools located here:
+ * http://www.lm-sensors.org/wiki/I2CTools
+ *
+ * This file merges the userspace headers and applications to a single
+ * entity as we do not maintain a userspace/kernel space isolation
+ *
+ * NOTE: 10-bit addresses are NOT supported!
+ */
+/*
+ * (C) Copyright 2006-2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This application is based on the following:
+ *
+ * i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
+ * Part of user-space programs to access for I2C
+ * devices.
+ * Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
+ * i2cdump.c - a user-space program to dump I2C registers
+ * Copyright (C) 2002-2003 Frodo Looijaard <frodol@dds.nl>, and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
+ * i2cget.c - A user-space program to read an I2C register.
+ * Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
+ * i2cset.c - A user-space program to write an I2C register.
+ * Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <types.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <fs.h>
+#include <errno.h>
+#include <linux/stat.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include "i2c.h"
+
+#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n"
+
+/*************** Lib Functions *************/
+
+/**
+ * @brief Parse an I2CBUS command line argument
+ *
+ * @param i2cbus_arg arg to busparam
+ *
+ * @return the corresponding bus number,
+ * or a negative value if the bus is invalid.
+ */
+int lookup_i2c_bus(const char *i2cbus_arg)
+{
+ long i2cbus;
+ char *end;
+
+ if (i2cbus_arg == NULL) {
+ fprintf(stderr, "no bus arg! expect 0-9\n");
+ return -1;
+ }
+ if (strlen(i2cbus_arg) > 2) {
+ fprintf(stderr, "bad bus arg! expect 0-9 saw %s\n", i2cbus_arg);
+ return -2;
+ }
+ i2cbus = simple_strtol(i2cbus_arg, &end, 0);
+ if ((*i2cbus_arg != '0') && (i2cbus == 0)) {
+ fprintf(stderr, "bad bus arg! expect 0-9, saw %s\n",
+ i2cbus_arg);
+ return -2;
+ }
+ if (i2cbus < 0 || i2cbus > 0xff) {
+ fprintf(stderr, "Error: I2C bus out of range (0-255)!\n");
+ return -3;
+ }
+
+ return i2cbus;
+}
+
+/**
+ * @brief open a given i2cdevice
+ *
+ * @param i2cbus bus index
+ * @param filename return the devfs filename for the bus
+ * @param quiet be silent?
+ *
+ * @return return value of open
+ */
+int open_i2c_dev(const int i2cbus, char *filename, const int quiet)
+{
+ int file;
+
+ sprintf(filename, "/dev/" I2C_DEV_NAME "%d", i2cbus);
+ file = open(filename, O_RDWR);
+
+ if (file < 0 && !quiet) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not open file "
+ "`%s'\n", filename);
+ }
+
+ return file;
+}
+
+/**
+ * @brief Parse a CHIP-ADDRESS command line argument
+ *
+ * @param address_arg -user provided argument
+ *
+ * @return The corresponding chip address,
+ * or a negative value if the address is invalid.
+ */
+int parse_i2c_address(const char *address_arg)
+{
+ long address;
+ char *end;
+
+ address = simple_strtol(address_arg, &end, 0);
+ if (*end || !*address_arg) {
+ fprintf(stderr, "Error: Chip address is not a number!\n");
+ return -1;
+ }
+ if (address < 0x03 || address > 0x77) {
+ fprintf(stderr, "Error: Chip address out of range "
+ "(0x03-0x77)!\n");
+ return -2;
+ }
+
+ return address;
+}
+
+/**
+ * @brief force the slave address
+ *
+ * @param file file id
+ * @param address address to set
+ * @param force force address
+ *
+ * @return returns result of ioctl
+ */
+int set_slave_addr(int file, int address, int force)
+{
+ /* With force, let the user read from/write to the registers
+ even when a driver is also running */
+ if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, (void *)address) <
+ 0) {
+ perror(NULL);
+ fprintf(stderr,
+ "Error: Could not set address to 0x%02x\n", address);
+ return -errno;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief check functionality of the adapter
+ *
+ * @param file file index
+ * @param size size of the same
+ * @param daddress device address
+ * @param pec pec
+ *
+ * @return result of ioctl check negative if failed
+ */
+int check_funcs(int file, int size, int daddress, int pec)
+{
+ unsigned long funcs;
+
+ /* check adapter functionality */
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+ perror(NULL);
+ fprintf(stderr, "Error: Could not get the adapter "
+ "functionality matrix\n");
+ return -1;
+ }
+
+ if (!(funcs & I2C_FUNC_I2C)) {
+ fprintf(stderr, MISSING_FUNC_FMT, "I2C support");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int read_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
+ size_t count)
+{
+ struct i2c_msg msg[2] = {
+ {daddr, 0, reg_width, (u8 *) &addr},
+ {daddr, 0 | I2C_M_RD, count, buffer}
+ };
+ struct i2c_rdwr_ioctl_data data = {
+ .msgs = msg,
+ .nmsgs = 2,
+ };
+ return ioctl(file, I2C_RDWR, &data);
+}
+
+int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
+ size_t count)
+{
+ unsigned char *temp_buf;
+ struct i2c_msg msg = { daddr, 0, count + reg_width, NULL };
+ struct i2c_rdwr_ioctl_data data = {
+ .msgs = &msg,
+ .nmsgs = 1,
+ };
+ int ret;
+ temp_buf = malloc(count + reg_width);
+ if (temp_buf == NULL)
+ return -ENOMEM;
+ memcpy(temp_buf, &addr, reg_width);
+ memcpy(temp_buf + reg_width, buffer, count);
+ msg.buf = temp_buf;
+ ret = ioctl(file, I2C_RDWR, &data);
+ free(temp_buf);
+ return ret;
+}
+
+/****************** Test implementations **************/
+#ifdef CONFIG_CMD_I2C_DETECT
+
+#define MODE_AUTO 0
+#define MODE_QUICK 1
+#define MODE_READ 2
+#define MODE_FUNC 3
+
+static const __maybe_unused char cmd_i2cdetect_help_s[] =
+ "Usage:\n"
+ "a) i2cdetect [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
+ "Where:\n"
+ " -a : all addresses (default scans from 0x03 - 0x77)\n"
+ " -q : use write-risky at times\n"
+ " -r : use read-risky@times\n"
+ " If provided, FIRST and LAST limit the probing range.\n"
+ "b) i2cdetect -F I2CBUS\n"
+ "Where:\n"
+ " -F : Show functionality of the device\n"
+ "\n"
+ "I2CBUS is an integer representing the bus index\n"
+ "these are present as 'xx' of /dev/" I2C_DEV_NAME
+ "xx\n" "WARN:\n"
+ "This program can confuse your I2C bus, cause data loss and worse!\n";
+
+#ifdef CONFIG_LONGHELP
+static void cmd_i2cdetect_help(void)
+{
+ fprintf(stderr, "%s", cmd_i2cdetect_help_s);
+}
+#else
+#define cmd_i2cdetect_help()
+#endif
+
+/**
+ * @brief scan the i2c bus
+ *
+ * @param file file index
+ * @param mode what mode to scan it with
+ * @param first start address
+ * @param last end address
+ *
+ * @return negative if scan failed, else return 0
+ */
+static int scan_i2c_bus(int file, int mode, int first, int last)
+{
+ int i, j;
+ int res;
+ unsigned char dummy = 0x0;
+
+ printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
+
+ for (i = 0; i < 128; i += 16) {
+ printf("%02x: ", i);
+ for (j = 0; j < 16; j++) {
+
+ /* Skip unwanted addresses */
+ if (i + j < first || i + j > last) {
+ printf(" ");
+ continue;
+ }
+
+ /* Set slave address */
+ if (ioctl(file, I2C_SLAVE, (void *)(i + j)) < 0) {
+ if (errno == EBUSY) {
+ printf("UU ");
+ continue;
+ } else {
+ perror(NULL);
+ fprintf(stderr, "Error: Could not set "
+ "address to 0x%02x\n", i + j);
+ return -1;
+ }
+ }
+
+ /* Probe this address */
+ switch (mode) {
+ case MODE_QUICK:
+ /* Attempt a 0 byte write -can lock up many
+ * devices */
+ res = write_i2c(file, i + j, 0x0, 1, NULL, 0);
+ break;
+ case MODE_READ:
+ /* This is known to lock on various
+ write-only chips (mainly clock chips) */
+ res = read_i2c(file, i + j, 0x0, 1, &dummy, 1);
+ break;
+ default:
+ if ((i + j >= 0x30 && i + j <= 0x37)
+ || (i + j >= 0x50 && i + j <= 0x5F))
+ res =
+ read_i2c(file, i + j, 0x0, 1,
+ &dummy, 1);
+ else
+ res =
+ write_i2c(file, i + j, 0x0, 1, NULL,
+ 0);
+ }
+
+ if (res < 0)
+ printf("-- ");
+ else
+ printf("%02x ", i + j);
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+struct func {
+ long value;
+ const char *name;
+};
+
+static const struct func all_func[] = {
+ {.value = I2C_FUNC_I2C,
+ .name = "I2C"},
+ {.value = 0,
+ .name = ""}
+};
+
+/**
+ * @brief print the functionality of the adapter
+ *
+ * @param funcs the ioctl returned value
+ *
+ * @return none
+ */
+static void print_functionality(unsigned long funcs)
+{
+ int i;
+ for (i = 0; all_func[i].value; i++) {
+ printf("%-32s %s\n", all_func[i].name,
+ (funcs & all_func[i].value) ? "yes" : "no");
+ }
+}
+
+static int do_cmd_i2c_detect(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *end;
+ int i2cbus, file = 0, res = 0;
+ char filename[PATH_MAX];
+ unsigned long funcs;
+ int mode = MODE_AUTO;
+ int first = 0x03, last = 0x77;
+ int flags = 0;
+
+ /* handle (optional) flags first */
+ while (1 + flags < argc && argv[1 + flags][0] == '-') {
+ switch (argv[1 + flags][1]) {
+ case 'F':
+ if (mode != MODE_AUTO && mode != MODE_FUNC) {
+ fprintf(stderr, "Error: Different modes "
+ "specified!\n");
+ goto quit_i2cdetect;
+ }
+ mode = MODE_FUNC;
+ break;
+ case 'r':
+ if (mode == MODE_QUICK) {
+ fprintf(stderr, "Error: Different modes "
+ "specified!\n");
+ goto quit_i2cdetect;
+ }
+ mode = MODE_READ;
+ break;
+ case 'q':
+ if (mode == MODE_READ) {
+ fprintf(stderr, "Error: Different modes "
+ "specified!\n");
+ goto quit_i2cdetect;
+ }
+ mode = MODE_QUICK;
+ break;
+ case 'a':
+ first = 0x00;
+ last = 0x7F;
+ break;
+ default:
+ fprintf(stderr, "Error: Unsupported option "
+ "\"%s\"!\n", argv[1 + flags]);
+ goto quit_i2cdetect;
+ }
+ flags++;
+ }
+
+ if (argc < flags + 2) {
+ fprintf(stderr, "Error: No i2c-bus specified!\n");
+ goto quit_i2cdetect;
+ }
+ i2cbus = lookup_i2c_bus(argv[flags + 1]);
+ if (i2cbus < 0) {
+ fprintf(stderr, "Error: bus not found!\n");
+ goto quit_i2cdetect;
+ }
+
+ /* read address range if present */
+ if (argc == flags + 4 && mode != MODE_FUNC) {
+ int tmp;
+
+ tmp = simple_strtol(argv[flags + 2], &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error: FIRST argment not a "
+ "number!\n");
+ goto quit_i2cdetect;
+ }
+ if (tmp < first || tmp > last) {
+ fprintf(stderr, "Error: FIRST argument out of range "
+ "(0x%02x-0x%02x)!\n", first, last);
+ goto quit_i2cdetect;
+ }
+ first = tmp;
+
+ tmp = simple_strtol(argv[flags + 3], &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error: LAST argment not a "
+ "number!\n");
+ goto quit_i2cdetect;
+ }
+ if (tmp < first || tmp > last) {
+ fprintf(stderr, "Error: LAST argument out of range "
+ "(0x%02x-0x%02x)!\n", first, last);
+ goto quit_i2cdetect;
+ }
+ last = tmp;
+ } else if (argc != flags + 2) {
+ goto quit_i2cdetect;
+ }
+
+ file = open_i2c_dev(i2cbus, filename, 0);
+ if (file < 0)
+ return 1;
+
+ res = 1;
+ if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not get the adapter "
+ "functionality matrix\n");
+ goto ret;
+ }
+
+ /* Special case, we only list the implemented functionalities */
+ if (mode == MODE_FUNC) {
+ printf("Functionalities implemented by %s:\n", filename);
+ print_functionality(funcs);
+ res = 0;
+ goto ret;
+ }
+
+ res = scan_i2c_bus(file, mode, first, last);
+ret:
+ if (file >= 0)
+ close(file);
+ return res ? 1 : 0;
+
+quit_i2cdetect:
+ /* Exit after printing help */
+ cmd_i2cdetect_help();
+ goto ret;
+}
+
+U_BOOT_CMD_START(i2cdetect)
+ .maxargs = 6,
+ .cmd = do_cmd_i2c_detect,
+ .usage = "program to scan for I2C devices",
+ U_BOOT_CMD_HELP(cmd_i2cdetect_help_s)
+U_BOOT_CMD_END
+#endif /* CONFIG_CMD_I2C_DETECT */
+
+#ifdef CONFIG_CMD_I2C_DUMP
+static const __maybe_unused char cmd_i2cdump_help_s[] =
+ "Usage: i2cdump [-f] [-r first-last] I2CBUS ADDRESS [MODE]\n"
+ "Where:\n"
+ " -f : Force set the slave address\n"
+ " -r : first-last the range of addresses which will be dumped\n"
+ "I2CBUS is an integer representing the bus index\n"
+ " these are present as 'xx' of /dev/" I2C_DEV_NAME "xx\n"
+ "ADDRESS is an integer representing device address (0x03 - 0x77)\n"
+ "MODE is one of:\n"
+ " b (byte, default)\n"
+ " w (word)\n"
+ " W (word on even register addresses)\n"
+ " Append p for PEC\n"
+ "WARN: i2cdump can be dangerous if used improperly.\n";
+
+#ifdef CONFIG_LONGHELP
+static const __maybe_unused char cmd_i2c_ext_help_s[] =
+ "Most notably, the c mode "
+ "starts with WRITING a byte to the chip. On most chips it will be stored\n"
+ "in the address pointer register, which is OK, but some chips with a\n"
+ "single register or no (visible)register at all will most likely see this\n"
+ "as a real WRITE, resulting in possible misbehavior or corruption. Do not\n"
+ "use i2cdump on random addresses. Anyway, it is of little use unless you\n"
+ "have good knowledge of the chip you??(tm)re working with and an idea of \n"
+ "what you are looking for.\n";
+static void cmd_i2dump_help(void)
+{
+ fprintf(stderr, "%s", cmd_i2cdump_help_s);
+ fprintf(stderr, "%s", cmd_i2c_ext_help_s);
+}
+#else
+#define cmd_i2dump_help()
+#endif
+
+static int do_cmd_i2c_dump(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *end;
+ int i, j, res, i2cbus, address, size, file = -1;
+ char filename[PATH_MAX];
+ int block[256];
+ int pec = 0, even = 0;
+ int flags = 0;
+ int force = 0;
+ const char *range = NULL;
+ int first = 0x00, last = 0xff;
+
+ /* handle (optional) flags first */
+ while (1 + flags < argc && argv[1 + flags][0] == '-') {
+ switch (argv[1 + flags][1]) {
+ case 'f':
+ force = 1;
+ break;
+ case 'r':
+ range = argv[1 + (++flags)];
+ break;
+ default:
+ fprintf(stderr, "Error: Unsupported option "
+ "\"%s\"!\n", argv[1 + flags]);
+ goto quit_i2cdump;
+ }
+ flags++;
+ }
+
+ if (argc < flags + 2) {
+ fprintf(stderr, "Error: No i2c-bus specified!\n");
+ goto quit_i2cdump;
+ }
+ i2cbus = lookup_i2c_bus(argv[flags + 1]);
+ if (i2cbus < 0) {
+ fprintf(stderr, "Error: Bus not found!\n");
+ goto quit_i2cdump;
+ }
+
+ if (argc < flags + 3) {
+ fprintf(stderr, "Error: No address specified!\n");
+ goto quit_i2cdump;
+ }
+ address = parse_i2c_address(argv[flags + 2]);
+ if (address < 0) {
+ fprintf(stderr, "Error: Badd address\n");
+ goto quit_i2cdump;
+ }
+
+ if (argc < flags + 4) {
+ fprintf(stderr, "No size specified (using byte-data access)\n");
+ size = I2C_SMBUS_BYTE_DATA;
+ } else if (!strncmp(argv[flags + 3], "b", 1)) {
+ size = I2C_SMBUS_BYTE_DATA;
+ pec = argv[flags + 3][1] == 'p';
+ } else if (!strncmp(argv[flags + 3], "w", 1)) {
+ size = I2C_SMBUS_WORD_DATA;
+ pec = argv[flags + 3][1] == 'p';
+ } else if (!strncmp(argv[flags + 3], "W", 1)) {
+ size = I2C_SMBUS_WORD_DATA;
+ even = 1;
+ } else {
+ fprintf(stderr, "Error: Invalid mode!\n");
+ goto quit_i2cdump;
+ }
+
+ /* Parse optional range string */
+ if (range) {
+ char *dash;
+
+ first = simple_strtol(range, &dash, 0);
+ if ((dash == range) || (*dash != '-') || (first < 0) ||
+ (first > 0xff)) {
+ fprintf(stderr, "Error: Invalid range parameter!\n");
+ goto quit_i2cdump;
+ }
+ last = simple_strtol(++dash, &end, 0);
+ if ((end == dash) || (*end != '\0') || (last < first) ||
+ (last > 0xff)) {
+ fprintf(stderr, "Error: Invalid range parameter!\n");
+ goto quit_i2cdump;
+ }
+
+ /* Check mode constraints */
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (!even || (!(first % 2) && last % 2))
+ break;
+ /* Fall through */
+ default:
+ fprintf(stderr,
+ "Error: Range parameter not compatible"
+ "with selected mode!\n");
+ goto quit_i2cdump;
+ }
+ }
+
+ file = open_i2c_dev(i2cbus, filename, 0);
+ if (file < 0 || check_funcs(file, size, address, pec)
+ || set_slave_addr(file, address, force))
+ goto quit_i2cdump;
+
+ if (pec) {
+ if (ioctl(file, I2C_PEC, (void *)1) < 0) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not set PEC\n");
+ goto quit_i2cdump;
+ }
+ }
+
+ /* handle all but word data */
+ if (size != I2C_SMBUS_WORD_DATA || even) {
+ printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
+ " 0123456789abcdef\n");
+ for (i = 0; i < 256; i += 16) {
+ if (i / 16 < first / 16)
+ continue;
+ if (i / 16 > last / 16)
+ break;
+
+ printf("%02x: ", i);
+ for (j = 0; j < 16; j++) {
+ /* Skip unwanted registers */
+ if (i + j < first || i + j > last) {
+ printf(" ");
+ if (size == I2C_SMBUS_WORD_DATA) {
+ printf(" ");
+ j++;
+ }
+ continue;
+ }
+
+ if (size == I2C_SMBUS_BYTE_DATA) {
+ u8 buf;
+ res =
+ read_i2c(file, address, i + j, 1,
+ &buf, 1);
+ block[i + j] = buf;
+
+ } else if (size == I2C_SMBUS_WORD_DATA) {
+ u8 buf[2];
+ res =
+ read_i2c(file, address, i + j,
+ (even) ? 2 : 1, buf, 2);
+ if (res < 0) {
+ block[i + j] = res;
+ block[i + j + 1] = res;
+ } else {
+ block[i + j] = buf[0];
+ block[i + j + 1] = buf[1];
+ }
+ } else
+ res = block[i + j];
+
+ if (res < 0) {
+ printf("XX ");
+ if (size == I2C_SMBUS_WORD_DATA)
+ printf("XX ");
+ } else {
+ printf("%02x ", block[i + j]);
+ if (size == I2C_SMBUS_WORD_DATA)
+ printf("%02x ",
+ block[i + j + 1]);
+ }
+ if (size == I2C_SMBUS_WORD_DATA)
+ j++;
+ }
+ printf(" ");
+
+ for (j = 0; j < 16; j++) {
+ /* Skip unwanted registers */
+ if (i + j < first || i + j > last) {
+ printf(" ");
+ continue;
+ }
+
+ res = block[i + j];
+ if (res < 0)
+ printf("X");
+ else if ((res & 0xff) == 0x00
+ || (res & 0xff) == 0xff)
+ printf(".");
+ else if ((res & 0xff) < 32
+ || (res & 0xff) >= 127)
+ printf("?");
+ else
+ printf("%c", res & 0xff);
+ }
+ printf("\n");
+ }
+ } else {
+ printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n");
+ for (i = 0; i < 256; i += 8) {
+ if (i / 8 < first / 8)
+ continue;
+ if (i / 8 > last / 8)
+ break;
+
+ printf("%02x: ", i);
+ for (j = 0; j < 8; j++) {
+ u16 buf;
+ /* Skip unwanted registers */
+ if (i + j < first || i + j > last) {
+ printf(" ");
+ continue;
+ }
+
+ res =
+ read_i2c(file, address, i + j, 1,
+ (u8 *) &buf, 2);
+ if (res < 0)
+ printf("XXXX ");
+ else
+ printf("%04x ", buf & 0xffff);
+ }
+ printf("\n");
+ }
+ }
+ return 0;
+
+quit_i2cdump:
+ /* Quit after providing help info */
+ cmd_i2dump_help();
+ if (file >= 0)
+ close(file);
+ return 1;
+}
+
+U_BOOT_CMD_START(i2cdump)
+ .maxargs = 8,
+ .cmd = do_cmd_i2c_dump,
+ .usage = "program to dump I2C registers",
+ U_BOOT_CMD_HELP(cmd_i2cdump_help_s)
+U_BOOT_CMD_END
+#endif /* CONFIG_CMD_I2C_DUMP */
+
+#ifdef CONFIG_CMD_I2C_GET
+static const __maybe_unused char cmd_i2cget_help_s[] =
+ "Usage: i2cget [-y] [-f] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]\n"
+ "Where:\n"
+ " -y : will allow to get from 0x50 to 0x57 with pec enabled\n"
+ " -f : Force set the slave address\n"
+ "I2CBUS is an integer representing the bus index\n"
+ " these are present as 'xx' of /dev/" I2C_DEV_NAME "xx\n"
+ "CHIP-ADDRESS is an integer representing device address (0x03 - 0x77)\n"
+ "DATA-ADDRESS is an integer representing register offset.\n"
+ " (0x00 - 0xFF). If omitted, the currently active register\n"
+ " will be read (if that makes sense for the considered chip).\n"
+ "MODE is one of:\n"
+ " b (read byte data, default)\n"
+ " w (read word data)\n"
+ " c (write byte/read byte)\n"
+ " Append p for PEC\n"
+ "WARN: i2cget can be extremely dangerous if used improperly.\n";
+
+#ifdef CONFIG_LONGHELP
+static const __maybe_unused char cmd_i2cget_help_add_s[] =
+ "I2C"
+ "are designed in such a way that an read transaction can be seen\n"
+ "as a write transaction by certain chips. This is particularly true if\n"
+ "setting mode to cp (write byte/read byte with PEC). Be extremely careful\n"
+ "using this program.\n";
+static void cmd_i2get_help(void)
+{
+ fprintf(stderr, "%s", cmd_i2cget_help_s);
+ fprintf(stderr, "%s", cmd_i2cget_help_add_s);
+}
+#else
+#define cmd_i2get_help()
+#endif
+
+/**
+ * @brief confirm if user can really proceed without badly hurting..
+ *
+ * @param filename
+ * @param address
+ * @param size
+ * @param daddress
+ * @param pec
+ *
+ * @return 0 if dont proceed, 1 if ok to go ahead
+ */
+static int confirm_get(const char *filename, int address, int size,
+ int daddress, int pec)
+{
+ /* Don't let the user break his/her EEPROMs */
+ if (address >= 0x50 && address <= 0x57 && pec) {
+ fprintf(stderr, "STOP! EEPROMs are I2C devices, not "
+ "SMBus devices. Using PEC\non I2C devices may "
+ "result in unexpected results, such as\n"
+ "trashing the contents of EEPROMs. We can't "
+ "let you do that, sorry.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * @brief read from I2C chip registers
+ *
+ * @param cmdtp
+ * @param argc
+ * @param argv
+ *
+ * @return
+ */
+static int do_cmd_i2c_get(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *end;
+ int res, i2cbus, address, size, file = -1;
+ int daddress;
+ char filename[PATH_MAX];
+ int pec = 0;
+ int flags = 0;
+ int force = 0, yes = 0;
+
+ /* handle (optional) flags first */
+ while (1 + flags < argc && argv[1 + flags][0] == '-') {
+ switch (argv[1 + flags][1]) {
+ case 'f':
+ force = 1;
+ break;
+ case 'y':
+ yes = 1;
+ break;
+ default:
+ fprintf(stderr, "Error: Unsupported option "
+ "\"%s\"!\n", argv[1 + flags]);
+ goto quit_i2cget;
+ }
+ flags++;
+ }
+
+ if (argc < flags + 3) {
+ fprintf(stderr, "Error: Not enough args\n");
+ goto quit_i2cget;
+ }
+
+ i2cbus = lookup_i2c_bus(argv[flags + 1]);
+ if (i2cbus < 0) {
+ fprintf(stderr, "Error: Bad bus!\n");
+ goto quit_i2cget;
+ }
+
+ address = parse_i2c_address(argv[flags + 2]);
+ if (address < 0) {
+ fprintf(stderr, "Error: Bad address!\n");
+ goto quit_i2cget;
+ }
+
+ if (argc > flags + 3) {
+ size = I2C_SMBUS_BYTE_DATA;
+ daddress = simple_strtol(argv[flags + 3], &end, 0);
+ if (*end || daddress < 0 || daddress > 0xff) {
+ fprintf(stderr, "Error: Data address invalid!\n");
+ goto quit_i2cget;
+ }
+ } else {
+ size = I2C_SMBUS_BYTE;
+ daddress = -1;
+ }
+
+ if (argc > flags + 4) {
+ switch (argv[flags + 4][0]) {
+ case 'b':
+ size = I2C_SMBUS_BYTE_DATA;
+ break;
+ case 'w':
+ size = I2C_SMBUS_WORD_DATA;
+ break;
+ case 'c':
+ size = I2C_SMBUS_BYTE;
+ break;
+ default:
+ fprintf(stderr, "Error: Invalid mode!\n");
+ goto quit_i2cget;
+ }
+ pec = argv[flags + 4][1] == 'p';
+ }
+
+ file = open_i2c_dev(i2cbus, filename, 0);
+ if (file < 0 || check_funcs(file, size, daddress, pec)
+ || set_slave_addr(file, address, force))
+ goto quit_i2cget;
+
+ if (!yes && !confirm_get(filename, address, size, daddress, pec)) {
+ res = 0;
+ goto ret1;
+ }
+
+ if (pec && ioctl(file, I2C_PEC, (void *)1) < 0) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not set PEC\n");
+ goto quit_i2cget;
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ res = read_i2c(file, address, daddress, 1, NULL, 0);
+ break;
+ default:
+ {
+ u16 new_val;
+ res =
+ read_i2c(file, address, daddress, 1,
+ (u8 *) &new_val,
+ (size == I2C_SMBUS_WORD_DATA) ? 2 : 1);
+ if (res >= 0)
+ res = new_val;
+ }
+ }
+ret1:
+ close(file);
+
+ if (res < 0) {
+ fprintf(stderr, "Error: Read failed\n");
+ return 2;
+ }
+
+ printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
+
+ return 0;
+
+quit_i2cget:
+ cmd_i2get_help();
+ if (file >= 0)
+ close(file);
+ return 1;
+}
+
+U_BOOT_CMD_START(i2cget)
+ .maxargs = 7,
+ .cmd = do_cmd_i2c_get,
+ .usage = "program to read an I2C register",
+ U_BOOT_CMD_HELP(cmd_i2cget_help_s)
+U_BOOT_CMD_END
+#endif /* CONFIG_CMD_I2C_GET */
+
+#ifdef CONFIG_CMD_I2C_SET
+static const __maybe_unused char cmd_i2cset_help_s[] =
+ "Usage: i2cset [-y] [-f] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE"
+ " [MODE [MASK]]]\n"
+ "Where:\n"
+ " -y : will allow to set 0x50 to 0x57 with pec enabled\n"
+ " -f : Force set the slave address\n"
+ "I2CBUS is an integer representing the bus index\n"
+ " these are present as 'xx' of /dev/" I2C_DEV_NAME
+ "xx\n"
+ "CHIP-ADDRESS is an integer representing device address (0x03 - 0x77)\n"
+ "DATA-ADDRESS is an integer representing register on chip.\n"
+ " (0x00 - 0xFF).\n"
+ "VALUE is the value to be written, if ignored, an short write is issued.\n"
+ "MODE is one of:\n"
+ " b (read byte data, default)\n"
+ " w (read word data)\n"
+ " Append p for PEC\n"
+ "MASK if specified,describes which bits of value will be actually written\n"
+ "WARN:\n" "i2cset can be extremely dangerous if used improperly.\n";
+
+#ifdef CONFIG_LONGHELP
+static const __maybe_unused char cmd_i2cset_help_add_s[] =
+ "It can confuse "
+ "your I2C bus, cause data loss, or have more serious side effects.\n"
+ "Writing to a serial EEPROM on a memory DIMM (chip addresses between\n"
+ "0x50 and 0x57) may DESTROY your memory, leaving your system unbootable!\n"
+ "Be extremely careful using this program.\n";
+static void cmd_i2set_help(void)
+{
+ fprintf(stderr, "%s", cmd_i2cset_help_s);
+ fprintf(stderr, "%s", cmd_i2cset_help_add_s);
+}
+#else
+#define cmd_i2set_help()
+#endif
+
+/**
+ * @brief confirm we can write to the reg without killing the user
+ *
+ * @param filename
+ * @param address
+ * @param size
+ * @param daddress
+ * @param value
+ * @param vmask
+ * @param pec
+ *
+ * @return
+ */
+static int confirm_set(const char *filename, int address, int size,
+ int daddress, int value, int vmask, int pec)
+{
+ if (address >= 0x50 && address <= 0x57) {
+ fprintf(stderr, "DANGEROUS! Writing to a serial "
+ "EEPROM on a memory DIMM\nmay render your "
+ "memory USELESS and make your system " "UNBOOTABLE!\n");
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * @brief set I2C registers
+ *
+ * @param cmdtp
+ * @param argc
+ * @param argv
+ *
+ * @return
+ */
+static int do_cmd_i2c_set(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *end;
+ int res, i2cbus, address, size, file = -1;
+ int value, daddress, vmask = 0;
+ char filename[PATH_MAX];
+ int pec = 0;
+ int flags = 0;
+ int force = 0, yes = 0;
+
+ /* handle (optional) flags first */
+ while (1 + flags < argc && argv[1 + flags][0] == '-') {
+ switch (argv[1 + flags][1]) {
+ case 'f':
+ force = 1;
+ break;
+ case 'y':
+ yes = 1;
+ break;
+ default:
+ fprintf(stderr, "Error: Unsupported option "
+ "\"%s\"!\n", argv[1 + flags]);
+ goto quit_i2cset;
+ }
+ flags++;
+ }
+
+ if (argc < flags + 4) {
+ fprintf(stderr, "Error: Not enough arguments\n");
+ goto quit_i2cset;
+ }
+
+ i2cbus = lookup_i2c_bus(argv[flags + 1]);
+ if (i2cbus < 0) {
+ fprintf(stderr, "Error: Invalid Bus!\n");
+ goto quit_i2cset;
+ }
+
+ address = parse_i2c_address(argv[flags + 2]);
+ if (address < 0) {
+ fprintf(stderr, "Error: Invalid address!\n");
+ goto quit_i2cset;
+ }
+
+ daddress = simple_strtol(argv[flags + 3], &end, 0);
+ if (*end || daddress < 0 || daddress > 0xff) {
+ fprintf(stderr, "Error: Data address invalid!\n");
+ goto quit_i2cset;
+ }
+
+ if (argc > flags + 4) {
+ size = I2C_SMBUS_BYTE_DATA;
+ value = simple_strtol(argv[flags + 4], &end, 0);
+ if (*end || value < 0) {
+ fprintf(stderr, "Error: Data value invalid!\n");
+ goto quit_i2cset;
+ }
+ } else {
+ size = I2C_SMBUS_BYTE;
+ value = -1;
+ }
+
+ if (argc > flags + 5) {
+ switch (argv[flags + 5][0]) {
+ case 'b':
+ size = I2C_SMBUS_BYTE_DATA;
+ break;
+ case 'w':
+ size = I2C_SMBUS_WORD_DATA;
+ break;
+ default:
+ fprintf(stderr, "Error: Invalid mode!\n");
+ goto quit_i2cset;
+ }
+ pec = argv[flags + 5][1] == 'p';
+ }
+
+ if (argc > flags + 6) {
+ vmask = simple_strtol(argv[flags + 6], &end, 0);
+ if (*end || vmask == 0) {
+ fprintf(stderr, "Error: Data value mask invalid!\n");
+ goto quit_i2cset;
+ }
+ }
+
+ if ((size == I2C_SMBUS_BYTE_DATA && value > 0xff)
+ || (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
+ fprintf(stderr, "Error: Data value out of range!\n");
+ goto quit_i2cset;
+ }
+
+ file = open_i2c_dev(i2cbus, filename, 0);
+ if (file < 0 || check_funcs(file, size, daddress, pec)
+ || set_slave_addr(file, address, force))
+ goto quit_i2cset;
+
+ if (!yes && !confirm_set(filename, address, size, daddress,
+ value, vmask, pec)) {
+ close(file);
+ return 0;
+ }
+
+ if (vmask) {
+ int oldvalue;
+ u16 dat;
+ oldvalue =
+ read_i2c(file, address, daddress, 1, (u8 *) &dat,
+ (size == I2C_SMBUS_WORD_DATA) ? 2 : 1);
+
+ if (oldvalue < 0) {
+ fprintf(stderr, "Error: Failed to read old value\n");
+ goto quit_i2cset;
+ }
+ oldvalue = dat;
+
+ value = (value & vmask) | (oldvalue & ~vmask);
+
+ fprintf(stderr, "Old value 0x%0*x, write mask "
+ "0x%0*x: Will write 0x%0*x to register "
+ "0x%02x\n",
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, value, daddress);
+
+ }
+
+ if (pec && ioctl(file, I2C_PEC, (void *)1) < 0) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not set PEC\n");
+ goto quit_i2cset;
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ res = write_i2c(file, address, daddress, 1, NULL, 0);
+ break;
+ default:
+ res =
+ write_i2c(file, address, daddress, 1,
+ (u8 *) &value,
+ (size == I2C_SMBUS_WORD_DATA) ? 2 : 1);
+ }
+ if (res < 0) {
+ fprintf(stderr, "Error: Write failed\n");
+ goto quit_i2cset;
+ }
+
+ if (pec) {
+ if (ioctl(file, I2C_PEC, (void *)0) < 0) {
+ perror(filename);
+ fprintf(stderr, "Error: Could not clear PEC\n");
+ goto quit_i2cset;
+ }
+ }
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ /* No readback */
+ break;
+ default:
+ {
+ u16 new_val;
+ res =
+ read_i2c(file, address, daddress, 1,
+ (u8 *) &new_val,
+ (size == I2C_SMBUS_WORD_DATA) ? 2 : 1);
+ if (res >= 0)
+ res = new_val;
+ }
+ }
+ close(file);
+
+ if (size == I2C_SMBUS_BYTE) /* We're done */
+ return 0;
+
+ if (res < 0) {
+ printf("Warning - readback failed\n");
+ } else if (res != value) {
+ printf("Warning - data mismatch - wrote "
+ "0x%0*x, read back 0x%0*x\n",
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
+ } else {
+ printf("Value 0x%0*x written, readback matched\n",
+ size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
+ }
+
+ return 0;
+quit_i2cset:
+ if (file >= 0)
+ close(file);
+ cmd_i2set_help();
+ return 1;
+}
+
+U_BOOT_CMD_START(i2cset)
+ .maxargs = 8,
+ .cmd = do_cmd_i2c_set,
+ .usage = "program to write an I2C register",
+ U_BOOT_CMD_HELP(cmd_i2cset_help_s)
+U_BOOT_CMD_END
+#endif /* CONFIG_CMD_I2C_SET */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-19 15:12 ` [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands Menon, Nishanth
@ 2008-06-19 20:33 ` Wolfgang Denk
2008-06-20 2:10 ` Menon, Nishanth
2008-06-20 10:28 ` Sascha Hauer
1 sibling, 1 reply; 43+ messages in thread
From: Wolfgang Denk @ 2008-06-19 20:33 UTC (permalink / raw)
To: u-boot
In message <7A436F7769CA33409C6B44B358BFFF0CD3211BBD@dlee02.ent.ti.com> you wrote:
> Introduce I2c commands from i2c-tools.
> This allows for Diagnostics capability.
> Supports ONLY i2c busses at the moment.
>
> This code is based on
> http://www.lm-sensors.org/wiki/I2CTools
> This closely follows the functionality, options
> and man page documentation
Please indent by TABs.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Diplomacy is the art of saying "nice doggy" until you can find a rock.
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-19 20:33 ` Wolfgang Denk
@ 2008-06-20 2:10 ` Menon, Nishanth
2008-06-20 7:28 ` Wolfgang Denk
0 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-20 2:10 UTC (permalink / raw)
To: u-boot
Wolfgang,
> -----Original Message-----
> From: wd at denx.de [mailto:wd at denx.de]
> Sent: Thursday, June 19, 2008 3:33 PM
> To: Menon, Nishanth
> Cc: Sascha Hauer; u-boot-users at lists.sourceforge.net
> Subject: Re: [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
>
> Please indent by TABs.
Is'nt checkpatch supposed to catch such issues?
I do get 10 warning all of the nature of:
WARNING: consider using strict_strtol in preference to simple_strtol
#1167: FILE: commands/i2c.c:1145:
+ vmask = simple_strtol(argv[flags + 6], &end, 0);
But there are no tab warnings. Since we don't have strict_strol, I have
Ignored this warning for u-boot v2.
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-20 2:10 ` Menon, Nishanth
@ 2008-06-20 7:28 ` Wolfgang Denk
0 siblings, 0 replies; 43+ messages in thread
From: Wolfgang Denk @ 2008-06-20 7:28 UTC (permalink / raw)
To: u-boot
In message <7A436F7769CA33409C6B44B358BFFF0CD3212142@dlee02.ent.ti.com> you wrote:
>
> > Please indent by TABs.
> Is'nt checkpatch supposed to catch such issues?
IIRC it catches only indentations >= 8 columns.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
The perversity of nature is nowhere better demonstrated by the fact
that, when exposed to the same atmosphere, bread becomes hard while
crackers become soft.
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-19 15:12 ` [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands Menon, Nishanth
2008-06-19 20:33 ` Wolfgang Denk
@ 2008-06-20 10:28 ` Sascha Hauer
2008-06-20 13:35 ` Menon, Nishanth
1 sibling, 1 reply; 43+ messages in thread
From: Sascha Hauer @ 2008-06-20 10:28 UTC (permalink / raw)
To: u-boot
On Thu, Jun 19, 2008 at 10:12:32AM -0500, Menon, Nishanth wrote:
> Introduce I2c commands from i2c-tools.
> This allows for Diagnostics capability.
> Supports ONLY i2c busses at the moment.
>
> This code is based on
> http://www.lm-sensors.org/wiki/I2CTools
> This closely follows the functionality, options
> and man page documentation
Some overall comments first.
You seem to register a device for each bus and do all access to slave
devices through the bus. It would be better if we register a new device
for each slave device. Slave devices could either be hardwired by a
board setup or, if the board maintainer or user is brave, through an
autodetect mechanism.
Once we have a device for each slave most of this patch can be removed
since you can use the generic md/mm commands for reading registers. In
the device tree this could look like this:
/dev/i2cbus0 # bus 0
/dev/i2cbus0_50 # device 0x50 on bus 0...
/dev/eeprom0 # which happens to be an eeprom
Please resist to introduce a new command for each type of device.
more inline...
Sascha
>
> Signed-off-by: Nishanth Menon <x0nishan@ti.com>
>
> ---
> commands/i2c.c | 1268 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 1268 insertions(+)
>
> Index: u-boot-v2.git/commands/i2c.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ u-boot-v2.git/commands/i2c.c 2008-06-19 09:31:37.000000000 -0500
> @@ -0,0 +1,1268 @@
> +/**
> + * @file
> + * @brief I2C related applications
> + *
> + * FileName: commands/i2c.c
> + * This provides i2cdump, i2cdetect, i2cset and i2cget appplications
> + * The code originates from the i2c-tools located here:
> + * http://www.lm-sensors.org/wiki/I2CTools
> + *
> + * This file merges the userspace headers and applications to a single
> + * entity as we do not maintain a userspace/kernel space isolation
> + *
> + * NOTE: 10-bit addresses are NOT supported!
> + */
> +/*
> + * (C) Copyright 2006-2008
> + * Texas Instruments, <www.ti.com>
> + * Nishanth Menon <x0nishan@ti.com>
> + *
> + * This application is based on the following:
> + *
> + * i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
> + * Part of user-space programs to access for I2C
> + * devices.
> + * Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
> + * Mark D. Studebaker <mdsxyz123@yahoo.com>
> + * Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
> + * i2cdump.c - a user-space program to dump I2C registers
> + * Copyright (C) 2002-2003 Frodo Looijaard <frodol@dds.nl>, and
> + * Mark D. Studebaker <mdsxyz123@yahoo.com>
> + * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
> + * i2cget.c - A user-space program to read an I2C register.
> + * Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
> + * i2cset.c - A user-space program to write an I2C register.
> + * Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
> + * Mark D. Studebaker <mdsxyz123@yahoo.com>
> + * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> + * MA 02110-1301 USA.
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <types.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <malloc.h>
> +#include <fs.h>
> +#include <errno.h>
> +#include <linux/stat.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-dev.h>
> +#include "i2c.h"
> +
> +#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n"
> +
> +/*************** Lib Functions *************/
> +
> +/**
> + * @brief Parse an I2CBUS command line argument
> + *
> + * @param i2cbus_arg arg to busparam
> + *
> + * @return the corresponding bus number,
> + * or a negative value if the bus is invalid.
> + */
> +int lookup_i2c_bus(const char *i2cbus_arg)
> +{
> + long i2cbus;
> + char *end;
> +
> + if (i2cbus_arg == NULL) {
> + fprintf(stderr, "no bus arg! expect 0-9\n");
> + return -1;
> + }
> + if (strlen(i2cbus_arg) > 2) {
> + fprintf(stderr, "bad bus arg! expect 0-9 saw %s\n", i2cbus_arg);
> + return -2;
> + }
> + i2cbus = simple_strtol(i2cbus_arg, &end, 0);
> + if ((*i2cbus_arg != '0') && (i2cbus == 0)) {
> + fprintf(stderr, "bad bus arg! expect 0-9, saw %s\n",
> + i2cbus_arg);
> + return -2;
> + }
> + if (i2cbus < 0 || i2cbus > 0xff) {
> + fprintf(stderr, "Error: I2C bus out of range (0-255)!\n");
> + return -3;
> + }
> +
> + return i2cbus;
> +}
> +
> +/**
> + * @brief open a given i2cdevice
> + *
> + * @param i2cbus bus index
> + * @param filename return the devfs filename for the bus
> + * @param quiet be silent?
> + *
> + * @return return value of open
> + */
> +int open_i2c_dev(const int i2cbus, char *filename, const int quiet)
> +{
> + int file;
> +
> + sprintf(filename, "/dev/" I2C_DEV_NAME "%d", i2cbus);
> + file = open(filename, O_RDWR);
> +
> + if (file < 0 && !quiet) {
> + perror(filename);
> + fprintf(stderr, "Error: Could not open file "
> + "`%s'\n", filename);
> + }
> +
> + return file;
> +}
> +
> +/**
> + * @brief Parse a CHIP-ADDRESS command line argument
> + *
> + * @param address_arg -user provided argument
> + *
> + * @return The corresponding chip address,
> + * or a negative value if the address is invalid.
> + */
> +int parse_i2c_address(const char *address_arg)
> +{
> + long address;
> + char *end;
> +
> + address = simple_strtol(address_arg, &end, 0);
> + if (*end || !*address_arg) {
> + fprintf(stderr, "Error: Chip address is not a number!\n");
> + return -1;
> + }
> + if (address < 0x03 || address > 0x77) {
> + fprintf(stderr, "Error: Chip address out of range "
> + "(0x03-0x77)!\n");
> + return -2;
> + }
> +
> + return address;
> +}
> +
> +/**
> + * @brief force the slave address
> + *
> + * @param file file id
> + * @param address address to set
> + * @param force force address
> + *
> + * @return returns result of ioctl
> + */
> +int set_slave_addr(int file, int address, int force)
> +{
> + /* With force, let the user read from/write to the registers
> + even when a driver is also running */
> + if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, (void *)address) <
> + 0) {
> + perror(NULL);
> + fprintf(stderr,
> + "Error: Could not set address to 0x%02x\n", address);
> + return -errno;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * @brief check functionality of the adapter
> + *
> + * @param file file index
> + * @param size size of the same
> + * @param daddress device address
> + * @param pec pec
> + *
> + * @return result of ioctl check negative if failed
> + */
> +int check_funcs(int file, int size, int daddress, int pec)
> +{
> + unsigned long funcs;
> +
> + /* check adapter functionality */
> + if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
> + perror(NULL);
> + fprintf(stderr, "Error: Could not get the adapter "
> + "functionality matrix\n");
> + return -1;
> + }
> +
> + if (!(funcs & I2C_FUNC_I2C)) {
> + fprintf(stderr, MISSING_FUNC_FMT, "I2C support");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +int read_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
> + size_t count)
> +{
> + struct i2c_msg msg[2] = {
> + {daddr, 0, reg_width, (u8 *) &addr},
> + {daddr, 0 | I2C_M_RD, count, buffer}
> + };
> + struct i2c_rdwr_ioctl_data data = {
> + .msgs = msg,
> + .nmsgs = 2,
> + };
> + return ioctl(file, I2C_RDWR, &data);
> +}
> +
> +int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
> + size_t count)
> +{
> + unsigned char *temp_buf;
> + struct i2c_msg msg = { daddr, 0, count + reg_width, NULL };
> + struct i2c_rdwr_ioctl_data data = {
> + .msgs = &msg,
> + .nmsgs = 1,
> + };
> + int ret;
> + temp_buf = malloc(count + reg_width);
> + if (temp_buf == NULL)
> + return -ENOMEM;
> + memcpy(temp_buf, &addr, reg_width);
> + memcpy(temp_buf + reg_width, buffer, count);
> + msg.buf = temp_buf;
> + ret = ioctl(file, I2C_RDWR, &data);
> + free(temp_buf);
> + return ret;
> +}
> +
> +/****************** Test implementations **************/
> +#ifdef CONFIG_CMD_I2C_DETECT
> +
> +#define MODE_AUTO 0
> +#define MODE_QUICK 1
> +#define MODE_READ 2
> +#define MODE_FUNC 3
> +
> +static const __maybe_unused char cmd_i2cdetect_help_s[] =
> + "Usage:\n"
> + "a) i2cdetect [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
> + "Where:\n"
> + " -a : all addresses (default scans from 0x03 - 0x77)\n"
> + " -q : use write-risky at times\n"
> + " -r : use read-risky at times\n"
> + " If provided, FIRST and LAST limit the probing range.\n"
> + "b) i2cdetect -F I2CBUS\n"
> + "Where:\n"
> + " -F : Show functionality of the device\n"
> + "\n"
> + "I2CBUS is an integer representing the bus index\n"
> + "these are present as 'xx' of /dev/" I2C_DEV_NAME
> + "xx\n" "WARN:\n"
This requires documentation and implementation. Why not -f <filename>?
> + "This program can confuse your I2C bus, cause data loss and worse!\n";
> +
> +#ifdef CONFIG_LONGHELP
> +static void cmd_i2cdetect_help(void)
> +{
> + fprintf(stderr, "%s", cmd_i2cdetect_help_s);
> +}
> +#else
> +#define cmd_i2cdetect_help()
> +#endif
You do not need this ifdef...
> +
> +/**
> + * @brief scan the i2c bus
> + *
> + * @param file file index
> + * @param mode what mode to scan it with
> + * @param first start address
> + * @param last end address
> + *
> + * @return negative if scan failed, else return 0
> + */
> +static int scan_i2c_bus(int file, int mode, int first, int last)
> +{
> + int i, j;
> + int res;
> + unsigned char dummy = 0x0;
> +
> + printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
> +
> + for (i = 0; i < 128; i += 16) {
> + printf("%02x: ", i);
> + for (j = 0; j < 16; j++) {
> +
> + /* Skip unwanted addresses */
> + if (i + j < first || i + j > last) {
> + printf(" ");
> + continue;
> + }
> +
> + /* Set slave address */
> + if (ioctl(file, I2C_SLAVE, (void *)(i + j)) < 0) {
> + if (errno == EBUSY) {
> + printf("UU ");
> + continue;
> + } else {
> + perror(NULL);
> + fprintf(stderr, "Error: Could not set "
> + "address to 0x%02x\n", i + j);
> + return -1;
> + }
> + }
> +
> + /* Probe this address */
> + switch (mode) {
> + case MODE_QUICK:
> + /* Attempt a 0 byte write -can lock up many
> + * devices */
> + res = write_i2c(file, i + j, 0x0, 1, NULL, 0);
> + break;
> + case MODE_READ:
> + /* This is known to lock on various
> + write-only chips (mainly clock chips) */
> + res = read_i2c(file, i + j, 0x0, 1, &dummy, 1);
> + break;
> + default:
> + if ((i + j >= 0x30 && i + j <= 0x37)
> + || (i + j >= 0x50 && i + j <= 0x5F))
> + res =
> + read_i2c(file, i + j, 0x0, 1,
> + &dummy, 1);
> + else
> + res =
> + write_i2c(file, i + j, 0x0, 1, NULL,
> + 0);
> + }
> +
> + if (res < 0)
> + printf("-- ");
> + else
> + printf("%02x ", i + j);
> + }
> + printf("\n");
> + }
> +
> + return 0;
> +}
> +
> +struct func {
> + long value;
> + const char *name;
> +};
> +
> +static const struct func all_func[] = {
> + {.value = I2C_FUNC_I2C,
> + .name = "I2C"},
> + {.value = 0,
> + .name = ""}
> +};
> +
> +/**
> + * @brief print the functionality of the adapter
> + *
> + * @param funcs the ioctl returned value
> + *
> + * @return none
> + */
> +static void print_functionality(unsigned long funcs)
> +{
> + int i;
> + for (i = 0; all_func[i].value; i++) {
> + printf("%-32s %s\n", all_func[i].name,
> + (funcs & all_func[i].value) ? "yes" : "no");
> + }
> +}
> +
> +static int do_cmd_i2c_detect(cmd_tbl_t *cmdtp, int argc, char *argv[])
> +{
> + char *end;
> + int i2cbus, file = 0, res = 0;
> + char filename[PATH_MAX];
> + unsigned long funcs;
> + int mode = MODE_AUTO;
> + int first = 0x03, last = 0x77;
> + int flags = 0;
> +
> + /* handle (optional) flags first */
> + while (1 + flags < argc && argv[1 + flags][0] == '-') {
> + switch (argv[1 + flags][1]) {
> + case 'F':
> + if (mode != MODE_AUTO && mode != MODE_FUNC) {
> + fprintf(stderr, "Error: Different modes "
> + "specified!\n");
> + goto quit_i2cdetect;
> + }
> + mode = MODE_FUNC;
> + break;
> + case 'r':
> + if (mode == MODE_QUICK) {
> + fprintf(stderr, "Error: Different modes "
> + "specified!\n");
> + goto quit_i2cdetect;
> + }
> + mode = MODE_READ;
> + break;
> + case 'q':
> + if (mode == MODE_READ) {
> + fprintf(stderr, "Error: Different modes "
> + "specified!\n");
> + goto quit_i2cdetect;
> + }
> + mode = MODE_QUICK;
> + break;
> + case 'a':
> + first = 0x00;
> + last = 0x7F;
> + break;
> + default:
> + fprintf(stderr, "Error: Unsupported option "
> + "\"%s\"!\n", argv[1 + flags]);
> + goto quit_i2cdetect;
> + }
> + flags++;
> + }
Please use getopt instead.
> +
> + if (argc < flags + 2) {
> + fprintf(stderr, "Error: No i2c-bus specified!\n");
> + goto quit_i2cdetect;
> + }
> + i2cbus = lookup_i2c_bus(argv[flags + 1]);
> + if (i2cbus < 0) {
> + fprintf(stderr, "Error: bus not found!\n");
> + goto quit_i2cdetect;
> + }
> +
> + /* read address range if present */
> + if (argc == flags + 4 && mode != MODE_FUNC) {
> + int tmp;
> +
> + tmp = simple_strtol(argv[flags + 2], &end, 0);
> + if (*end) {
> + fprintf(stderr, "Error: FIRST argment not a "
> + "number!\n");
> + goto quit_i2cdetect;
> + }
> + if (tmp < first || tmp > last) {
> + fprintf(stderr, "Error: FIRST argument out of range "
> + "(0x%02x-0x%02x)!\n", first, last);
> + goto quit_i2cdetect;
> + }
> + first = tmp;
> +
> + tmp = simple_strtol(argv[flags + 3], &end, 0);
> + if (*end) {
> + fprintf(stderr, "Error: LAST argment not a "
> + "number!\n");
> + goto quit_i2cdetect;
> + }
> + if (tmp < first || tmp > last) {
> + fprintf(stderr, "Error: LAST argument out of range "
> + "(0x%02x-0x%02x)!\n", first, last);
> + goto quit_i2cdetect;
> + }
> + last = tmp;
> + } else if (argc != flags + 2) {
> + goto quit_i2cdetect;
> + }
> +
> + file = open_i2c_dev(i2cbus, filename, 0);
> + if (file < 0)
> + return 1;
> +
> + res = 1;
> + if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
> + perror(filename);
> + fprintf(stderr, "Error: Could not get the adapter "
> + "functionality matrix\n");
> + goto ret;
> + }
> +
> + /* Special case, we only list the implemented functionalities */
> + if (mode == MODE_FUNC) {
> + printf("Functionalities implemented by %s:\n", filename);
> + print_functionality(funcs);
> + res = 0;
> + goto ret;
> + }
> +
> + res = scan_i2c_bus(file, mode, first, last);
> +ret:
> + if (file >= 0)
> + close(file);
> + return res ? 1 : 0;
> +
> +quit_i2cdetect:
> + /* Exit after printing help */
> + cmd_i2cdetect_help();
If you want to print the help text here call u_boot_cmd_usage(cmdtp).
> + goto ret;
> +}
> +
> +U_BOOT_CMD_START(i2cdetect)
> + .maxargs = 6,
> + .cmd = do_cmd_i2c_detect,
> + .usage = "program to scan for I2C devices",
> + U_BOOT_CMD_HELP(cmd_i2cdetect_help_s)
> +U_BOOT_CMD_END
> +#endif /* CONFIG_CMD_I2C_DETECT */
> +
> +#ifdef CONFIG_CMD_I2C_DUMP
> +static const __maybe_unused char cmd_i2cdump_help_s[] =
> + "Usage: i2cdump [-f] [-r first-last] I2CBUS ADDRESS [MODE]\n"
> + "Where:\n"
> + " -f : Force set the slave address\n"
> + " -r : first-last the range of addresses which will be dumped\n"
> + "I2CBUS is an integer representing the bus index\n"
> + " these are present as 'xx' of /dev/" I2C_DEV_NAME "xx\n"
> + "ADDRESS is an integer representing device address (0x03 - 0x77)\n"
> + "MODE is one of:\n"
> + " b (byte, default)\n"
> + " w (word)\n"
> + " W (word on even register addresses)\n"
> + " Append p for PEC\n"
> + "WARN: i2cdump can be dangerous if used improperly.\n";
> +
> +#ifdef CONFIG_LONGHELP
> +static const __maybe_unused char cmd_i2c_ext_help_s[] =
> + "Most notably, the c mode "
> + "starts with WRITING a byte to the chip. On most chips it will be stored\n"
> + "in the address pointer register, which is OK, but some chips with a\n"
> + "single register or no (visible)register at all will most likely see this\n"
> + "as a real WRITE, resulting in possible misbehavior or corruption. Do not\n"
> + "use i2cdump on random addresses. Anyway, it is of little use unless you\n"
> + "have good knowledge of the chip you??(tm)re working with and an idea of \n"
> + "what you are looking for.\n";
> +static void cmd_i2dump_help(void)
> +{
> + fprintf(stderr, "%s", cmd_i2cdump_help_s);
> + fprintf(stderr, "%s", cmd_i2c_ext_help_s);
> +}
> +#else
> +#define cmd_i2dump_help()
> +#endif
> +
> +static int do_cmd_i2c_dump(cmd_tbl_t *cmdtp, int argc, char *argv[])
> +{
> + char *end;
> + int i, j, res, i2cbus, address, size, file = -1;
> + char filename[PATH_MAX];
> + int block[256];
> + int pec = 0, even = 0;
> + int flags = 0;
> + int force = 0;
> + const char *range = NULL;
> + int first = 0x00, last = 0xff;
> +
> + /* handle (optional) flags first */
> + while (1 + flags < argc && argv[1 + flags][0] == '-') {
> + switch (argv[1 + flags][1]) {
> + case 'f':
> + force = 1;
> + break;
> + case 'r':
> + range = argv[1 + (++flags)];
> + break;
> + default:
> + fprintf(stderr, "Error: Unsupported option "
> + "\"%s\"!\n", argv[1 + flags]);
> + goto quit_i2cdump;
> + }
> + flags++;
> + }
getopt instead
<snip>
--
Pengutronix e.K. - Linux Solutions for Science and Industry
-----------------------------------------------------------
Kontakt-Informationen finden Sie im Header dieser Mail oder
auf der Webseite -> http://www.pengutronix.de/impressum/ <-
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-20 10:28 ` Sascha Hauer
@ 2008-06-20 13:35 ` Menon, Nishanth
2008-06-20 15:16 ` Sascha Hauer
0 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-20 13:35 UTC (permalink / raw)
To: u-boot
Sascha,
> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> Sent: Friday, June 20, 2008 5:29 AM
> To: Menon, Nishanth
> Cc: u-boot-users at lists.sourceforge.net
> Subject: Re: [Patch 5/9]U-boot-V2:cmd: add I2C commands
>
> Some overall comments first.
>
> You seem to register a device for each bus and do all access to slave
> devices through the bus. It would be better if we register a new device
> for each slave device.
No. that is not a good strategy. Many reasons why not to do it as the cmds
are a debug tool:
a) I am not interested in registering camera and all devices I may have in
code. Yet, the handy little tool is good to do some basic debug of the device.
b) Every client behaves in a different way. Camera for example may follow CCI
specification, in which case, they would have 8, 16 ,32 bit regs all in the same
device. In fact it may be near impossible to write a generic driver for them all.
We cannot predict what we want to do for every device out there.
c) Devices wanting to expose their own app may choose to do so. Yes, I get the
comment:
> Please resist to introduce a new command for each type of device.
d) It is wasteful to generate multiple device nodes when someone smart enough to
understand I2C specification will also know that the common denominator for all
devices is the I2C bus.
e) Creating device node for each client node requires extensive client mechanism
in I2C which has no "use case" for me.
f) 7 bit addressing allows 127 devices, and I have 3 busses. 127*3 device nodes as
a theoretical max is outrageous. When just 3 device nodes could have done the same job.
In short, the common access mechanism of exposing the bus and allowing users to
Do i2c accesses to the devices in the manner of choosing would be the most generic
Method to do it. In fact U-Boot v1 also does something similar.
> Slave devices could either be hardwired by a
> board setup or, if the board maintainer or user is brave, through an
> autodetect mechanism.
> Once we have a device for each slave most of this patch can be removed
> since you can use the generic md/mm commands for reading registers. In
> the device tree this could look like this:
>
> /dev/i2cbus0 # bus 0
> /dev/i2cbus0_50 # device 0x50 on bus 0...
> /dev/eeprom0 # which happens to be an eeprom
A) who would decide this would be a eeprom?
B) why should /dev/i2cbus0_50 be any different from /dev/eeprom?
C) you are looking at 3 different device nodes when a single one would suffice.
Note that complex development platforms like mine may have upto 30-40 devices on the bus.
I have power monitoring ADC chips on buses which I really don?t care about during boot, yet
May want to debug intermittently.
What do we achieve by introducing i2c device based nodes?
Will look at comments if we are aligned on this basic infrastructure. (overall I think the
Rest of the comments are valid, even though I'd wish you'd stop putting the entire patch
In the mail.. lots of scrolling down to reach your comment ;) )..
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-20 13:35 ` Menon, Nishanth
@ 2008-06-20 15:16 ` Sascha Hauer
2008-06-20 16:28 ` Menon, Nishanth
` (2 more replies)
0 siblings, 3 replies; 43+ messages in thread
From: Sascha Hauer @ 2008-06-20 15:16 UTC (permalink / raw)
To: u-boot
On Fri, Jun 20, 2008 at 08:35:46AM -0500, Menon, Nishanth wrote:
> Sascha,
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> > Sent: Friday, June 20, 2008 5:29 AM
> > To: Menon, Nishanth
> > Cc: u-boot-users at lists.sourceforge.net
> > Subject: Re: [Patch 5/9]U-boot-V2:cmd: add I2C commands
> >
> > Some overall comments first.
> >
> > You seem to register a device for each bus and do all access to slave
> > devices through the bus. It would be better if we register a new device
> > for each slave device.
> No. that is not a good strategy. Many reasons why not to do it as the cmds
> are a debug tool:
Just like md/mm are
> a) I am not interested in registering camera and all devices I may have in
> code. Yet, the handy little tool is good to do some basic debug of the device.
> b) Every client behaves in a different way. Camera for example may follow CCI
> specification, in which case, they would have 8, 16 ,32 bit regs all in the same
> device. In fact it may be near impossible to write a generic driver for them all.
> We cannot predict what we want to do for every device out there.
Lets see:
+int read_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
+ size_t count)
+int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char
*buffer,
+ size_t count)
These arguments map nicely to md/mm
> c) Devices wanting to expose their own app may choose to do so. Yes, I get the
> comment:
> > Please resist to introduce a new command for each type of device.
> d) It is wasteful to generate multiple device nodes when someone smart enough to
> understand I2C specification will also know that the common denominator for all
> devices is the I2C bus.
I do not understand why this is wasteful. It may be wasteful in terms of
malloc space, but all boards I know have more than enough memory for the
bootloader.
> e) Creating device node for each client node requires extensive client mechanism
> in I2C which has no "use case" for me.
> f) 7 bit addressing allows 127 devices, and I have 3 busses. 127*3 device nodes as
> a theoretical max is outrageous. When just 3 device nodes could have done the same job.
I did not mean for every possible device but for each device that is
actually present, or even from the present ones only the ones which are
of use for u-boot.
If you want to access a device which you know is present but U-Boot does
not know about it, then add a command like
i2c add /dev/i2cbus0 0x50
which would create the device node that you need to access device 0x50
on i2cbus0.
> In short, the common access mechanism of exposing the bus and allowing users to
> Do i2c accesses to the devices in the manner of choosing would be the most generic
> Method to do it. In fact U-Boot v1 also does something similar.
>
>
> > Slave devices could either be hardwired by a
> > board setup or, if the board maintainer or user is brave, through an
> > autodetect mechanism.
> > Once we have a device for each slave most of this patch can be removed
> > since you can use the generic md/mm commands for reading registers. In
> > the device tree this could look like this:
> >
> > /dev/i2cbus0 # bus 0
> > /dev/i2cbus0_50 # device 0x50 on bus 0...
> > /dev/eeprom0 # which happens to be an eeprom
> A) who would decide this would be a eeprom?
The board setup code in this case as eeproms are not probable.
> B) why should /dev/i2cbus0_50 be any different from /dev/eeprom?
issuing md on /dev/i2cbus0_50 would let you read the registers of the
chip, which of course happen to be the contents of the eeprom, so this
might be a bad example. Consider an A/D converter; reading
/dev/i2cbus0_xy would give you the register space while /dev/adxy would
give you the digital values (provided a client driver is present). Thus
/dev/adxy would require a driver whereas /dev/i2cbus0_xy does not.
> C) you are looking at 3 different device nodes when a single one would suffice.
>
> Note that complex development platforms like mine may have upto 30-40 devices on the bus.
> I have power monitoring ADC chips on buses which I really don???t care about during boot, yet
> May want to debug intermittently.
>
> What do we achieve by introducing i2c device based nodes?
- An overview over the system for those who are not familiar with it.
You may know the devices that are connected to the bus on your board,
I don't. One of the benefits in U-Boot-V2 for me is that many different
systems behave similarly although they have a very different hardware.
- when md/mm are usable on a device it also means that cp/memcmp/cat or
any other file command is usable.
- reduction in code size since you can reuse what's already there (like
file commands instead of new commands). That's one of the points that
make U-Boot-V1 bigger than it has to be.
>
> Will look at comments if we are aligned on this basic infrastructure. (overall I think the
> Rest of the comments are valid, even though I'd wish you'd stop putting the entire patch
> In the mail.. lots of scrolling down to reach your comment ;) )..
You are lucky, I already had to remove some lines as I hit the list
limit ;)
Regards,
Sascha
--
Pengutronix e.K. - Linux Solutions for Science and Industry
-----------------------------------------------------------
Kontakt-Informationen finden Sie im Header dieser Mail oder
auf der Webseite -> http://www.pengutronix.de/impressum/ <-
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-20 15:16 ` Sascha Hauer
@ 2008-06-20 16:28 ` Menon, Nishanth
2008-06-23 7:39 ` Sascha Hauer
2008-06-21 2:34 ` [U-Boot-Users] [Patch 4/9 Try 2]U-boot-V2:I2C: Introduce i2c-dev Menon, Nishanth
2008-06-21 2:34 ` [U-Boot-Users] [Patch 5/9 Try2]U-boot-V2:cmd: add I2C commands Menon, Nishanth
2 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-20 16:28 UTC (permalink / raw)
To: u-boot
Sascha,
Summary: Ok, you sold the idea to me.
> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> Sent: Friday, June 20, 2008 10:17 AM
> To: Menon, Nishanth
> Cc: u-boot-users at lists.sourceforge.net
> Subject: Re: [Patch 5/9]U-boot-V2:cmd: add I2C commands
> +int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char
> *buffer,
> + size_t count)
>
> These arguments map nicely to md/mm
Not exactly as of date (we can have register width as 16 bit and data width as 8 bit). But yeah, we can easily make md/mm do it. Yep, I have used md to dump nand and cp to write data.
> > What do we achieve by introducing i2c device based nodes?
>
> - An overview over the system for those who are not familiar with it.
> You may know the devices that are connected to the bus on your board,
> I don't. One of the benefits in U-Boot-V2 for me is that many different
> systems behave similarly although they have a very different hardware.
> - when md/mm are usable on a device it also means that cp/memcmp/cat or
> any other file command is usable.
> - reduction in code size since you can reuse what's already there (like
> file commands instead of new commands). That's one of the points that
> make U-Boot-V1 bigger than it has to be.
Ok, getting down to implementation level, here is the proposal as I understand:
1: I2c bus device node:
1.a: For every bus registered, a default device is registered /dev/i2cbusX.
1.b: this will be done by enabling CHARDEV config
2: Device Nodes:
2.a: created only when CHARDEV config is enabled.
2.b: board files can optionally register default devices. That will appear
as: /dev/i2cbusX_Y where X=busID and Y=device address in hex.
2.c: new command i2cadd <options> -f /dev/i2cbusX -d device address in hex
Usage:
md /dev/i2cbusX will do i2cdetect. (writes and any other access will not be supported). In future when smbus is supported, what ever the bus's default feature is, that will be used. This will attempt a 0 byte read only. (What about buses on which we'd want to do detect based on 0 byte writes?).
devinfo /dev/i2cbusX will display i2c functionality.
i2cadd -f /dev/i2cbusX -d 0x49 will create /dev/i2cbusX_49
With default features: 8 bit reg access access, 8 bit data.
Other Options:
Register addressing: 8 or 16 bit
Anything else we can think of..
devinfo /dev/i2cbusX_Y will give device information.
md /dev/i2cbusX_Y will do the equivalent of i2cdump and i2cget
mm /dev/i2cbusX_Y will do the equivalent of i2cset.
The risk I see is in trying to do i2cdetect with equivalent of -q -
quick read. I don't have aneed for it, but does anyone else have?
Another risk in using generic commands.. folks are going to want
some custom feature and extension to the generic commands.. that
is a good thing, and something we can take in when the need comes.
md/mm might need further changes to handle access sizes.
Does this strategy work ok for eeproms?
The only negative I see is that folks need an additional command
to create a device node. Not too bad a tradeoff considering the
other stuff we could do..
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-20 16:28 ` Menon, Nishanth
@ 2008-06-23 7:39 ` Sascha Hauer
2008-06-23 13:29 ` Menon, Nishanth
0 siblings, 1 reply; 43+ messages in thread
From: Sascha Hauer @ 2008-06-23 7:39 UTC (permalink / raw)
To: u-boot
On Fri, Jun 20, 2008 at 11:28:52AM -0500, Menon, Nishanth wrote:
> Sascha,
>
> Summary: Ok, you sold the idea to me.
>
> > -----Original Message-----
> > From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> > Sent: Friday, June 20, 2008 10:17 AM
> > To: Menon, Nishanth
> > Cc: u-boot-users at lists.sourceforge.net
> > Subject: Re: [Patch 5/9]U-boot-V2:cmd: add I2C commands
> > +int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char
> > *buffer,
> > + size_t count)
> >
> > These arguments map nicely to md/mm
> Not exactly as of date (we can have register width as 16 bit and data width as 8 bit). But yeah, we can easily make md/mm do it. Yep, I have used md to dump nand and cp to write data.
Are you aware of device parameters? Well, you are, they are used for
setting the mac address and stuff like that. Maybe this would be a
possibility for the user to change the address width.
>
> > > What do we achieve by introducing i2c device based nodes?
> >
> > - An overview over the system for those who are not familiar with it.
> > You may know the devices that are connected to the bus on your board,
> > I don't. One of the benefits in U-Boot-V2 for me is that many different
> > systems behave similarly although they have a very different hardware.
> > - when md/mm are usable on a device it also means that cp/memcmp/cat or
> > any other file command is usable.
> > - reduction in code size since you can reuse what's already there (like
> > file commands instead of new commands). That's one of the points that
> > make U-Boot-V1 bigger than it has to be.
> Ok, getting down to implementation level, here is the proposal as I understand:
> 1: I2c bus device node:
> 1.a: For every bus registered, a default device is registered /dev/i2cbusX.
> 1.b: this will be done by enabling CHARDEV config
> 2: Device Nodes:
> 2.a: created only when CHARDEV config is enabled.
I don't think that this has to be dependent on an additional config
option. I mean, is there something sensible left when this option is
disabled?
> 2.b: board files can optionally register default devices. That will appear
> as: /dev/i2cbusX_Y where X=busID and Y=device address in hex.
> 2.c: new command i2cadd <options> -f /dev/i2cbusX -d device address in hex
I haven't thought that to the end, that was just an idea, but it looks
plausible. Please use 0 as base to simple_strtoul() so that the base is
determined by the prefix.
>
> Usage:
> md /dev/i2cbusX will do i2cdetect. (writes and any other access will not be supported). In future when smbus is supported, what ever the bus's default feature is, that will be used. This will attempt a 0 byte read only. (What about buses on which we'd want to do detect based on 0 byte writes?).
Hm, what should the output look like for 'md /dev/i2cbusX'? How about
another command:
i2cdetect -f /dev/i2cbusX
- try to detect slave devices on a bus and register them.
or maybe just 'i2cadd -d -f /dev/i2cbusX' (d for detect) instead of
another command.
>
> devinfo /dev/i2cbusX will display i2c functionality.
whereas devinfo /dev/i2cbusX_Y could show the access mode (7bit/10bit
addressing) and give the user a chance to change it.
>
> i2cadd -f /dev/i2cbusX -d 0x49 will create /dev/i2cbusX_49
> With default features: 8 bit reg access access, 8 bit data.
> Other Options:
> Register addressing: 8 or 16 bit
> Anything else we can think of..
>
> devinfo /dev/i2cbusX_Y will give device information.
>
> md /dev/i2cbusX_Y will do the equivalent of i2cdump and i2cget
>
> mm /dev/i2cbusX_Y will do the equivalent of i2cset.
>
> The risk I see is in trying to do i2cdetect with equivalent of -q -
> quick read. I don't have aneed for it, but does anyone else have?
> Another risk in using generic commands.. folks are going to want
> some custom feature and extension to the generic commands.. that
> is a good thing, and something we can take in when the need comes.
>
> md/mm might need further changes to handle access sizes.
It shouldn't need any changes, at least no i2c specific ones. If it
does, we did something wrong.
>
> Does this strategy work ok for eeproms?
Why not? When we have a eeprom slave driver together with a /dev/eepromX
device node, everything should be fine.
>
> The only negative I see is that folks need an additional command
> to create a device node.
Normally they wouldn't need it because mostly the board would register
all devices available on the system. This may not be true for your
board, but most boards I have only have an eeprom, a rtc and only a few
other devices connected to the i2c bus. It's not a big memory penalty to
register them.
Regards,
Sascha
--
Pengutronix e.K. - Linux Solutions for Science and Industry
-----------------------------------------------------------
Kontakt-Informationen finden Sie im Header dieser Mail oder
auf der Webseite -> http://www.pengutronix.de/impressum/ <-
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands
2008-06-23 7:39 ` Sascha Hauer
@ 2008-06-23 13:29 ` Menon, Nishanth
0 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-23 13:29 UTC (permalink / raw)
To: u-boot
Sascha,
> -----Original Message-----
> From: Sascha Hauer [mailto:s.hauer at pengutronix.de]
> Sent: Monday, June 23, 2008 2:40 AM
> To: Menon, Nishanth
> Cc: u-boot-users at lists.sourceforge.net
> Subject: Re: [Patch 5/9]U-boot-V2:cmd: add I2C commands
>
> Are you aware of device parameters? Well, you are, they are used for
> setting the mac address and stuff like that. Maybe this would be a
> possibility for the user to change the address width.
Oh yeah, that would work just perfectly for our needs. Probably
additional patches can add that functionality.
>
> I don't think that this has to be dependent on an additional config
> option. I mean, is there something sensible left when this option is
> disabled?
Look at the makefile -> i2c-core.c which provides the basic
Infrastructure(i2c_transfer) is retained. Not all configurations need
i2c-dev. It is merely a debug tool. It is good to isolate it out.
> I haven't thought that to the end, that was just an idea, but it looks
> plausible. Please use 0 as base to simple_strtoul() so that the base is
> determined by the prefix.
I recommend a step by step approach, lets add features to the patches I
Proposed in a phased manner. Do comment on the patch(try2 and 3) I have send.
> Hm, what should the output look like for 'md /dev/i2cbusX'? How about
Do check the dox comments in patch try2/3. I have given a sample output.
> another command:
>
> i2cdetect -f /dev/i2cbusX
> - try to detect slave devices on a bus and register them.
This would be redundant. md command just works fine.
>
> or maybe just 'i2cadd -d -f /dev/i2cbusX' (d for detect) instead of
> another command.
This is a possible direction we could take, but -d will basically add
i2cdetect feature when none is required at the moment.
> whereas devinfo /dev/i2cbusX_Y could show the access mode (7bit/10bit
> addressing) and give the user a chance to change it.
We can add more information in show_info. Register width, data width being
The few of them. Current patches don't have that support, but is easy to
Introduce when we need them.
> It shouldn't need any changes, at least no i2c specific ones. If it
> does, we did something wrong.
Yes, I agree.
>
> >
> > The only negative I see is that folks need an additional command
> > to create a device node.
>
> Normally they wouldn't need it because mostly the board would register
> all devices available on the system. This may not be true for your
> board, but most boards I have only have an eeprom, a rtc and only a few
> other devices connected to the i2c bus. It's not a big memory penalty to
> register them.
>
Yes, you are right.
The current patches I have send provide the basic framework, all things we
Discussed above can be added in phases as our needs come in.
Regards,
Nishanth Menon
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 4/9 Try 2]U-boot-V2:I2C: Introduce i2c-dev
2008-06-20 15:16 ` Sascha Hauer
2008-06-20 16:28 ` Menon, Nishanth
@ 2008-06-21 2:34 ` Menon, Nishanth
2008-06-24 8:05 ` Sascha Hauer
2008-06-21 2:34 ` [U-Boot-Users] [Patch 5/9 Try2]U-boot-V2:cmd: add I2C commands Menon, Nishanth
2 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-21 2:34 UTC (permalink / raw)
To: u-boot
I2C by default does not expose a device interface
for the adapters registering in the system. This
is usually not needed unless we need to debug
something. in which case, this is a handy little
layer when used in conjunction with the i2c
commands. This layer has changed
This is based on the discussion here:
http://www.nabble.com/-Patch-0-9--U-boot-V2%3A-
Introduce-I2C-support-for-SDP3430-to17981717.html
#a18029740
Patches 4 and 5 in the previous series have
changed, 6 is redundant and removed from the
series.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
drivers/i2c/Kconfig | 10
drivers/i2c/Makefile | 1
drivers/i2c/i2c-core.c | 12
drivers/i2c/i2c-core.h | 4
drivers/i2c/i2c-dev.c | 813 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-dev.h | 43 ++
6 files changed, 883 insertions(+)
Index: u-boot-v2.git/include/linux/i2c-dev.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/i2c-dev.h 2008-06-20 21:09:57.000000000 -0500
@@ -0,0 +1,43 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: include/linux/i2c-dev.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LINUX_I2C_DEV_H
+#define _LINUX_I2C_DEV_H
+
+/* For command access */
+#define I2C_SLAVE_ADD 0x0703 /* Create a new slave device */
+#define I2C_SLAVE_REM 0x0706 /* Remove a new slave device */
+
+/******* For the platforms to use *********/
+int i2cdev_new(unsigned int, unsigned int);
+int i2cdev_remove(unsigned int, unsigned int);
+
+#endif /* _LINUX_I2C_DEV_H */
Index: u-boot-v2.git/drivers/i2c/i2c-dev.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/i2c-dev.c 2008-06-20 21:16:25.000000000 -0500
@@ -0,0 +1,813 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: drivers/i2c/i2c-dev.c
+ *
+ * It is very important to note the following:
+ * read to an i2cbus device is a 0 byte read operation. writes
+ * are not supported to i2cbus device.
+ *
+ * i2cdev devices on the other hand translate all read/write to
+ * 1 byte read/write operations as per i2c spec.
+ *
+ * Note: both of these can confuse certain devices on I2C bus.
+ * USE WITH CAUTION.
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * Note: even though we borrow i2c-dev from linux, there are
+ * major differences in operations.
+ *
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+ But I have used so much of his original code and ideas that it seems
+ only fair to recognize him as co-author -- Frodo */
+
+#include <common.h>
+#include <errno.h>
+#include <list.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "i2c-core.h"
+
+#ifdef CONFIG_I2C_DEBUG_DEV
+#define DBG_MODULE_NAME "i2cdev"
+#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
+#define dev_warn(ARGS...) fprintf(stderr, ARGS);
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#else
+#define dev_dbg(ARGS...)
+#define dev_warn(ARGS...)
+#define dbg_entry(FORMAT, ARGS...)
+#define dbg_exit(FORMAT, ARGS...)
+#endif
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+#define I2C_BUS_NAME "i2cbus"
+#define I2C_DEV_NAME "i2cdev"
+
+static struct i2c_driver i2cdev_driver;
+
+/**
+ * An i2c_bus represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ */
+struct i2cdev_bus {
+ struct list_head list;
+ struct i2c_adapter *adap;
+ struct device_d dev;
+};
+
+/**
+ * contains the internal structure for a device node this is the i2c device
+ */
+struct i2cdev_dev {
+ struct list_head list;
+ struct device_d dev;
+};
+
+#define I2C_MINORS 256
+static LIST_HEAD(i2c_bus_list);
+static LIST_HEAD(i2c_dev_list);
+
+/** A structure to store the various functions supported by the adapter */
+struct func {
+ long value;
+ const char *name;
+};
+static const struct func all_func[] = {
+ {.value = I2C_FUNC_I2C,
+ .name = "I2C"},
+ {.value = 0,
+ .name = ""}
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief search and get a bus given a bus adapter index.
+ *
+ * @param index adapter index
+ *
+ * @return bus node if found
+ */
+static struct i2cdev_bus *i2c_bus_get_by_minor(unsigned index)
+{
+ struct i2cdev_bus *i2cdev_bus;
+
+ dbg_entry("index=%x", index);
+
+ list_for_each_entry(i2cdev_bus, &i2c_bus_list, list) {
+ if (i2cdev_bus->adap->nr == index)
+ goto found;
+ }
+ i2cdev_bus = NULL;
+found:
+ return i2cdev_bus;
+}
+
+/**
+ * @brief get a free i2cbus node
+ * allocates memory and links up to bus node list.
+ *
+ * @param adap adapter to allocate a node for
+ *
+ * @return if success, return node, else NULL
+ */
+static struct i2cdev_bus *get_free_i2c_bus(struct i2c_adapter *adap)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ dbg_entry("adap=%x", (u32) adap);
+
+ if (adap->nr >= I2C_MINORS) {
+ dev_err("i2c-dev: Out of device minors (%d)\n", adap->nr);
+ return NULL;
+ }
+
+ i2cdev_bus = calloc(1, sizeof(*i2cdev_bus));
+ if (!i2cdev_bus)
+ return NULL;
+ i2cdev_bus->adap = adap;
+
+ list_add_tail(&i2cdev_bus->list, &i2c_bus_list);
+ return i2cdev_bus;
+}
+
+/**
+ * @brief releases the i2cdev_bus list.
+ *
+ * @param i2cdev_bus item to be released
+ *
+ * @return none
+ */
+static void return_i2c_bus(struct i2cdev_bus *i2cdev_bus)
+{
+ dbg_entry("i2cdev_bus=%x", (u32) i2cdev_bus);
+ list_del(&i2cdev_bus->list);
+ free(i2cdev_bus);
+}
+
+/**
+ * @brief tiny little helper to check if address is proper.
+ *
+ * @param dev device node
+ * @param addrp address
+ *
+ * @return 0 is no driver already linked, else -EBUSY
+ */
+static int i2cdev_check(struct device_d *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+
+ dbg_entry("dev=%x addrp=%x", (u32) dev, (u32) addrp);
+ if (!client || client->addr != *(unsigned int *)addrp)
+ return 0;
+
+ return dev->driver ? -EBUSY : 0;
+}
+
+/**
+ * @brief This address checking function differs from the one in i2c-core
+ * in that it considers an address with a registered device, but no driver
+ * bound to it, as NOT busy.
+ *
+ * @param adapter adapter to attach to
+ * @param addr device address
+ *
+ * @return device present or not.
+ */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+ int ret = 0;
+ struct device_d *child;
+ dbg_entry("adapter=%x addr=%x", (u32) adapter, (u32) addr);
+ device_for_each_child((&(adapter->dev)), child) {
+ ret = i2cdev_check(child, &addr);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief read function for a bus.
+ *
+ * This allows for a functionality like i2cdetect.
+ * Offset of each byte corresponds to the device address
+ * each offset without a device will be set with 0xFF indicating empty.
+ * (This is coz 0x0 is a valid address..)
+ * any offset with data will have that address filled with corresponding dev
+ * address
+ *
+ * @param dev bus device.
+ * @param buffer buffer to return data
+ * @param count bytes to read
+ * @param offset device address
+ * @param flags any special flags?
+ *
+ * @return reult of operation
+ */
+static ssize_t i2cbus_read(struct device_d *dev, void *buffer, size_t count,
+ ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ unsigned char addr = 0;
+ unsigned char reg_address = 0;
+ unsigned char tmp = 0;
+ char *buf = (char *)buffer;
+ int idx = 0;
+ struct i2c_msg msgs[2] = {
+ {0, 0, 1, &addr},
+ /* Attempt a 0 byte read */
+ {0, 0 | I2C_M_RD, 0, &tmp}
+ };
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+
+ if (offset > dev->size) {
+ dev_err("Request=%d size=%d!\n", offset, dev->size);
+ return -EINVAL;
+ }
+ count = min(count, dev->size - offset);
+ /* Set all defaults to 0xFF */
+ memset(buf, 0xFF, count);
+ while (idx < count) {
+ reg_address = (unsigned char)offset + idx;
+ msgs[0].addr = msgs[1].addr = reg_address;
+
+ /* is this address being used? */
+ if (!i2cdev_check_addr(client->adapter, reg_address)) {
+ /* No client driver? aha! we shalt access thee! */
+ if (i2c_transfer(client->adapter, msgs, 2) >= 0)
+ *buf = reg_address;
+ } else
+ /* Client driver present.. probable that device exists!
+ * we dare not access it though :( - dunno how it's
+ * gonna behave
+ */
+ *buf = reg_address;
+ buf++;
+ idx++;
+ }
+ return idx;
+}
+
+/**
+ * @brief display a short summary of the adapter
+ *
+ * @param dev -dev
+ *
+ * @return none
+ */
+static void i2cbus_shortinfo(struct device_d *dev)
+{
+ struct i2c_adapter *adap;
+ struct i2cdev_bus *i2cdev_bus;
+ i2cdev_bus = i2c_bus_get_by_minor(dev->map_base);
+ if (!i2cdev_bus) {
+ dev_err("did not get bus\n");
+ return;
+ }
+ adap = i2c_get_adapter(i2cdev_bus->adap->nr);
+ if (!adap) {
+ dev_err("No such adapter!\n");
+ return;
+ }
+ fprintf(stdout, "Adapter Name: %s\n", adap->name);
+}
+
+/**
+ * @brief show detailed info of the adapter
+ *
+ * @param dev system dev
+ *
+ * @return none
+ */
+static void i2cbus_showinfo(struct device_d *dev)
+{
+ struct i2c_adapter *adap;
+ struct i2cdev_bus *i2cdev_bus;
+ unsigned long funcs;
+ int i;
+ i2cdev_bus = i2c_bus_get_by_minor(dev->map_base);
+ if (!i2cdev_bus) {
+ dev_err("did not get bus\n");
+ return;
+ }
+ adap = i2c_get_adapter(i2cdev_bus->adap->nr);
+ if (!adap) {
+ dev_err("No such adapter!\n");
+ return;
+ }
+ /* Display basic info */
+ fprintf(stdout,
+ "Adapter Name: %s\n"
+ "Adapter ID : %d\n"
+ "Adapter Nr : %d\n"
+ "Has Algo? : %s\n"
+ "Timeout : %d\n"
+ "Retries : %d\n"
+ "----------------\n"
+ "Functionalities:\n",
+ adap->name,
+ adap->id,
+ adap->nr,
+ (adap->algo) ? "yes" : "no", adap->timeout, adap->retries);
+
+ funcs = i2c_get_functionality(i2cdev_bus->adap);
+ for (i = 0; all_func[i].value; i++) {
+ fprintf(stdout, "%-32s %s\n", all_func[i].name,
+ (funcs & all_func[i].value) ? "yes" : "no");
+ }
+
+}
+
+/**
+ * @brief ioctls for the bus
+ *
+ * @param dev system dev
+ * @param cmd
+ * @param argument
+ *
+ * @return ioctl result
+ */
+static int i2cbus_ioctl(struct device_d *dev, int cmd, void *argument)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ unsigned long arg = (unsigned long)argument;
+ int ret = 0;
+ dbg_entry("dev=%x cmd=%x arg=%x", (u32) dev, (u32) cmd, (u32) arg);
+
+ if (arg > 0x7f) {
+ fprintf(stderr, "arg %x>0x7f\n", arg);
+ return -EINVAL;
+ }
+ switch (cmd) {
+ case I2C_SLAVE_ADD:
+ if (i2cdev_check_addr(client->adapter, arg)) {
+ fprintf(stderr, "client on address\n");
+ return -EBUSY;
+ }
+ ret = i2cdev_new(client->adapter->nr, arg);
+ break;
+ case I2C_SLAVE_REM:
+ /* we dont attach to normal i2c client struct..
+ * so call our integral search func */
+ ret = i2cdev_remove(client->adapter->nr, arg);
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+ return ret;
+}
+
+/**
+ * @brief open a bus device
+ *
+ * @param dev system dev
+ * @param file
+ *
+ * @return open success or not
+ */
+static int i2cbus_open(struct device_d *dev, struct filep *file)
+{
+ struct i2c_client *client;
+ struct i2c_adapter *adap;
+ struct i2cdev_bus *i2cdev_bus;
+ unsigned long funcs;
+
+ dbg_entry("dev=%x file=%x", (u32) dev, (u32) file);
+ i2cdev_bus = i2c_bus_get_by_minor(dev->map_base);
+ if (!i2cdev_bus) {
+ dev_err("did not get bus\n");
+ return -ENODEV;
+ }
+
+ adap = i2c_get_adapter(i2cdev_bus->adap->nr);
+ if (!adap) {
+ dev_err("No such device!\n");
+ return -ENODEV;
+ }
+
+ /* Check i2c functionality */
+ funcs = i2c_get_functionality(i2cdev_bus->adap);
+
+ if (!(funcs & I2C_FUNC_I2C)) {
+ dev_err("I2C support is missing!");
+ return -EINVAL;
+ }
+
+ /* This creates an anonymous i2c_client, which may later be
+ * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
+ *
+ * This client is ** NEVER REGISTERED ** with the driver model
+ * or I2C core code!! It just holds private copies of addressing
+ * information and maybe a PEC flag.
+ */
+ client = calloc(1, sizeof(*client));
+ if (!client) {
+ i2c_put_adapter(adap);
+ return -ENOMEM;
+ }
+ sprintf(client->name, "i2c-bus %d", adap->nr);
+ /* Attach a dummy driver */
+ client->driver = &i2cdev_driver;
+
+ client->adapter = adap;
+ dev->priv = client;
+
+ return 0;
+}
+
+/**
+ * @brief done using the bus device. now release it.
+ *
+ * @param dev system dev
+ * @param file
+ *
+ * @return
+ */
+static int i2cbus_release(struct device_d *dev, struct filep *file)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+
+ dbg_entry("dev=%x file=%x, client=%x", (u32) dev, (u32) file,
+ (u32) client);
+ i2c_put_adapter(client->adapter);
+ free(client);
+ dev->priv = NULL;
+
+ return 0;
+}
+
+static struct driver_d i2cbus_fops = {
+ .name = I2C_BUS_NAME,
+ .probe = dummy_probe,
+ .ioctl = i2cbus_ioctl,
+ .read = i2cbus_read,
+ .lseek = dev_lseek_default,
+ .open = i2cbus_open,
+ .remove = dummy_probe,
+ .close = i2cbus_release,
+ .info = i2cbus_showinfo,
+ .shortinfo = i2cbus_shortinfo,
+ .type = DEVICE_TYPE_I2CDEV,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief read an i2cdev device ->byte by byte.. no multibyte reads..
+ *
+ * @param dev device
+ * @param buffer data buffer to put data
+ * @param count how much data to read
+ * @param offset which offset to get data
+ * @param flags the usual
+ *
+ * @return operation result
+ */
+static ssize_t i2cdev_read(struct device_d *dev, void *buffer, size_t count,
+ ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ char *buf = (char *)buffer;
+ int ret;
+ int idx = 0;
+ char dev_offset = (char)offset;
+ /* it is simpler to do a multibyte read, but that would not work
+ * on all devices. */
+ struct i2c_msg msgs[2] = {
+ /* register address */
+ {client->addr, 0, 1, &dev_offset},
+ /* Attempt a 0 byte read */
+ {client->addr, 0 | I2C_M_RD, 1, NULL}
+ };
+ dbg_entry
+ ("dev=%x buffer=%x count=%x offset=%x flags=%x client=%x addr=%x",
+ (u32) dev, (u32) buffer, (u32) count, (u32) offset, (u32) flags,
+ (u32) client, client->addr);
+ count = min(count, dev->size - offset);
+ while (idx < count) {
+ msgs[1].buf = buf;
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret <= 0)
+ return ret;
+ buf++;
+ idx++;
+ dev_offset++;
+ }
+ return idx;
+}
+
+/**
+ * @brief write to an i2cdev device ->byte by byte.. no multibyte writes..
+ *
+ * @param dev device
+ * @param buffer data buffer to take data
+ * @param count how much data to write
+ * @param offset which offset to put data
+ * @param flags the usual
+ *
+ * @return operation result
+ */
+static ssize_t i2cdev_write(struct device_d *dev, const void *buffer,
+ size_t count, ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ char *buf = (char *)buffer;
+ int ret;
+ int idx = 0;
+ char buff[2];
+ /* it is simpler to do a multibyte write, but that would not work
+ * on all devices. */
+ struct i2c_msg msgs[1] = {
+ /* register address and data go together */
+ {client->addr, 0, 2, buff},
+ };
+
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+
+ count = min(count, dev->size - offset);
+ while (idx < count) {
+ buff[0] = (char)(offset + idx);
+ buff[1] = *buf;
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret <= 0)
+ return ret;
+ buf++;
+ idx++;
+ }
+ return idx;
+}
+
+/**
+ * @brief open the device
+ * we reuse most of i2cbus open functionality here.
+ * we use the i2cbus release function to get rid of the device
+ *
+ * @param dev dev
+ * @param file file
+ *
+ * @return result value
+ */
+static int i2cdev_open(struct device_d *dev, struct filep *file)
+{
+ int ret;
+ struct i2c_client *client;
+ unsigned int addr = (unsigned int)dev->platform_data;
+ /* All the stuff we want checked and done is done in bus!
+ * reuse it! */
+ ret = i2cbus_open(dev, file);
+ if (ret)
+ return ret;
+
+ /* retrieve the client and customize a few things */
+ client = (struct i2c_client *)dev->priv;
+ client->addr = (unsigned short)(addr);
+ sprintf(client->name, "i2cdev_%x_%x", client->adapter->nr,
+ client->addr);
+
+ return 0;
+}
+
+/**
+ * @brief Do a device probe. if there are other client drivers, we will not
+ * hook on.
+ * Note:
+ * dev->platform_data contains device address
+ * dev->map_base contains adapter index
+ *
+ * @param dev dev
+ *
+ * @return 0 if all things ok, else -EINVAL or error val
+ */
+static int i2cdev_probe(struct device_d *dev)
+{
+ unsigned int addr = (unsigned int)dev->platform_data;
+ unsigned int adap_nr = (unsigned int)dev->map_base;
+ struct i2c_adapter *adap;
+ int ret;
+ adap = i2c_get_adapter(adap_nr);
+ if (!adap) {
+ dev_err("Adapter %d not found!\n");
+ return -EINVAL;
+ }
+
+ /* if some other client driver exists.. we will not hook on! */
+ ret = i2cdev_check_addr(adap, addr);
+ /* return the adapter */
+ i2c_put_adapter(adap);
+
+ return ret;
+}
+
+static struct driver_d i2cdev_fops = {
+ .name = I2C_DEV_NAME,
+ .probe = i2cdev_probe,
+ .remove = dummy_probe,
+ .read = i2cdev_read,
+ .write = i2cdev_write,
+ .lseek = dev_lseek_default,
+ .open = i2cdev_open,
+ .close = i2cbus_release,
+ .type = DEVICE_TYPE_I2CDEV,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief attach a new adapter to the device architecture
+ *
+ * @param adap adapter name
+ *
+ * @return
+ */
+int i2cdev_attach_adapter(struct i2c_adapter *adap)
+{
+ struct device_d *dev;
+ struct i2cdev_bus *i2cdev_bus;
+ int res;
+ dbg_entry("adap=%x", (u32) adap);
+ i2cdev_bus = get_free_i2c_bus(adap);
+ if (!i2cdev_bus) {
+ dev_err("Did not get free dev-adap %d\n", adap->nr);
+ return -ENOMEM;
+ }
+ dev = &i2cdev_bus->dev;
+ /* Store my adapter number in mapbase for retrieval */
+ dev->map_base = adap->nr;
+ dev->size = 0x80;
+ /* my i2cdev type */
+ sprintf((char *)&dev->name, "%s", I2C_BUS_NAME);
+ sprintf((char *)&dev->id, "%s%d", I2C_BUS_NAME, adap->nr);
+ dev->type = DEVICE_TYPE_I2CDEV;
+
+ res = register_device(dev);
+ if (res < 0) {
+ dev_err("Device %d registration failed %d\n", adap->nr, res);
+ perror(dev->id);
+ return_i2c_bus(i2cdev_bus);
+ return res;
+ }
+ return res;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
+
+/**
+ * @brief detach the adapter from the device tree
+ *
+ * @param adap -adapter
+ *
+ * @return result
+ */
+int i2cdev_detach_adapter(struct i2c_adapter *adap)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ int ret = 0;
+ dbg_entry("adap=%x", (u32) adap);
+ i2cdev_bus = i2c_bus_get_by_minor(adap->nr);
+ if (!i2cdev_bus) {
+ dev_err("not registered adapter %d with me!\n", adap->nr);
+ return -ENODEV;
+ }
+ ret = unregister_device(&(i2cdev_bus->dev));
+ if (ret) {
+ dev_err("Adapter %d dev is in use(%d)?\n", adap->nr, ret);
+ return ret;
+ }
+ if (i2cdev_bus)
+ return_i2c_bus(i2cdev_bus);
+ return ret;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
+
+/**
+ * @brief attach a new device to the device tree
+ *
+ * @param adapter_number adapter number
+ * @param device_address device address
+ *
+ * @return -result
+ */
+int i2cdev_new(unsigned int adapter_number, unsigned int device_address)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ struct device_d *dev;
+ struct i2cdev_dev *d;
+ int res;
+
+ i2cdev_bus = i2c_bus_get_by_minor(adapter_number);
+ if (!i2cdev_bus) {
+ dev_err("not registered adapter %d with me!\n", adapter_number);
+ return -ENODEV;
+ }
+ d = calloc(1, sizeof(*d));
+ if (!d) {
+ dev_err("unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ dev = &d->dev;
+ /* Store my adapter number in mapbase for retrieval */
+ dev->map_base = adapter_number,
+ dev->platform_data = (void *)device_address;
+ dev->size = 256;
+ /* my i2cdev type */
+ sprintf((char *)&dev->name, "%s", I2C_DEV_NAME);
+ sprintf((char *)&dev->id, "%s%d_%x", I2C_BUS_NAME, adapter_number,
+ device_address);
+ dev->type = DEVICE_TYPE_I2CDEV;
+ res = register_device(dev);
+ if (res < 0) {
+ dev_err("Bus %d Device 0x%x registration failed %d\n",
+ adapter_number, device_address, res);
+ perror(dev->id);
+ free(d);
+ return res;
+ }
+ list_add_tail(&d->list, &i2c_dev_list);
+ return res;
+}
+EXPORT_SYMBOL(i2cdev_new);
+
+/**
+ * @brief remove the device
+ *
+ * @param adapter_number adapter numbe adapter numberr
+ * @param device_address device address
+ *
+ * @return -ENODEV if there is no such device in the system
+ */
+int i2cdev_remove(unsigned int adapter_number, unsigned int device_address)
+{
+ struct device_d *dev;
+ struct i2cdev_dev *d;
+ char id[MAX_DRIVER_NAME];
+ sprintf(id, "%s%d_%x", I2C_BUS_NAME, adapter_number, device_address);
+ list_for_each_entry(d, &i2c_dev_list, list) {
+ if (!strcmp(d->dev.id, id))
+ goto found;
+ }
+ return -ENODEV;
+found:
+ dev = &d->dev;
+ unregister_device(dev);
+ list_del(&d->list);
+ free(d);
+ return 0;
+}
+EXPORT_SYMBOL(i2cdev_remove);
+
+/* ------------------------------------------------------------------------- */
+
+static int i2cdev_init(void)
+{
+
+ int res = 0;
+ dbg_entry("%s", "none");
+ res = register_driver(&i2cbus_fops);
+ if (res)
+ return res;
+ res = register_driver(&i2cdev_fops);
+ dbg_exit("res=%d", res);
+ return res;
+}
+device_initcall(i2cdev_init);
Index: u-boot-v2.git/drivers/i2c/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Kconfig 2008-06-20 21:09:55.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Kconfig 2008-06-20 21:09:57.000000000 -0500
@@ -19,6 +19,16 @@
if I2C
+config I2C_CHARDEV
+ tristate "I2C device interface"
+ help
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have applications
+ to use the I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-dev.
+
source drivers/i2c/busses/Kconfig
config I2C_DEBUG_CORE
Index: u-boot-v2.git/drivers/i2c/Makefile
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Makefile 2008-06-20 21:09:55.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Makefile 2008-06-20 21:09:57.000000000 -0500
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
Index: u-boot-v2.git/drivers/i2c/i2c-core.c
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.c 2008-06-20 21:09:55.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.c 2008-06-20 21:09:57.000000000 -0500
@@ -102,6 +102,10 @@
dev_dbg("adapter [%s] registered\n", adap->name);
+#ifdef CONFIG_I2C_CHARDEV
+ i2cdev_attach_adapter(adap);
+#endif
+
out_unlock:
return res;
@@ -222,6 +226,14 @@
goto out_unlock;
}
+#ifdef CONFIG_I2C_CHARDEV
+ res = i2cdev_detach_adapter(adap);
+ if (res) {
+ dev_err("adapter in use\n");
+ goto out_unlock;
+ }
+#endif
+
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
Index: u-boot-v2.git/drivers/i2c/i2c-core.h
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.h 2008-06-20 21:09:55.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.h 2008-06-20 21:09:57.000000000 -0500
@@ -34,4 +34,8 @@
extern struct list_head __i2c_board_list;
extern int __i2c_first_dynamic_bus_num;
+/* Automatically called by i2c-Core..*/
+int i2cdev_attach_adapter(struct i2c_adapter *adap);
+int i2cdev_detach_adapter(struct i2c_adapter *adap);
+
#endif /* __i2C_CORE_H */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 4/9 Try 2]U-boot-V2:I2C: Introduce i2c-dev
2008-06-21 2:34 ` [U-Boot-Users] [Patch 4/9 Try 2]U-boot-V2:I2C: Introduce i2c-dev Menon, Nishanth
@ 2008-06-24 8:05 ` Sascha Hauer
2008-06-25 1:48 ` [U-Boot-Users] [Patch 4/9 Try 3]U-boot-V2:I2C: " Menon, Nishanth
0 siblings, 1 reply; 43+ messages in thread
From: Sascha Hauer @ 2008-06-24 8:05 UTC (permalink / raw)
To: u-boot
On Fri, Jun 20, 2008 at 09:34:47PM -0500, Menon, Nishanth wrote:
> I2C by default does not expose a device interface
> for the adapters registering in the system. This
> is usually not needed unless we need to debug
> something. in which case, this is a handy little
> layer when used in conjunction with the i2c
> commands. This layer has changed
>
> This is based on the discussion here:
> http://www.nabble.com/-Patch-0-9--U-boot-V2%3A-
> Introduce-I2C-support-for-SDP3430-to17981717.html
> #a18029740
>
> Patches 4 and 5 in the previous series have
> changed, 6 is redundant and removed from the
> series.
>
> Signed-off-by: Nishanth Menon <x0nishan@ti.com>
>
> ---
> drivers/i2c/Kconfig | 10
> drivers/i2c/Makefile | 1
> drivers/i2c/i2c-core.c | 12
> drivers/i2c/i2c-core.h | 4
> drivers/i2c/i2c-dev.c | 813 ++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/i2c-dev.h | 43 ++
> 6 files changed, 883 insertions(+)
>
> Index: u-boot-v2.git/include/linux/i2c-dev.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ u-boot-v2.git/include/linux/i2c-dev.h 2008-06-20 21:09:57.000000000 -0500
> @@ -0,0 +1,43 @@
> +/**
> + * @file
> + * @brief i2c-bus driver, "char device" interface
> + *
> + * FileName: include/linux/i2c-dev.h
> + *
> + */
> +/* Originally from Linux kernel. Ported to U-boot-v2.
> + * (C) Copyright 2008
> + * Texas Instruments, <www.ti.com>
> + * Nishanth Menon <x0nishan@ti.com>
> + */
> +/*
> + Copyright (C) 1995-97 Simon G. Vogl
> + Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +*/
> +
> +#ifndef _LINUX_I2C_DEV_H
> +#define _LINUX_I2C_DEV_H
> +
> +/* For command access */
> +#define I2C_SLAVE_ADD 0x0703 /* Create a new slave device */
> +#define I2C_SLAVE_REM 0x0706 /* Remove a new slave device */
> +
> +/******* For the platforms to use *********/
> +int i2cdev_new(unsigned int, unsigned int);
> +int i2cdev_remove(unsigned int, unsigned int);
> +
> +#endif /* _LINUX_I2C_DEV_H */
> Index: u-boot-v2.git/drivers/i2c/i2c-dev.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ u-boot-v2.git/drivers/i2c/i2c-dev.c 2008-06-20 21:16:25.000000000 -0500
> @@ -0,0 +1,813 @@
> +/**
> + * @file
> + * @brief i2c-bus driver, "char device" interface
> + *
> + * FileName: drivers/i2c/i2c-dev.c
> + *
> + * It is very important to note the following:
> + * read to an i2cbus device is a 0 byte read operation. writes
> + * are not supported to i2cbus device.
> + *
> + * i2cdev devices on the other hand translate all read/write to
> + * 1 byte read/write operations as per i2c spec.
> + *
> + * Note: both of these can confuse certain devices on I2C bus.
> + * USE WITH CAUTION.
> + */
> +/* Originally from Linux kernel. Ported to U-boot-v2.
> + * Note: even though we borrow i2c-dev from linux, there are
> + * major differences in operations.
> + *
> + * (C) Copyright 2008
> + * Texas Instruments, <www.ti.com>
> + * Nishanth Menon <x0nishan@ti.com>
> + */
> +/*
> + Copyright (C) 1995-97 Simon G. Vogl
> + Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
> + Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +*/
> +
> +/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
> + But I have used so much of his original code and ideas that it seems
> + only fair to recognize him as co-author -- Frodo */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <list.h>
> +#include <init.h>
> +#include <driver.h>
> +#include <malloc.h>
> +#include <string.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-dev.h>
> +
> +#include "i2c-core.h"
> +
> +#ifdef CONFIG_I2C_DEBUG_DEV
> +#define DBG_MODULE_NAME "i2cdev"
> +#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
> +#define dev_warn(ARGS...) fprintf(stderr, ARGS);
> +#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
> + DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
> + __func__, __LINE__, ARGS)
> +#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
> + DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
> + __func__, __LINE__, ARGS)
> +#else
> +#define dev_dbg(ARGS...)
> +#define dev_warn(ARGS...)
> +#define dbg_entry(FORMAT, ARGS...)
> +#define dbg_exit(FORMAT, ARGS...)
> +#endif
> +#define dev_err(ARGS...) fprintf(stderr, ARGS);
Note to self: We need a better set of debug macros. debug is ok, but the
name is poorly chosen and not sufficient. Drivers shouldn't add their
own macros.
> +
> +#define I2C_BUS_NAME "i2cbus"
> +#define I2C_DEV_NAME "i2cdev"
> +
> +static struct i2c_driver i2cdev_driver;
> +
> +/**
> + * An i2c_bus represents an i2c_adapter ... an I2C or SMBus master, not a
> + * slave (i2c_client) with which messages will be exchanged. It's coupled
> + * with a character special file which is accessed by user mode drivers.
> + *
> + */
> +struct i2cdev_bus {
> + struct list_head list;
> + struct i2c_adapter *adap;
> + struct device_d dev;
> +};
> +
> +/**
> + * contains the internal structure for a device node this is the i2c device
> + */
> +struct i2cdev_dev {
> + struct list_head list;
> + struct device_d dev;
> +};
> +
> +#define I2C_MINORS 256
This seems to be an artificial limitation.
> +static LIST_HEAD(i2c_bus_list);
> +static LIST_HEAD(i2c_dev_list);
> +
> +/** A structure to store the various functions supported by the adapter */
> +struct func {
> + long value;
> + const char *name;
> +};
> +static const struct func all_func[] = {
> + {.value = I2C_FUNC_I2C,
> + .name = "I2C"},
> + {.value = 0,
> + .name = ""}
> +};
> +
> +/* ------------------------------------------------------------------------- */
> +
> +/**
> + * @brief search and get a bus given a bus adapter index.
> + *
> + * @param index adapter index
> + *
> + * @return bus node if found
> + */
> +static struct i2cdev_bus *i2c_bus_get_by_minor(unsigned index)
> +{
Better get_by_bus_id()?
> + struct i2cdev_bus *i2cdev_bus;
> +
> + dbg_entry("index=%x", index);
> +
> + list_for_each_entry(i2cdev_bus, &i2c_bus_list, list) {
> + if (i2cdev_bus->adap->nr == index)
> + goto found;
> + }
> + i2cdev_bus = NULL;
> +found:
> + return i2cdev_bus;
> +}
> +
> +/**
> + * @brief get a free i2cbus node
> + * allocates memory and links up to bus node list.
> + *
> + * @param adap adapter to allocate a node for
> + *
> + * @return if success, return node, else NULL
> + */
> +static struct i2cdev_bus *get_free_i2c_bus(struct i2c_adapter *adap)
> +{
> + struct i2cdev_bus *i2cdev_bus;
> + dbg_entry("adap=%x", (u32) adap);
> +
> + if (adap->nr >= I2C_MINORS) {
> + dev_err("i2c-dev: Out of device minors (%d)\n", adap->nr);
> + return NULL;
> + }
> +
> + i2cdev_bus = calloc(1, sizeof(*i2cdev_bus));
> + if (!i2cdev_bus)
> + return NULL;
> + i2cdev_bus->adap = adap;
> +
> + list_add_tail(&i2cdev_bus->list, &i2c_bus_list);
> + return i2cdev_bus;
> +}
> +
> +/**
> + * @brief releases the i2cdev_bus list.
> + *
> + * @param i2cdev_bus item to be released
> + *
> + * @return none
> + */
> +static void return_i2c_bus(struct i2cdev_bus *i2cdev_bus)
> +{
> + dbg_entry("i2cdev_bus=%x", (u32) i2cdev_bus);
> + list_del(&i2cdev_bus->list);
> + free(i2cdev_bus);
> +}
> +
> +/**
> + * @brief tiny little helper to check if address is proper.
> + *
> + * @param dev device node
> + * @param addrp address
> + *
> + * @return 0 is no driver already linked, else -EBUSY
> + */
> +static int i2cdev_check(struct device_d *dev, void *addrp)
> +{
> + struct i2c_client *client = i2c_verify_client(dev);
> +
> + dbg_entry("dev=%x addrp=%x", (u32) dev, (u32) addrp);
> + if (!client || client->addr != *(unsigned int *)addrp)
> + return 0;
> +
> + return dev->driver ? -EBUSY : 0;
> +}
> +
> +/**
> + * @brief This address checking function differs from the one in i2c-core
> + * in that it considers an address with a registered device, but no driver
> + * bound to it, as NOT busy.
> + *
> + * @param adapter adapter to attach to
> + * @param addr device address
> + *
> + * @return device present or not.
> + */
> +static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
> +{
> + int ret = 0;
> + struct device_d *child;
> + dbg_entry("adapter=%x addr=%x", (u32) adapter, (u32) addr);
> + device_for_each_child((&(adapter->dev)), child) {
> + ret = i2cdev_check(child, &addr);
> + if (ret)
> + break;
> + }
> + return ret;
> +}
> +
> +/* ------------------------------------------------------------------------- */
> +
> +/**
> + * @brief read function for a bus.
> + *
> + * This allows for a functionality like i2cdetect.
> + * Offset of each byte corresponds to the device address
> + * each offset without a device will be set with 0xFF indicating empty.
> + * (This is coz 0x0 is a valid address..)
> + * any offset with data will have that address filled with corresponding dev
> + * address
> + *
> + * @param dev bus device.
> + * @param buffer buffer to return data
> + * @param count bytes to read
> + * @param offset device address
> + * @param flags any special flags?
> + *
> + * @return reult of operation
> + */
> +static ssize_t i2cbus_read(struct device_d *dev, void *buffer, size_t count,
> + ulong offset, ulong flags)
> +{
> + struct i2c_client *client = (struct i2c_client *)dev->priv;
> + unsigned char addr = 0;
> + unsigned char reg_address = 0;
> + unsigned char tmp = 0;
> + char *buf = (char *)buffer;
> + int idx = 0;
> + struct i2c_msg msgs[2] = {
> + {0, 0, 1, &addr},
> + /* Attempt a 0 byte read */
> + {0, 0 | I2C_M_RD, 0, &tmp}
> + };
> + dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
> + (u32) buffer, (u32) count, (u32) offset, (u32) flags);
> +
> + if (offset > dev->size) {
> + dev_err("Request=%d size=%d!\n", offset, dev->size);
> + return -EINVAL;
> + }
> + count = min(count, dev->size - offset);
> + /* Set all defaults to 0xFF */
> + memset(buf, 0xFF, count);
> + while (idx < count) {
> + reg_address = (unsigned char)offset + idx;
> + msgs[0].addr = msgs[1].addr = reg_address;
> +
> + /* is this address being used? */
> + if (!i2cdev_check_addr(client->adapter, reg_address)) {
> + /* No client driver? aha! we shalt access thee! */
> + if (i2c_transfer(client->adapter, msgs, 2) >= 0)
> + *buf = reg_address;
> + } else
> + /* Client driver present.. probable that device exists!
> + * we dare not access it though :( - dunno how it's
> + * gonna behave
> + */
> + *buf = reg_address;
> + buf++;
> + idx++;
> + }
> + return idx;
> +}
> +
> +/**
> + * @brief display a short summary of the adapter
> + *
> + * @param dev -dev
> + *
> + * @return none
> + */
> +static void i2cbus_shortinfo(struct device_d *dev)
> +{
> + struct i2c_adapter *adap;
> + struct i2cdev_bus *i2cdev_bus;
> + i2cdev_bus = i2c_bus_get_by_minor(dev->map_base);
> + if (!i2cdev_bus) {
> + dev_err("did not get bus\n");
> + return;
> + }
> + adap = i2c_get_adapter(i2cdev_bus->adap->nr);
> + if (!adap) {
> + dev_err("No such adapter!\n");
> + return;
> + }
> + fprintf(stdout, "Adapter Name: %s\n", adap->name);
> +}
> +
> +/**
> + * @brief show detailed info of the adapter
> + *
> + * @param dev system dev
> + *
> + * @return none
> + */
> +static void i2cbus_showinfo(struct device_d *dev)
> +{
> + struct i2c_adapter *adap;
> + struct i2cdev_bus *i2cdev_bus;
> + unsigned long funcs;
> + int i;
> + i2cdev_bus = i2c_bus_get_by_minor(dev->map_base);
The function is called get_by_minor, the argument name in the
declaration indicates that it is passed an index and here it gets passed
map_base. There is something mixed up here.
*dev should lead you directly to the bus without having to use the help
of a function which loops over busses.
> + if (!i2cdev_bus) {
> + dev_err("did not get bus\n");
> + return;
> + }
> + adap = i2c_get_adapter(i2cdev_bus->adap->nr);
I guess i2c_get_adapter() returns nothing different than
i2cdev_bus->adap.
i2cdev_bus and i2c_adapter seem to have a 1:1 relationship,
so just move the fields into one struct.
> +int i2cdev_attach_adapter(struct i2c_adapter *adap)
> +{
> + struct device_d *dev;
> + struct i2cdev_bus *i2cdev_bus;
> + int res;
> + dbg_entry("adap=%x", (u32) adap);
> + i2cdev_bus = get_free_i2c_bus(adap);
> + if (!i2cdev_bus) {
> + dev_err("Did not get free dev-adap %d\n", adap->nr);
> + return -ENOMEM;
> + }
> + dev = &i2cdev_bus->dev;
> + /* Store my adapter number in mapbase for retrieval */
> + dev->map_base = adap->nr;
Ah ok, I understand. Please do not hijack this field for other uses than
it was intended to.
Regards,
Sascha
--
Pengutronix e.K. - Linux Solutions for Science and Industry
-----------------------------------------------------------
Kontakt-Informationen finden Sie im Header dieser Mail oder
auf der Webseite -> http://www.pengutronix.de/impressum/ <-
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 4/9 Try 3]U-boot-V2:I2C: Introduce i2c-dev
2008-06-24 8:05 ` Sascha Hauer
@ 2008-06-25 1:48 ` Menon, Nishanth
0 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-25 1:48 UTC (permalink / raw)
To: u-boot
I2C by default does not expose a device interface
for the adapters registering in the system. This
is usually not needed unless we need to debug
something. in which case, this is a handy little
layer when used in conjunction with the i2c
commands. This layer has changed
New fixes include not using map_base etc and
similar review comments from Sascha.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
drivers/i2c/Kconfig | 18 +
drivers/i2c/Makefile | 1
drivers/i2c/i2c-core.c | 12
drivers/i2c/i2c-core.h | 4
drivers/i2c/i2c-dev.c | 828 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c-dev.h | 43 ++
6 files changed, 906 insertions(+)
Index: u-boot-v2.git/include/linux/i2c-dev.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/linux/i2c-dev.h 2008-06-24 19:38:02.000000000 -0500
@@ -0,0 +1,43 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: include/linux/i2c-dev.h
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _LINUX_I2C_DEV_H
+#define _LINUX_I2C_DEV_H
+
+/* For command access */
+#define I2C_SLAVE_ADD 0x0703 /* Create a new slave device */
+#define I2C_SLAVE_REM 0x0706 /* Remove a new slave device */
+
+/******* For the platforms to use *********/
+int i2cdev_new(unsigned int, unsigned int);
+int i2cdev_remove(unsigned int, unsigned int);
+
+#endif /* _LINUX_I2C_DEV_H */
Index: u-boot-v2.git/drivers/i2c/i2c-dev.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/i2c-dev.c 2008-06-24 19:42:35.000000000 -0500
@@ -0,0 +1,828 @@
+/**
+ * @file
+ * @brief i2c-bus driver, "char device" interface
+ *
+ * FileName: drivers/i2c/i2c-dev.c
+ *
+ * It is very important to note the following:
+ * read to an i2cbus device is a 0 byte read operation. writes
+ * are not supported to i2cbus device.
+ *
+ * i2cdev devices on the other hand translate all read/write to
+ * 0 byte read/write operations as per i2c spec.
+ *
+ * Note: both of these can confuse certain devices on I2C bus.
+ * USE WITH CAUTION.
+ *
+ * NOTE: We dont support 10 bit addressing
+ *
+ */
+/* Originally from Linux kernel. Ported to U-boot-v2.
+ *
+ * Note: even though we borrow i2c-dev concept from linux, there are
+ * major differences in operations.
+ * I have retained original copyrights for the heavy influence it
+ * has on the current code.
+ *
+ * This implementation is heavily influenced by the valuable inputs from
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ */
+/*
+ * Copyright (C) 1995-97 Simon G. Vogl
+ * Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+ * But I have used so much of his original code and ideas that it seems
+ * only fair to recognize him as co-author -- Frodo
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <list.h>
+#include <init.h>
+#include <driver.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+/* Get some compatibility macros */
+#include <linux/mtd/compat.h>
+
+#include "i2c-core.h"
+
+#ifdef CONFIG_I2C_DEBUG_DEV
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+ "i2cdev: %s:%d:Entry:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#else
+#define dbg_entry(FORMAT, ARGS...)
+#endif
+
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+#define I2C_BUS_NAME "i2cbus"
+#define I2C_DEV_NAME "i2cdev"
+
+/** My dummy driver */
+static struct i2c_driver i2cdev_driver;
+
+/**
+ * An i2c_bus represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ */
+struct i2cdev_bus {
+ struct list_head list;
+ struct i2c_adapter *adap;
+ struct device_d dev;
+};
+static LIST_HEAD(i2c_bus_list);
+
+/**
+ * contains the internal structure for a device node this is the i2c device
+ */
+struct i2cdev_dev {
+ struct list_head list;
+ unsigned short daddr;
+ struct i2cdev_bus *i2cdev_bus;
+ struct device_d dev;
+};
+static LIST_HEAD(i2c_dev_list);
+
+/** A structure to store the various functions supported by the adapter */
+struct func {
+ long value;
+ const char *name;
+};
+static const struct func all_func[] = {
+ {.value = I2C_FUNC_I2C,
+ .name = "I2C"},
+ {.value = 0,
+ .name = ""}
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief search and get a bus given a bus adapter index.
+ *
+ * @param index adapter index
+ *
+ * @return bus node if found
+ */
+static struct i2cdev_bus *i2c_bus_from_busid(unsigned index)
+{
+ struct i2cdev_bus *i2cdev_bus;
+
+ dbg_entry("index=%x", index);
+
+ list_for_each_entry(i2cdev_bus, &i2c_bus_list, list) {
+ if (i2cdev_bus->adap->nr == index)
+ goto found;
+ }
+ i2cdev_bus = NULL;
+found:
+ return i2cdev_bus;
+}
+
+/**
+ * @brief get a free i2cbus node
+ * allocates memory and links up to bus node list.
+ *
+ * @param adap adapter to allocate a node for
+ *
+ * @return if success, return node, else NULL
+ */
+static struct i2cdev_bus *get_free_i2c_bus(struct i2c_adapter *adap)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ dbg_entry("adap=%x", (u32) adap);
+
+ /* if we already have a registered bus id..
+ * need to check for ensuring uniqueness */
+ i2cdev_bus = i2c_bus_from_busid(adap->nr);
+ if (i2cdev_bus)
+ return NULL;
+
+ i2cdev_bus = calloc(1, sizeof(*i2cdev_bus));
+ if (!i2cdev_bus)
+ return NULL;
+ i2cdev_bus->adap = adap;
+
+ list_add_tail(&i2cdev_bus->list, &i2c_bus_list);
+ return i2cdev_bus;
+}
+
+/**
+ * @brief releases the i2cdev_bus list.
+ *
+ * @param i2cdev_bus item to be released
+ *
+ * @return none
+ */
+static void return_i2c_bus(struct i2cdev_bus *i2cdev_bus)
+{
+ dbg_entry("i2cdev_bus=%x", (u32) i2cdev_bus);
+ list_del(&i2cdev_bus->list);
+ free(i2cdev_bus);
+}
+
+/**
+ * @brief tiny little helper to check if address is proper.
+ *
+ * @param dev device node
+ * @param addrp address
+ *
+ * @return 0 is no driver already linked, else -EBUSY
+ */
+static int i2cdev_check(struct device_d *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ dbg_entry("dev=%x addrp=%x", (u32) dev, (u32) addrp);
+
+ if (!client || client->addr != *(unsigned int *)addrp)
+ return 0;
+
+ return dev->driver ? -EBUSY : 0;
+}
+
+/**
+ * @brief This address checking function differs from the one in i2c-core
+ * in that it considers an address with a registered device, but no driver
+ * bound to it, as NOT busy.
+ *
+ * @param adapter adapter to attach to
+ * @param addr device address
+ *
+ * @return device present or not.
+ */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+ int ret = 0;
+ struct device_d *child;
+ dbg_entry("adapter=%x addr=%x", (u32) adapter, (u32) addr);
+ device_for_each_child((&(adapter->dev)), child) {
+ ret = i2cdev_check(child, &addr);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief read function for a bus.
+ *
+ * This allows for a functionality like i2cdetect.
+ * Offset of each byte corresponds to the device address
+ * each offset without a device will be set with 0xFF indicating empty.
+ * (This is coz 0x0 is a valid address..)
+ * any offset with data will have that address filled with corresponding dev
+ * address
+ *
+ * @param dev bus device.
+ * @param buffer buffer to return data
+ * @param count bytes to read
+ * @param offset device address
+ * @param flags any special flags?
+ *
+ * @return reult of operation
+ */
+static ssize_t i2cbus_read(struct device_d *dev, void *buffer, size_t count,
+ ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ unsigned char addr = 0;
+ unsigned char reg_address = 0;
+ unsigned char tmp = 0;
+ char *buf = (char *)buffer;
+ int idx = 0;
+ struct i2c_msg msgs[2] = {
+ {0, 0, 1, &addr},
+ /* Attempt a 0 byte read */
+ {0, 0 | I2C_M_RD, 0, &tmp}
+ };
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+
+ if (offset > dev->size) {
+ dev_err("Request=%d size=%d!\n", offset, dev->size);
+ return -EINVAL;
+ }
+ count = min(count, dev->size - offset);
+ /* Set all defaults to 0xFF */
+ memset(buf, 0xFF, count);
+ while (idx < count) {
+ reg_address = (unsigned char)offset + idx;
+ msgs[0].addr = msgs[1].addr = reg_address;
+
+ /* is this address being used? */
+ if (i2cdev_check_addr(client->adapter, reg_address))
+ /* Client driver present.. probable that device exists!
+ * we dare not access it though :( - dunno how it's
+ * gonna behave
+ */
+ *buf = reg_address;
+ else if (i2c_transfer(client->adapter, msgs, 2) >= 0)
+ *buf = reg_address;
+ buf++;
+ idx++;
+ }
+ return idx;
+}
+
+/**
+ * @brief display a short summary of the adapter
+ *
+ * @param dev -dev
+ *
+ * @return none
+ */
+static void i2cbus_shortinfo(struct device_d *dev)
+{
+ struct i2c_adapter *adap;
+ struct i2cdev_bus *i2cdev_bus = (struct i2cdev_bus *)dev->platform_data;
+ adap = i2cdev_bus->adap;
+ fprintf(stdout, "Adapter Name: %s\n", adap->name);
+}
+
+/**
+ * @brief show detailed info of the adapter
+ *
+ * @param dev system dev
+ *
+ * @return none
+ */
+static void i2cbus_showinfo(struct device_d *dev)
+{
+ struct i2c_adapter *adap;
+ struct i2cdev_bus *i2cdev_bus = (struct i2cdev_bus *)dev->platform_data;
+ unsigned long funcs;
+ int i;
+
+ adap = i2cdev_bus->adap;
+ /* Display basic info */
+ fprintf(stdout,
+ "Adapter Name: %s\n"
+ "Adapter ID : %d\n"
+ "Adapter Nr : %d\n"
+ "Has Algo? : %s\n"
+ "Timeout : %d\n"
+ "Retries : %d\n"
+ "----------------\n"
+ "Functionalities:\n",
+ adap->name,
+ adap->id,
+ adap->nr,
+ (adap->algo) ? "yes" : "no", adap->timeout, adap->retries);
+
+ funcs = i2c_get_functionality(adap);
+ for (i = 0; all_func[i].value; i++) {
+ fprintf(stdout, "%-32s %s\n", all_func[i].name,
+ (funcs & all_func[i].value) ? "yes" : "no");
+ }
+}
+
+/**
+ * @brief ioctls for the bus
+ *
+ * @param dev system dev
+ * @param cmd
+ * @param argument
+ *
+ * @return ioctl result
+ */
+static int i2cbus_ioctl(struct device_d *dev, int cmd, void *argument)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ unsigned long arg = (unsigned long)argument;
+ int ret = 0;
+ dbg_entry("dev=%x cmd=%x arg=%x", (u32) dev, (u32) cmd, (u32) arg);
+
+ if (arg > 0x7f) {
+ fprintf(stderr, "arg %x>0x7f\n", arg);
+ return -EINVAL;
+ }
+ switch (cmd) {
+ case I2C_SLAVE_ADD:
+ if (i2cdev_check_addr(client->adapter, arg)) {
+ fprintf(stderr, "There is already a "
+ "client on that address\n");
+ return -EBUSY;
+ }
+ ret = i2cdev_new(client->adapter->nr, arg);
+ break;
+ case I2C_SLAVE_REM:
+ /* we dont attach to normal i2c client struct..
+ * so call our integral search func */
+ ret = i2cdev_remove(client->adapter->nr, arg);
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+ return ret;
+}
+
+/**
+ * @brief open a bus device
+ *
+ * @param dev system dev
+ * @param file
+ *
+ * @return open success or not
+ */
+static int i2cbus_open(struct device_d *dev, struct filep *file)
+{
+ struct i2cdev_bus *i2cdev_bus = (struct i2cdev_bus *)dev->platform_data;
+ struct i2c_client *client;
+ struct i2c_adapter *adap;
+ unsigned long funcs;
+
+ dbg_entry("dev=%x file=%x", (u32) dev, (u32) file);
+
+ /* I am not multi-user */
+ if (dev->priv) {
+ dev_err("I am already in use\n");
+ return -EBUSY;
+ }
+ /* In case someone else registered with me.. do a basic check
+ * at least
+ */
+ BUG_ON(!i2cdev_bus);
+
+ /* Reserve the adapter for ourself */
+ adap = i2c_get_adapter(i2cdev_bus->adap->nr);
+ if (!adap) {
+ dev_err("Bus being used by someone else?\n");
+ return -EBUSY;
+ }
+
+ /* Check i2c functionality */
+ funcs = i2c_get_functionality(i2cdev_bus->adap);
+
+ if (!(funcs & I2C_FUNC_I2C)) {
+ dev_err("I2C support is missing!");
+ return -EINVAL;
+ }
+
+ /* This creates an anonymous i2c_client, which may later be
+ * given an address later on
+ *
+ * This client is ** NEVER REGISTERED ** with the driver model
+ * or I2C core code!! It just holds private copies of addressing
+ * information and maybe a PEC flag.
+ */
+ client = calloc(1, sizeof(*client));
+ if (!client) {
+ i2c_put_adapter(adap);
+ return -ENOMEM;
+ }
+
+ sprintf(client->name, "i2c-bus %d", adap->nr);
+
+ /* Attach a dummy driver */
+ client->driver = &i2cdev_driver;
+
+ client->adapter = adap;
+ dev->priv = client;
+
+ return 0;
+}
+
+/**
+ * @brief done using the bus device. now release it.
+ *
+ * @param dev system dev
+ * @param file
+ *
+ * @return
+ */
+static int i2cbus_release(struct device_d *dev, struct filep *file)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+
+ dbg_entry("dev=%x file=%x, client=%x", (u32) dev, (u32) file,
+ (u32) client);
+
+ i2c_put_adapter(client->adapter);
+ free(client);
+ dev->priv = NULL;
+
+ return 0;
+}
+
+static struct driver_d i2cbus_fops = {
+ .name = I2C_BUS_NAME,
+ .probe = dummy_probe,
+ .ioctl = i2cbus_ioctl,
+ .read = i2cbus_read,
+ .lseek = dev_lseek_default,
+ .open = i2cbus_open,
+ .remove = dummy_probe,
+ .close = i2cbus_release,
+ .info = i2cbus_showinfo,
+ .shortinfo = i2cbus_shortinfo,
+ .type = DEVICE_TYPE_I2CDEV,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief attach a new adapter to the device architecture
+ *
+ * @param adap adapter name
+ *
+ * @return
+ */
+int i2cdev_attach_adapter(struct i2c_adapter *adap)
+{
+ struct device_d *dev;
+ struct i2cdev_bus *i2cdev_bus;
+ int res;
+ dbg_entry("adap=%x", (u32) adap);
+ i2cdev_bus = get_free_i2c_bus(adap);
+ if (!i2cdev_bus) {
+ dev_err("Did not get free dev-adap %d\n", adap->nr);
+ return -ENOMEM;
+ }
+ dev = &i2cdev_bus->dev;
+ /* Store my structure in platform_data
+ * dev->priv will be used to store i2c_client
+ */
+ dev->platform_data = (void *)i2cdev_bus;
+ dev->size = 0x80;
+ /* my i2cdev type */
+ sprintf((char *)&dev->name, "%s", I2C_BUS_NAME);
+ sprintf((char *)&dev->id, "%s%d", I2C_BUS_NAME, adap->nr);
+ dev->type = DEVICE_TYPE_I2CDEV;
+
+ res = register_device(dev);
+ if (res < 0) {
+ dev_err("Device %d registration failed %d\n", adap->nr, res);
+ perror(dev->id);
+ return_i2c_bus(i2cdev_bus);
+ return res;
+ }
+ return res;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
+
+/**
+ * @brief detach the adapter from the device tree
+ *
+ * @param adap -adapter
+ *
+ * @return result
+ */
+int i2cdev_detach_adapter(struct i2c_adapter *adap)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ int ret = 0;
+ dbg_entry("adap=%x", (u32) adap);
+ i2cdev_bus = i2c_bus_from_busid(adap->nr);
+ if (!i2cdev_bus) {
+ dev_err("not registered adapter %d with me!\n", adap->nr);
+ return -ENODEV;
+ }
+ ret = unregister_device(&(i2cdev_bus->dev));
+ if (ret) {
+ dev_err("Adapter %d dev is in use(%d)?\n", adap->nr, ret);
+ return ret;
+ }
+ if (i2cdev_bus)
+ return_i2c_bus(i2cdev_bus);
+ return ret;
+}
+EXPORT_SYMBOL(i2cdev_attach_adapter);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief read an i2cdev device ->byte by byte.. no multibyte reads..
+ *
+ * @param dev device
+ * @param buffer data buffer to put data
+ * @param count how much data to read
+ * @param offset which offset to get data
+ * @param flags the usual
+ *
+ * @return operation result
+ */
+static ssize_t i2cdev_read(struct device_d *dev, void *buffer, size_t count,
+ ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ char *buf = (char *)buffer;
+ int ret;
+ int idx = 0;
+ char dev_offset = (char)offset;
+ /* it is simpler to do a multibyte read, but that would not work
+ * on all devices. */
+ struct i2c_msg msgs[2] = {
+ /* register address */
+ {client->addr, 0, 1, &dev_offset},
+ /* Attempt a 0 byte read */
+ {client->addr, 0 | I2C_M_RD, 1, NULL}
+ };
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x"
+ " client=%x addr=%x", (u32) dev, (u32) buffer,
+ (u32) count, (u32) offset, (u32) flags,
+ (u32) client, client->addr);
+ count = min(count, dev->size - offset);
+ while (idx < count) {
+ msgs[1].buf = buf;
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret <= 0)
+ return ret;
+ buf++;
+ idx++;
+ dev_offset++;
+ }
+ return idx;
+}
+
+/**
+ * @brief write to an i2cdev device ->byte by byte.. no multibyte writes..
+ *
+ * @param dev device
+ * @param buffer data buffer to take data
+ * @param count how much data to write
+ * @param offset which offset to put data
+ * @param flags the usual
+ *
+ * @return operation result
+ */
+static ssize_t i2cdev_write(struct device_d *dev, const void *buffer,
+ size_t count, ulong offset, ulong flags)
+{
+ struct i2c_client *client = (struct i2c_client *)dev->priv;
+ char *buf = (char *)buffer;
+ int ret;
+ int idx = 0;
+ char buff[2];
+ /* it is simpler to do a multibyte write, but that would not work
+ * on all devices. */
+ struct i2c_msg msgs[1] = {
+ /* register address and data go together */
+ {client->addr, 0, 2, buff},
+ };
+
+ dbg_entry("dev=%x buffer=%x count=%x offset=%x flags=%x", (u32) dev,
+ (u32) buffer, (u32) count, (u32) offset, (u32) flags);
+
+ count = min(count, dev->size - offset);
+ while (idx < count) {
+ buff[0] = (char)(offset + idx);
+ buff[1] = *buf;
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret <= 0)
+ return ret;
+ buf++;
+ idx++;
+ }
+ return idx;
+}
+
+/**
+ * @brief open the device
+ * we reuse most of i2cbus open functionality here.
+ *
+ * Then, since i2cbus_release kills the i2c_client, we reuse it on close
+ *
+ * @param dev dev
+ * @param file file
+ *
+ * @return result value
+ */
+static int i2cdev_open(struct device_d *dev, struct filep *file)
+{
+ int ret;
+ struct i2c_client *client;
+ struct i2cdev_dev *d = (struct i2cdev_dev *)dev->platform_data;
+ /* This is small piece of hack. we want to do what ever
+ * i2cbus_open does, so put the platform_data as what it expects
+ * and then put ours back.
+ */
+ dev->platform_data = d->i2cdev_bus;
+ /* All the stuff we want checked and done is done in bus!
+ * reuse it! */
+ ret = i2cbus_open(dev, file);
+ dev->platform_data = (void *)d;
+ if (ret)
+ return ret;
+
+ /* retrieve the client and customize a few things */
+ client = (struct i2c_client *)dev->priv;
+ client->addr = d->daddr;
+ sprintf(client->name, "i2cdev_%x_%x", client->adapter->nr,
+ client->addr);
+
+ return 0;
+}
+
+/**
+ * @brief Do a device probe. if there are other client drivers, we will not
+ * hook on.
+ *
+ * @param dev dev
+ *
+ * @return 0 if all things ok, else -EINVAL or error val
+ */
+static int i2cdev_probe(struct device_d *dev)
+{
+ struct i2c_adapter *adap;
+ struct i2cdev_dev *d = (struct i2cdev_dev *)dev->platform_data;
+ int ret;
+
+ /* Check if someone else is registering with my driver */
+ BUG_ON(!d);
+ BUG_ON(!d->i2cdev_bus);
+ adap = d->i2cdev_bus->adap;
+ BUG_ON(!adap);
+
+ /* if some other client driver exists.. we will not hook on! */
+ ret = i2cdev_check_addr(adap, d->daddr);
+
+ return ret;
+}
+
+static struct driver_d i2cdev_fops = {
+ .name = I2C_DEV_NAME,
+ .probe = i2cdev_probe,
+ .remove = dummy_probe,
+ .read = i2cdev_read,
+ .write = i2cdev_write,
+ .lseek = dev_lseek_default,
+ .open = i2cdev_open,
+ .close = i2cbus_release,
+ .type = DEVICE_TYPE_I2CDEV,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * @brief attach a new device to the device tree
+ *
+ * I can be called from either a platform file OR by sending ioctls to i2cbus
+ * device.
+ *
+ * @param adapter_number adapter number
+ * @param device_address device address
+ *
+ * @return -result
+ */
+int i2cdev_new(unsigned int adapter_number, unsigned int device_address)
+{
+ struct i2cdev_bus *i2cdev_bus;
+ struct device_d *dev;
+ struct i2cdev_dev *d;
+ int res;
+
+ if (device_address > 0x7F) {
+ dev_err("bad dev address %x!\n", device_address);
+ return -EINVAL;
+ }
+
+ i2cdev_bus = i2c_bus_from_busid(adapter_number);
+ if (!i2cdev_bus) {
+ dev_err("not registered adapter %d with me!\n", adapter_number);
+ return -ENODEV;
+ }
+ d = calloc(1, sizeof(*d));
+ if (!d) {
+ dev_err("unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ /* I hate searching again.. so store the bus pointer */
+ d->i2cdev_bus = i2cdev_bus;
+ d->daddr = device_address;
+ dev = &d->dev;
+ /* Store my master structure for retrieval
+ * dev->priv will be used for i2c_client
+ */
+ dev->platform_data = (void *)d;
+ dev->size = 256;
+
+ sprintf((char *)&dev->name, "%s", I2C_DEV_NAME);
+ sprintf((char *)&dev->id, "%s%d_%x", I2C_BUS_NAME, adapter_number,
+ device_address);
+ dev->type = DEVICE_TYPE_I2CDEV;
+ res = register_device(dev);
+ if (res < 0) {
+ dev_err("Bus %d Device 0x%x registration failed %d\n",
+ adapter_number, device_address, res);
+ perror(dev->id);
+ free(d);
+ return res;
+ }
+ list_add_tail(&d->list, &i2c_dev_list);
+ return res;
+}
+EXPORT_SYMBOL(i2cdev_new);
+
+/**
+ * @brief remove the device
+ *
+ * I can be called from either a platform file OR by sending ioctls to i2cbus
+ * device.
+ *
+ * @param adapter_number adapter numbe adapter numberr
+ * @param device_address device address
+ *
+ * @return -ENODEV if there is no such device in the system
+ */
+int i2cdev_remove(unsigned int adapter_number, unsigned int device_address)
+{
+ struct device_d *dev;
+ struct i2cdev_dev *d;
+ char id[MAX_DRIVER_NAME];
+ sprintf(id, "%s%d_%x", I2C_BUS_NAME, adapter_number, device_address);
+ list_for_each_entry(d, &i2c_dev_list, list) {
+ if (!strcmp(d->dev.id, id))
+ goto found;
+ }
+ return -ENODEV;
+found:
+ dev = &d->dev;
+ unregister_device(dev);
+ list_del(&d->list);
+ free(d);
+ return 0;
+}
+EXPORT_SYMBOL(i2cdev_remove);
+
+/* ------------------------------------------------------------------------- */
+
+static int i2cdev_init(void)
+{
+
+ int res = 0;
+ dbg_entry("%s", "none");
+ res = register_driver(&i2cbus_fops);
+ if (res)
+ return res;
+ res = register_driver(&i2cdev_fops);
+ return res;
+}
+device_initcall(i2cdev_init);
Index: u-boot-v2.git/drivers/i2c/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Kconfig 2008-06-24 19:37:44.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Kconfig 2008-06-24 19:38:02.000000000 -0500
@@ -19,6 +19,16 @@
if I2C
+config I2C_CHARDEV
+ tristate "I2C device interface"
+ help
+ Say Y here to use i2c-* device files, usually found in the /dev
+ directory on your system. They make it possible to have applications
+ to use the I2C bus.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-dev.
+
source drivers/i2c/busses/Kconfig
config I2C_DEBUG_CORE
@@ -28,6 +38,14 @@
messages to the system log. Select this if you are having a
problem with I2C support and want to see more of what is going on.
+config I2C_DEBUG_DEV
+ bool "I2C Dev debugging messages"
+ depends on I2C_CHARDEV
+ help
+ Say Y here if you want the I2C dev to produce a bunch of debug
+ messages to the system log. Select this if you are having a
+ problem with I2C support and want to see more of what is going on.
+
config I2C_DEBUG_BUS
bool "I2C Bus debugging messages"
help
Index: u-boot-v2.git/drivers/i2c/Makefile
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/Makefile 2008-06-24 19:37:44.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/Makefile 2008-06-24 19:38:02.000000000 -0500
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_I2C) += i2c-core.o
+obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/
ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
Index: u-boot-v2.git/drivers/i2c/i2c-core.c
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.c 2008-06-24 19:37:58.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.c 2008-06-24 19:38:02.000000000 -0500
@@ -94,6 +94,10 @@
debug("adapter [%s] registered\n", adap->name);
+#ifdef CONFIG_I2C_CHARDEV
+ i2cdev_attach_adapter(adap);
+#endif
+
out_unlock:
return res;
@@ -214,6 +218,14 @@
goto out_unlock;
}
+#ifdef CONFIG_I2C_CHARDEV
+ res = i2cdev_detach_adapter(adap);
+ if (res) {
+ dev_err("adapter in use\n");
+ goto out_unlock;
+ }
+#endif
+
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
Index: u-boot-v2.git/drivers/i2c/i2c-core.h
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/i2c-core.h 2008-06-24 19:37:44.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/i2c-core.h 2008-06-24 19:38:02.000000000 -0500
@@ -34,4 +34,8 @@
extern struct list_head __i2c_board_list;
extern int __i2c_first_dynamic_bus_num;
+/* Automatically called by i2c-Core..*/
+int i2cdev_attach_adapter(struct i2c_adapter *adap);
+int i2cdev_detach_adapter(struct i2c_adapter *adap);
+
#endif /* __i2C_CORE_H */
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 5/9 Try2]U-boot-V2:cmd: add I2C commands
2008-06-20 15:16 ` Sascha Hauer
2008-06-20 16:28 ` Menon, Nishanth
2008-06-21 2:34 ` [U-Boot-Users] [Patch 4/9 Try 2]U-boot-V2:I2C: Introduce i2c-dev Menon, Nishanth
@ 2008-06-21 2:34 ` Menon, Nishanth
2008-06-21 7:23 ` Wolfgang Denk
2 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-21 2:34 UTC (permalink / raw)
To: u-boot
i2cdev command is introduced here. This allows
for device creation for doing i2c ops.
This is based on the discussion here:
http://www.nabble.com/-Patch-0-9--U-boot-V2%3A-
Introduce-I2C-support-for-SDP3430-to17981717.html
#a18029740
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
Documentation/commands.dox | 1
commands/Kconfig | 4
commands/i2c.c | 211 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 216 insertions(+)
Index: u-boot-v2.git/Documentation/commands.dox
===================================================================
--- u-boot-v2.git.orig/Documentation/commands.dox 2008-06-20 21:09:53.000000000 -0500
+++ u-boot-v2.git/Documentation/commands.dox 2008-06-20 21:09:59.000000000 -0500
@@ -20,5 +20,6 @@
- @subpage setenv_command
- @subpage sh_command
- @subpage unprotect_command
+ - @subpage page_do_cmd_i2cdev
*/
Index: u-boot-v2.git/commands/Kconfig
===================================================================
--- u-boot-v2.git.orig/commands/Kconfig 2008-06-20 21:09:53.000000000 -0500
+++ u-boot-v2.git/commands/Kconfig 2008-06-20 21:11:16.000000000 -0500
@@ -180,6 +180,10 @@
prompt "nand"
endmenu
+config CMD_I2C
+ depends on I2C_CHARDEV
+ tristate
+ prompt "i2cdev"
menu "booting "
Index: u-boot-v2.git/commands/i2c.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/commands/i2c.c 2008-06-20 21:09:59.000000000 -0500
@@ -0,0 +1,211 @@
+/**
+ * @file
+ * @brief I2C related applications
+ *
+ * FileName: commands/i2c.c
+ * This provides i2cdump, i2cdetect, i2cset and i2cget appplications
+ * The code originates from the i2c-tools located here:
+ * http://www.lm-sensors.org/wiki/I2CTools
+ *
+ * This file merges the userspace headers and applications to a single
+ * entity as we do not maintain a userspace/kernel space isolation
+ *
+ * NOTE: 10-bit addresses are NOT supported!
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <fs.h>
+#include <getopt.h>
+#include <linux/i2c-dev.h>
+
+static const __maybe_unused char cmd_i2cdev_s[] =
+ "Usage:\n"
+ " i2cdev [-a|-r] -b bus_dev -d dev_addr \n"
+ "Where:\n"
+ "-a Add a new device node\n"
+ "-r Remove existing device node\n"
+ "-b bus_dev i2c bus device to operate on\n"
+ "-d dev_addr Device address for which to create\n";
+
+static int do_cmd_i2cdev(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *bus_dev = NULL;
+ int dev_addr = -1;
+ int opt, file, ret;
+ char add = 0, rem = 0;
+ getopt_reset();
+
+ while ((opt = getopt(argc, argv, "arb:d:")) > 0) {
+ switch (opt) {
+ case 'a':
+ if (rem) {
+ fprintf(stderr,
+ "you cannot add when you selected "
+ "delete!\n");
+ goto fail_ret;
+ }
+ add = 1;
+ break;
+ case 'r':
+ if (add) {
+ fprintf(stderr,
+ "you cannot delete when you selected "
+ "add!\n");
+ goto fail_ret;
+ }
+ rem = 1;
+ break;
+ case 'b':
+ bus_dev = optarg;
+ break;
+ case 'd':
+ dev_addr = (int)simple_strtoul(optarg, NULL, 10);
+ if (dev_addr > 0xFF) {
+ fprintf(stderr, "I2C address are b/w 0 and "
+ "0x7f\n");
+ goto fail_ret;
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown arg %s\n", opt);
+ goto fail_ret;
+ }
+ }
+
+ /* check args */
+ if (!(add + rem) || (bus_dev == NULL) || (dev_addr < 0)) {
+ fprintf(stderr, "not enough arguments\n");
+ goto fail_ret;
+ }
+ file = open(bus_dev, O_RDONLY);
+ if (file < 0) {
+ perror(argv[0]);
+ goto fail_ret;
+ }
+ if (add)
+ ret = ioctl(file, I2C_SLAVE_ADD, (void *)dev_addr);
+ else
+ ret = ioctl(file, I2C_SLAVE_REM, (void *)dev_addr);
+ if (ret)
+ fprintf(stderr, "Operation failed-%d!\n", ret);
+ close(file);
+ return (ret) ? 1 : 0;
+fail_ret:
+ u_boot_cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD_START(i2cdev)
+ .maxargs = 6,
+ .cmd = do_cmd_i2cdev,
+ .usage = "program to add a new i2cdevice",
+ U_BOOT_CMD_HELP(cmd_i2cdev_s)
+U_BOOT_CMD_END
+/** @page page_do_cmd_i2cdev i2cdev creates a I2C device node
+SYNOPSIS:
+ at li i2cdev [-a|-r] -b bus_dev -d dev_addr
+
+DESCRIPTION:
+ at verbatim
+ This program allows creation of device nodes corresponding
+ to a I2C device address on an I2C bus. This allows users
+ to do read or write access to a specific I2C device using
+ standard commands.
+ NOTE: i2cbusses are created by default once CHARDEV is
+ enabled during compilation.
+ at endverbatim
+OPTIONS:
+ at verbatim
+ -a Add a new device node
+ -r Remove existing device node
+ -b bus_dev i2c bus device to operate on
+ -d dev_addr Device address for which to create
+ at endverbatim
+
+ at warning Doing a blind probe on i2c bus is NOT RECOMMENDED unless
+you really know what you are doing!! These programs can confuse your
+I2C bus, cause data loss and worse!! Even Read/Write is to be used with
+absolute care and knowledge. If you need to know I2C specification, refer:
+http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
+
+EXAMPLE USAGE:
+ at li Scan the i2cbus for all devices present:
+ at verbatim
+$ md -b -s /dev/i2cbus0
+ 00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000040: ff ff ff ff ff ff ff ff 48 49 4a 4b ff ff ff ff ........HIJK....
+ 00000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+
+NOTE: 0xff means there are no devices present there. This example shows that
+there are devices on 0x48-0x4B. The md operation on a bus device does a 0 byte
+read (See warning).
+ at endverbatim
+
+ at li Create a new device node(if the device is present) on /dev/i2cbus0_49:
+ at verbatim
+ i2cdev -a -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Remove a existing device node (/dev/i2cbus0_49):
+ at verbatim
+ i2cdev -r -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Dump all registers of device 0n bus 0 device address 0x49:
+ at verbatim
+$ md -b -s /dev/i2cbus0_49
+00000000: 00 00 00 00 00 00 00 00 00 00 0f 0f 0f 0f 00 00 ................
+00000010: 3f 3f 3f 3f 25 00 00 00 00 32 32 32 32 00 00 55 ????%....2222..U
+00000020: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 ................
+00000030: 13 00 00 00 00 79 11 00 00 00 06 00 44 69 00 00 .....y......Di..
+00000040: 00 00 00 00 32 00 00 00 00 00 00 00 00 00 00 1b ....2...........
+00000050: 00 00 03 f0 05 00 00 00 1a 1a 00 00 00 00 00 00 ................
+00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000080: 00 20 00 00 00 2f 00 09 50 ff ff ff ff ff ff ff . .../..P.......
+00000090: ff 90 00 00 55 00 00 00 03 00 00 00 00 00 00 00 ....U...........
+000000a0: 00 00 00 00 00 00 00 00 00 00 04 15 50 01 44 05 ............P.D.
+000000b0: 00 00 00 00 ff ff 03 00 00 00 ff ff 03 00 00 00 ................
+000000c0: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
+000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ at endverbatim
+
+ at li Set a value 0xaa to register 1 on device 0x49, bus 0 and check if set:
+ at verbatim
+$ mw -b -d /dev/i2cbus0_49 0x1 0xaa
+$ md -b -s /dev/i2cbus0_49 0x1+1
+00000001: aa .
+@endverbatim
+
+ */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9 Try2]U-boot-V2:cmd: add I2C commands
2008-06-21 2:34 ` [U-Boot-Users] [Patch 5/9 Try2]U-boot-V2:cmd: add I2C commands Menon, Nishanth
@ 2008-06-21 7:23 ` Wolfgang Denk
2008-06-22 18:56 ` [U-Boot-Users] [Patch 5/9 Try 3]U-boot-V2:cmd: " Menon, Nishanth
0 siblings, 1 reply; 43+ messages in thread
From: Wolfgang Denk @ 2008-06-21 7:23 UTC (permalink / raw)
To: u-boot
In message <7A436F7769CA33409C6B44B358BFFF0CD32814D8@dlee02.ent.ti.com> you wrote:
> i2cdev command is introduced here. This allows
> for device creation for doing i2c ops.
...
> +static const __maybe_unused char cmd_i2cdev_s[] =
> + "Usage:\n"
> + " i2cdev [-a|-r] -b bus_dev -d dev_addr \n"
> + "Where:\n"
> + "-a Add a new device node\n"
> + "-r Remove existing device node\n"
> + "-b bus_dev i2c bus device to operate on\n"
> + "-d dev_addr Device address for which to create\n";
Indentation is by TABs, i. e. in columns of 8, 16, ...
Please stick to the Coding Style requirements!
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Nail here --X-- for new monitor.
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9 Try 3]U-boot-V2:cmd: add I2C commands
2008-06-21 7:23 ` Wolfgang Denk
@ 2008-06-22 18:56 ` Menon, Nishanth
2008-06-24 6:18 ` Sascha Hauer
0 siblings, 1 reply; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-22 18:56 UTC (permalink / raw)
To: u-boot
i2cdev command is introduced here. This allows
for device creation for doing i2c ops. With tab
indents corrected.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
Documentation/commands.dox | 1
commands/Kconfig | 4
commands/i2c.c | 211 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 216 insertions(+)
Index: u-boot.v2/Documentation/commands.dox
===================================================================
--- u-boot.v2.orig/Documentation/commands.dox 2008-06-21 09:53:22.000000000 -0500
+++ u-boot.v2/Documentation/commands.dox 2008-06-21 09:54:22.000000000 -0500
@@ -20,5 +20,6 @@
- @subpage setenv_command
- @subpage sh_command
- @subpage unprotect_command
+ - @subpage page_do_cmd_i2cdev
*/
Index: u-boot.v2/commands/Kconfig
===================================================================
--- u-boot.v2.orig/commands/Kconfig 2008-06-21 09:53:22.000000000 -0500
+++ u-boot.v2/commands/Kconfig 2008-06-21 09:54:22.000000000 -0500
@@ -180,6 +180,10 @@
prompt "nand"
endmenu
+config CMD_I2C
+ depends on I2C_CHARDEV
+ tristate
+ prompt "i2cdev"
menu "booting "
Index: u-boot.v2/commands/i2c.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot.v2/commands/i2c.c 2008-06-21 10:42:55.000000000 -0500
@@ -0,0 +1,211 @@
+/**
+ * @file
+ * @brief I2C related applications
+ *
+ * FileName: commands/i2c.c
+ * This provides i2cdump, i2cdetect, i2cset and i2cget appplications
+ * The code originates from the i2c-tools located here:
+ * http://www.lm-sensors.org/wiki/I2CTools
+ *
+ * This file merges the userspace headers and applications to a single
+ * entity as we do not maintain a userspace/kernel space isolation
+ *
+ * NOTE: 10-bit addresses are NOT supported!
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <fs.h>
+#include <getopt.h>
+#include <linux/i2c-dev.h>
+
+static const __maybe_unused char cmd_i2cdev_s[] =
+ "Usage:\n"
+ " i2cdev [-a|-r] -b bus_dev -d dev_addr \n"
+ "Where:\n"
+ "-a Add a new device node\n"
+ "-r Remove existing device node\n"
+ "-b bus_dev i2c bus device to operate on\n"
+ "-d dev_addr Device address for which to create\n";
+
+static int do_cmd_i2cdev(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *bus_dev = NULL;
+ int dev_addr = -1;
+ int opt, file, ret;
+ char add = 0, rem = 0;
+ getopt_reset();
+
+ while ((opt = getopt(argc, argv, "arb:d:")) > 0) {
+ switch (opt) {
+ case 'a':
+ if (rem) {
+ fprintf(stderr,
+ "you cannot add when you selected "
+ "delete!\n");
+ goto fail_ret;
+ }
+ add = 1;
+ break;
+ case 'r':
+ if (add) {
+ fprintf(stderr,
+ "you cannot delete when you selected "
+ "add!\n");
+ goto fail_ret;
+ }
+ rem = 1;
+ break;
+ case 'b':
+ bus_dev = optarg;
+ break;
+ case 'd':
+ dev_addr = (int)simple_strtoul(optarg, NULL, 10);
+ if (dev_addr > 0xFF) {
+ fprintf(stderr, "I2C address are b/w 0 and "
+ "0x7f\n");
+ goto fail_ret;
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown arg %s\n", opt);
+ goto fail_ret;
+ }
+ }
+
+ /* check args */
+ if (!(add + rem) || (bus_dev == NULL) || (dev_addr < 0)) {
+ fprintf(stderr, "not enough arguments\n");
+ goto fail_ret;
+ }
+ file = open(bus_dev, O_RDONLY);
+ if (file < 0) {
+ perror(argv[0]);
+ goto fail_ret;
+ }
+ if (add)
+ ret = ioctl(file, I2C_SLAVE_ADD, (void *)dev_addr);
+ else
+ ret = ioctl(file, I2C_SLAVE_REM, (void *)dev_addr);
+ if (ret)
+ fprintf(stderr, "Operation failed-%d!\n", ret);
+ close(file);
+ return (ret) ? 1 : 0;
+fail_ret:
+ u_boot_cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD_START(i2cdev)
+ .maxargs = 6,
+ .cmd = do_cmd_i2cdev,
+ .usage = "program to add a new i2cdevice",
+ U_BOOT_CMD_HELP(cmd_i2cdev_s)
+U_BOOT_CMD_END
+/** @page page_do_cmd_i2cdev i2cdev creates a I2C device node
+SYNOPSIS:
+ at li i2cdev [-a|-r] -b bus_dev -d dev_addr
+
+DESCRIPTION:
+ at verbatim
+ This program allows creation of device nodes corresponding
+ to a I2C device address on an I2C bus. This allows users
+ to do read or write access to a specific I2C device using
+ standard commands.
+ NOTE: i2cbusses are created by default once CHARDEV is
+ enabled during compilation.
+ at endverbatim
+OPTIONS:
+ at verbatim
+ -a Add a new device node
+ -r Remove existing device node
+ -b bus_dev i2c bus device to operate on
+ -d dev_addr Device address for which to create
+ at endverbatim
+
+ at warning Doing a blind probe on i2c bus is NOT RECOMMENDED unless
+you really know what you are doing!! These programs can confuse your
+I2C bus, cause data loss and worse!! Even Read/Write is to be used with
+absolute care and knowledge. If you need to know I2C specification, refer:
+http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
+
+EXAMPLE USAGE:
+ at li Scan the i2cbus for all devices present:
+ at verbatim
+$ md -b -s /dev/i2cbus0
+ 00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000040: ff ff ff ff ff ff ff ff 48 49 4a 4b ff ff ff ff ........HIJK....
+ 00000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+ 00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+
+NOTE: 0xff means there are no devices present there. This example shows that
+there are devices on 0x48-0x4B. The md operation on a bus device does a 0 byte
+read (See warning).
+ at endverbatim
+
+ at li Create a new device node(if the device is present) on /dev/i2cbus0_49:
+ at verbatim
+ i2cdev -a -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Remove a existing device node (/dev/i2cbus0_49):
+ at verbatim
+ i2cdev -r -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Dump all registers of device 0n bus 0 device address 0x49:
+ at verbatim
+$ md -b -s /dev/i2cbus0_49
+00000000: 00 00 00 00 00 00 00 00 00 00 0f 0f 0f 0f 00 00 ................
+00000010: 3f 3f 3f 3f 25 00 00 00 00 32 32 32 32 00 00 55 ????%....2222..U
+00000020: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 ................
+00000030: 13 00 00 00 00 79 11 00 00 00 06 00 44 69 00 00 .....y......Di..
+00000040: 00 00 00 00 32 00 00 00 00 00 00 00 00 00 00 1b ....2...........
+00000050: 00 00 03 f0 05 00 00 00 1a 1a 00 00 00 00 00 00 ................
+00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000080: 00 20 00 00 00 2f 00 09 50 ff ff ff ff ff ff ff . .../..P.......
+00000090: ff 90 00 00 55 00 00 00 03 00 00 00 00 00 00 00 ....U...........
+000000a0: 00 00 00 00 00 00 00 00 00 00 04 15 50 01 44 05 ............P.D.
+000000b0: 00 00 00 00 ff ff 03 00 00 00 ff ff 03 00 00 00 ................
+000000c0: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
+000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ at endverbatim
+
+ at li Set a value 0xaa to register 1 on device 0x49, bus 0 and check if set:
+ at verbatim
+$ mw -b -d /dev/i2cbus0_49 0x1 0xaa
+$ md -b -s /dev/i2cbus0_49 0x1+1
+00000001: aa .
+@endverbatim
+
+ */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9 Try 3]U-boot-V2:cmd: add I2C commands
2008-06-22 18:56 ` [U-Boot-Users] [Patch 5/9 Try 3]U-boot-V2:cmd: " Menon, Nishanth
@ 2008-06-24 6:18 ` Sascha Hauer
2008-06-25 1:46 ` [U-Boot-Users] [Patch 5/9 Try 4]U-boot-V2:cmd: " Menon, Nishanth
0 siblings, 1 reply; 43+ messages in thread
From: Sascha Hauer @ 2008-06-24 6:18 UTC (permalink / raw)
To: u-boot
On Sun, Jun 22, 2008 at 01:56:12PM -0500, Menon, Nishanth wrote:
> i2cdev command is introduced here. This allows
> for device creation for doing i2c ops. With tab
> indents corrected.
Nice and short ;) , just one comment...
+
> + while ((opt = getopt(argc, argv, "arb:d:")) > 0) {
> + switch (opt) {
> + case 'a':
> + if (rem) {
> + fprintf(stderr,
> + "you cannot add when you selected "
> + "delete!\n");
> + goto fail_ret;
> + }
> + add = 1;
> + break;
> + case 'r':
> + if (add) {
> + fprintf(stderr,
> + "you cannot delete when you selected "
> + "add!\n");
> + goto fail_ret;
> + }
> + rem = 1;
> + break;
> + case 'b':
> + bus_dev = optarg;
> + break;
> + case 'd':
> + dev_addr = (int)simple_strtoul(optarg, NULL, 10);
> + if (dev_addr > 0xFF) {
> + fprintf(stderr, "I2C address are b/w 0 and "
> + "0x7f\n");
> + goto fail_ret;
> + }
> + break;
> + default:
> + fprintf(stderr, "unknown arg %s\n", opt);
> + goto fail_ret;
> + }
> + }
Instead of two seperate if claues above:
if (add && rem) {
printf("both remove and add are selected\n");
goto fail_ret;
}
Regards,
Sascha
--
Pengutronix e.K. - Linux Solutions for Science and Industry
-----------------------------------------------------------
Kontakt-Informationen finden Sie im Header dieser Mail oder
auf der Webseite -> http://www.pengutronix.de/impressum/ <-
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 5/9 Try 4]U-boot-V2:cmd: add I2C commands
2008-06-24 6:18 ` Sascha Hauer
@ 2008-06-25 1:46 ` Menon, Nishanth
0 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-25 1:46 UTC (permalink / raw)
To: u-boot
i2cdev command is introduced here. This allows
for device creation for doing i2c ops.
This is based on the discussion here:
http://www.nabble.com/-Patch-0-9--U-boot-V2%3A-
Introduce-I2C-support-for-SDP3430-to17981717.html
#a18029740
Comments from sacha incorporated.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
Documentation/commands.dox | 1
commands/Kconfig | 4
commands/i2c.c | 204 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 209 insertions(+)
Index: u-boot-v2.git/Documentation/commands.dox
===================================================================
--- u-boot-v2.git.orig/Documentation/commands.dox 2008-06-24 16:59:06.000000000 -0500
+++ u-boot-v2.git/Documentation/commands.dox 2008-06-24 17:00:03.000000000 -0500
@@ -20,5 +20,6 @@
- @subpage setenv_command
- @subpage sh_command
- @subpage unprotect_command
+ - @subpage page_do_cmd_i2cdev
*/
Index: u-boot-v2.git/commands/Kconfig
===================================================================
--- u-boot-v2.git.orig/commands/Kconfig 2008-06-24 16:59:05.000000000 -0500
+++ u-boot-v2.git/commands/Kconfig 2008-06-24 19:27:43.000000000 -0500
@@ -180,6 +180,10 @@
prompt "nand"
endmenu
+config CMD_I2C
+ depends on I2C_CHARDEV
+ tristate
+ prompt "i2cdev"
menu "booting "
Index: u-boot-v2.git/commands/i2c.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/commands/i2c.c 2008-06-24 18:07:17.000000000 -0500
@@ -0,0 +1,204 @@
+/**
+ * @file
+ * @brief I2C related applications
+ *
+ * FileName: commands/i2c.c
+ *
+ * This provides for creation of i2c device specific node
+ * for a given bus.
+ *
+ */
+/*
+ * This implementation is heavily influenced by the valuable inputs from
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <fs.h>
+#include <getopt.h>
+#include <linux/i2c-dev.h>
+
+static const __maybe_unused char cmd_i2cdev_s[] =
+ "Usage:\n"
+ " i2cdev [-a|-r] -b bus_dev -d dev_addr\n"
+ "Where:\n"
+ "-a Add a new device node\n"
+ "-r Remove existing device node\n"
+ "-b bus_dev i2c bus device to operate on\n"
+ "-d dev_addr Device address for which to create\n";
+
+static int do_cmd_i2cdev(cmd_tbl_t *cmdtp, int argc, char *argv[])
+{
+ char *bus_dev = NULL;
+ int dev_addr = -1;
+ int opt, file, ret;
+ char add = 0, rem = 0;
+ getopt_reset();
+
+ while ((opt = getopt(argc, argv, "arb:d:")) > 0) {
+ switch (opt) {
+ case 'a':
+ add = 1;
+ break;
+ case 'r':
+ rem = 1;
+ break;
+ case 'b':
+ bus_dev = optarg;
+ break;
+ case 'd':
+ dev_addr = (int)simple_strtoul(optarg, NULL, 10);
+ if (dev_addr > 0xFF) {
+ fprintf(stderr, "I2C address are b/w 0 and "
+ "0x7f\n");
+ goto fail_ret;
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown arg %s\n", opt);
+ goto fail_ret;
+ }
+ }
+
+ /* check args */
+ if (add && rem) {
+ fprintf(stderr, "You cannot add and remove at the same time\n");
+ goto fail_ret;
+ }
+ if (!(add + rem) || (bus_dev == NULL) || (dev_addr < 0)) {
+ fprintf(stderr, "not enough arguments\n");
+ goto fail_ret;
+ }
+
+ file = open(bus_dev, O_RDONLY);
+ if (file < 0) {
+ perror(argv[0]);
+ goto fail_ret;
+ }
+
+ if (add)
+ ret = ioctl(file, I2C_SLAVE_ADD, (void *)dev_addr);
+ else
+ ret = ioctl(file, I2C_SLAVE_REM, (void *)dev_addr);
+ if (ret)
+ fprintf(stderr, "Operation failed-%d!\n", ret);
+
+ close(file);
+ return (ret) ? 1 : 0;
+
+fail_ret:
+ u_boot_cmd_usage(cmdtp);
+ return 1;
+}
+U_BOOT_CMD_START(i2cdev)
+ .maxargs = 6,
+ .cmd = do_cmd_i2cdev,
+ .usage = "program to add a new i2cdevice",
+ U_BOOT_CMD_HELP(cmd_i2cdev_s)
+U_BOOT_CMD_END
+/** @page page_do_cmd_i2cdev i2cdev creates a I2C device node
+SYNOPSIS:
+ at li i2cdev [-a|-r] -b bus_dev -d dev_addr
+
+DESCRIPTION:
+ at verbatim
+ This program allows creation of device nodes corresponding
+ to a I2C device address on an I2C bus. This allows users
+ to do read or write access to a specific I2C device using
+ standard commands.
+ NOTE: i2cbusses are created by default once CHARDEV is
+ enabled during compilation.
+ at endverbatim
+OPTIONS:
+ at verbatim
+ -a Add a new device node
+ -r Remove existing device node
+ -b bus_dev i2c bus device to operate on
+ -d dev_addr Device address for which to create
+ at endverbatim
+
+ at warning Doing a blind probe on i2c bus is NOT RECOMMENDED unless
+you really know what you are doing!! These programs can confuse your
+I2C bus, cause data loss and worse!! Even Read/Write is to be used with
+absolute care and knowledge. If you need to know I2C specification, refer:
+http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
+
+EXAMPLE USAGE:
+ at li Scan the i2cbus for all devices present:
+ at verbatim
+$ md -b -s /dev/i2cbus0
+00000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000040: ff ff ff ff ff ff ff ff 48 49 4a 4b ff ff ff ff ........HIJK....
+00000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
+
+NOTE: 0xff means there are no devices present there. This example shows that
+there are devices on 0x48-0x4B. The md operation on a bus device does a 0 byte
+read (See warning).
+ at endverbatim
+
+ at li Create a new device node(if the device is present) on /dev/i2cbus0_49:
+ at verbatim
+ i2cdev -a -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Remove a existing device node (/dev/i2cbus0_49):
+ at verbatim
+ i2cdev -r -b /dev/i2cbus0 -d 0x49
+ at endverbatim
+
+ at li Dump all registers of device 0n bus 0 device address 0x49:
+ at verbatim
+$ md -b -s /dev/i2cbus0_49
+00000000: 00 00 00 00 00 00 00 00 00 00 0f 0f 0f 0f 00 00 ................
+00000010: 3f 3f 3f 3f 25 00 00 00 00 32 32 32 32 00 00 55 ????%....2222..U
+00000020: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 ................
+00000030: 13 00 00 00 00 79 11 00 00 00 06 00 44 69 00 00 .....y......Di..
+00000040: 00 00 00 00 32 00 00 00 00 00 00 00 00 00 00 1b ....2...........
+00000050: 00 00 03 f0 05 00 00 00 1a 1a 00 00 00 00 00 00 ................
+00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00000080: 00 20 00 00 00 2f 00 09 50 ff ff ff ff ff ff ff . .../..P.......
+00000090: ff 90 00 00 55 00 00 00 03 00 00 00 00 00 00 00 ....U...........
+000000a0: 00 00 00 00 00 00 00 00 00 00 04 15 50 01 44 05 ............P.D.
+000000b0: 00 00 00 00 ff ff 03 00 00 00 ff ff 03 00 00 00 ................
+000000c0: 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
+000000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ at endverbatim
+
+ at li Set a value 0xaa to register 1 on device 0x49, bus 0 and check if set:
+ at verbatim
+$ mw -b -d /dev/i2cbus0_49 0x1 0xaa
+$ md -b -s /dev/i2cbus0_49 0x1+1
+00000001: aa .
+@endverbatim
+ */
^ permalink raw reply [flat|nested] 43+ messages in thread
* [U-Boot-Users] [Patch 6/9]U-boot-V2:cmd: I2C commands support
2008-06-18 20:44 ` Robert Schwebel
` (6 preceding siblings ...)
2008-06-19 15:12 ` [U-Boot-Users] [Patch 5/9]U-boot-V2:cmd: add I2C commands Menon, Nishanth
@ 2008-06-19 15:12 ` Menon, Nishanth
2008-06-19 15:13 ` [U-Boot-Users] [Patch 7/9]U-boot-V2:ARM:OMAP: OMAP classes Menon, Nishanth
` (2 subsequent siblings)
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:12 UTC (permalink / raw)
To: u-boot
This adds i2c documentation, build options
for i2c commands and a support header.
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
Documentation/commands.dox | 4
commands/Kconfig | 31 +++++
commands/i2c.c | 233 +++++++++++++++++++++++++++++++++++++++++++++
commands/i2c.h | 65 ++++++++++++
4 files changed, 333 insertions(+)
Index: u-boot-v2.git/commands/i2c.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/commands/i2c.h 2008-06-19 09:31:42.000000000 -0500
@@ -0,0 +1,65 @@
+/**
+ * @file
+ * @brief I2C Commands specific header.
+ *
+ * FileName: commands/i2c.h
+ * This provides i2cdump, i2cdetect, i2cset and i2cget appplications
+ * The code originates from the i2c-tools located here:
+ * http://www.lm-sensors.org/wiki/I2CTools
+ * This is used by the c file
+ */
+/*
+ * (C) Copyright 2006-2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * This application is based on the following:
+ *
+ * i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
+ * Part of user-space programs to access for I2C
+ * devices.
+ * Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
+ * i2cdump.c - a user-space program to dump I2C registers
+ * Copyright (C) 2002-2003 Frodo Looijaard <frodol@dds.nl>, and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
+ * i2cget.c - A user-space program to read an I2C register.
+ * Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
+ * i2cset.c - A user-space program to write an I2C register.
+ * Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
+ * Mark D. Studebaker <mdsxyz123@yahoo.com>
+ * Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef __CMD_I2C_H
+#define __CMD_I2C_H
+
+/*********** "USER SPACE I2C Access APIs" ************/
+
+int lookup_i2c_bus(const char *i2cbus_arg);
+int open_i2c_dev(const int i2cbus, char *filename, const int quiet);
+int parse_i2c_address(const char *address_arg);
+int set_slave_addr(int file, int address, int force);
+int check_funcs(int file, int size, int daddress, int pec);
+int read_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
+ size_t count);
+int write_i2c(int file, uchar daddr, u16 addr, u8 reg_width, char *buffer,
+ size_t count);
+#endif /* __CMD_I2C_H */
Index: u-boot-v2.git/Documentation/commands.dox
===================================================================
--- u-boot-v2.git.orig/Documentation/commands.dox 2008-06-19 09:29:03.000000000 -0500
+++ u-boot-v2.git/Documentation/commands.dox 2008-06-19 09:31:42.000000000 -0500
@@ -20,5 +20,9 @@
- @subpage setenv_command
- @subpage sh_command
- @subpage unprotect_command
+ - @subpage page_do_cmd_i2c_detect
+ - @subpage page_do_cmd_i2c_dump
+ - @subpage page_do_cmd_i2c_get
+ - @subpage page_do_cmd_i2c_set
*/
Index: u-boot-v2.git/commands/Kconfig
===================================================================
--- u-boot-v2.git.orig/commands/Kconfig 2008-06-19 09:29:03.000000000 -0500
+++ u-boot-v2.git/commands/Kconfig 2008-06-19 09:31:42.000000000 -0500
@@ -180,6 +180,37 @@
prompt "nand"
endmenu
+menu "i2c "
+ depends on I2C_CHARDEV
+
+config CMD_I2C
+ bool
+ default n
+
+config CMD_I2C_DETECT
+ tristate
+ default y
+ select CMD_I2C
+ prompt "i2cdetect"
+
+config CMD_I2C_DUMP
+ tristate
+ default y
+ select CMD_I2C
+ prompt "i2cdump"
+
+config CMD_I2C_GET
+ tristate
+ default y
+ select CMD_I2C
+ prompt "i2cget"
+
+config CMD_I2C_SET
+ tristate
+ default y
+ select CMD_I2C
+ prompt "i2cset"
+endmenu
menu "booting "
Index: u-boot-v2.git/commands/i2c.c
===================================================================
--- u-boot-v2.git.orig/commands/i2c.c 2008-06-19 09:31:49.000000000 -0500
+++ u-boot-v2.git/commands/i2c.c 2008-06-19 09:32:57.000000000 -0500
@@ -515,6 +515,64 @@
U_BOOT_CMD_HELP(cmd_i2cdetect_help_s)
U_BOOT_CMD_END
#endif /* CONFIG_CMD_I2C_DETECT */
+/** @page page_do_cmd_i2c_detect i2cdetect detect I2C chips
+SYNOPSIS:
+ at li i2cdetect [-a] [-q|-r] i2cbus [first last]
+ at li i2cdetect -F i2cbus
+
+ at warning
+ This program can confuse your I2C bus, cause data loss and worse!
+
+DESCRIPTION:
+ at verbatim
+ i2cdetect is a program to scan an I2C bus for devices. It
+ outputs a table with the list of detected devices on the specified bus.
+ i2cbus indicates the number of the I2C bus to be scanned, these are
+ present as 'xx' of /dev/i2cdxx. The optional parameters first and
+ last restrict the scanning range (default: from 0x03 to 0x77).
+
+ i2cdetect can also be used to query the functionalities of an I2C bus
+ (see option -F.)
+ at endverbatim
+
+INTERPRETING THE OUTPUT:
+ at verbatim
+ Each cell in the output table will contain one of the following sym
+ bols:
+
+ ?? "--". The address was probed but no chip answered.
+
+ ?? "UU". Probing was skipped, because this address is currently in use
+ by a driver. This strongly suggests that there is a chip at this
+ address.
+
+ ?? An address number in hexadecimal, e.g. "2d" or "4e". A chip was found
+ at this address.
+ at endverbatim
+
+OPTIONS:
+ at verbatim
+ -a Force scanning of non-regular addresses. Not recommended.
+
+ -q Use "quick write" commands for probing. Not recommended.
+
+ -r Use "read byte" commands for probing. Not recommended.
+ This is known to lock on various write-only chips.
+
+ -F Display the list of functionalities implemented by the adapter
+ and exit.
+
+ at endverbatim
+
+AUTHOR:
+ at verbatim
+ Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+ This manual page was originally written by Aurelien Jarno
+ <aurel32@debian.org>, for the Debian GNU/Linux system.
+
+ at endverbatim
+ */
#ifdef CONFIG_CMD_I2C_DUMP
static const __maybe_unused char cmd_i2cdump_help_s[] =
@@ -789,6 +847,66 @@
U_BOOT_CMD_HELP(cmd_i2cdump_help_s)
U_BOOT_CMD_END
#endif /* CONFIG_CMD_I2C_DUMP */
+/** @page page_do_cmd_i2c_dump i2cdump examine I2C registers
+SYNOPSIS
+ at li i2cdump [-f] [-r first-last] i2cbus address [mode]
+
+ at warning
+ i2cdump can be dangerous if used improperly. Most notably, the c mode
+ starts with WRITING a byte to the chip. On most chips it will be stored
+ in the address pointer register, which is OK, but some chips with a
+ single register or no (visible) register at all will most likely see
+ this as a real WRITE, resulting in possible misbehavior or corruption.
+ Do not use i2cdump on random addresses. Anyway, it is of little use
+ unless you have good knowledge of the chip you??(tm)re working with and an
+ idea of what you are looking for.
+
+DESCRIPTION:
+ at verbatim
+ i2cdump is a small helper program to examine registers visible through
+ the I2C bus.
+ at endverbatim
+
+OPTIONS:
+ at verbatim
+ -f Force access to the device even if it is already busy. By
+ default, i2cdump will refuse to access a device which is already
+ under the control of a kernel driver. Using this flag is danger???
+ ous, it can seriously confuse the kernel driver in question. It
+ can also cause i2cdump to return invalid results. So use at your
+ own risk and only if you know what you??(tm)re doing.
+
+ -r first-last
+ Limit the range of registers being accessed. This option is only
+ available with modes b, w, c and W. For mode W, first must be
+ even and last must be odd.
+
+ At least two options must be provided to i2cdump. i2cbus indicates the
+ number of the I2C bus to be scanned, these are present as 'xx' of
+ /dev/i2cdxx. The optional parameters first and address indicates
+ the address to be scanned on that bus, and is an integer between
+ 0x03 and 0x77.
+
+ The mode parameter, if specified, is one of the letters b, w,
+ corresponding to a read size of a single byte, a 16-bit word,
+ respectively.The W mode is also special, it is similar to w except that
+ a read command will only be issued on even register addresses;
+ this is again mainly useful for EEPROMs.
+
+ A p can also be appended to the mode parameter (except for i and W) to
+ enable PEC. If the mode parameter is omitted, i2cdump defaults to byte
+ access without PEC.
+
+ at endverbatim
+
+AUTHOR
+ at verbatim
+ Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+ This manual page was originally written by David Z Maze
+ <dmaze@debian.org> for the Debian GNU/Linux system.
+ at endverbatim
+ */
#ifdef CONFIG_CMD_I2C_GET
static const __maybe_unused char cmd_i2cget_help_s[] =
@@ -992,6 +1110,57 @@
U_BOOT_CMD_HELP(cmd_i2cget_help_s)
U_BOOT_CMD_END
#endif /* CONFIG_CMD_I2C_GET */
+/** @page page_do_cmd_i2c_get i2cget read from I2C chip registers
+SYNOPSIS
+ at li i2cget [-f] [-y] i2cbus chip-address [data-address [mode]]
+
+ at warning
+ i2cget can be extremely dangerous if used improperly.
+ Be extremely careful using this program.
+
+DESCRIPTION:
+ at verbatim
+ i2cget is a small helper program to read registers visible through the
+ I2C bus.
+ at endverbatim
+
+OPTIONS
+ at verbatim
+ -f Force access to the device even if it is already busy. By
+ default, i2cget will refuse to access a device which is already
+ under the control of a kernel driver. Using this flag is danger
+ ous, it can seriously confuse the kernel driver in question. It
+ can also cause i2cget to return an invalid value. So use at your
+ own risk and only if you know what you??(tm)re doing.
+
+ -y will allow to set 0x50 to 0x57 with pec enabled
+
+ At least two options must be provided to i2cget. i2cbus indicates the
+ number of the I2C bus to be scanned, these are present as 'xx' of
+ /dev/i2cdxx. chip-address specifies the address of the chip on
+ that bus, and is an integer between 0x03 and 0x77.
+
+ data-address specifies the address on that chip to read from, and is an
+ integer between 0x00 and 0xFF. If omitted, the currently active regis
+ ter will be read (if that makes sense for the considered chip).
+
+ The mode parameter, if specified, is one of the letters b, w or c, cor
+ responding to a read byte data, a read word data or a write byte/read
+ byte transaction, respectively. A p can also be appended to the mode
+ parameter to enable PEC. If the mode parameter is omitted, i2cget
+ defaults to a read byte data transaction, unless data-address is also
+ omitted, in which case the default (and only valid) transaction is a
+ single read byte.
+ at endverbatim
+
+AUTHOR
+ at verbatim
+ Jean Delvare
+
+ This manual page was strongly inspired from those written by David Z
+ Maze for i2cset.
+ at endverbatim
+*/
#ifdef CONFIG_CMD_I2C_SET
static const __maybe_unused char cmd_i2cset_help_s[] =
@@ -1266,3 +1435,67 @@
U_BOOT_CMD_HELP(cmd_i2cset_help_s)
U_BOOT_CMD_END
#endif /* CONFIG_CMD_I2C_SET */
+/** @page page_do_cmd_i2c_set i2cset set I2C registers
+
+SYNOPSIS
+ at li i2cset [-f] [-y] i2cbus chip-address data-address [value [mode [mask]]]
+
+ at warning
+ i2cset can be extremely dangerous if used improperly. It can confuse
+ your I2C bus, cause data loss, or have more serious side effects. Writ
+ ing to a serial EEPROM on a memory DIMM (chip addresses between 0x50
+ and 0x57) may DESTROY your memory! Be extremely careful using this
+ program.
+
+DESCRIPTION
+ at verbatim
+ i2cset is a small helper program to set registers visible through the
+ I2C bus.
+ at endverbatim
+
+OPTIONS
+ at verbatim
+ -f Force access to the device even if it is already busy. By
+ default, i2cset will refuse to access a device which is already
+ under the control of a kernel driver. Using this flag is danger
+ ous, it can seriously confuse the kernel driver in question. It
+ can also cause i2cset to silently write to the wrong register.
+ So use at your own risk and only if you know what you are
+ doing.
+
+ -y will allow to set 0x50 to 0x57 with pec enabled
+
+ There are three required options to i2cset. i2cbus indicates the number
+ of the I2C bus to be scanned, these are present as 'xx' of /dev/i2cdxx.
+ chip-address specifies the address of th chip on that bus, and is
+ an integer between 0x03 and 0x77. data-address specifies the address on
+ that chip to write to, and is an integer between 0x00 and 0xFF.
+
+ The value parameter, if specified, is the value to write to that loca
+ tion on the chip. If this parameter is omited, then a short write is
+ issued. For most chips, it simply sets an internal pointer to the tar
+ get location, but doesn??(tm)t actually write to that location. For a few
+ chips though, in particular simple ones with a single register, this
+ short write is an actual write.
+
+ The mode parameter, if specified, is one of the letters b or w, corre
+ sponding to a write size of a single byte or a 16-bit word, respec
+ tively. A p can also be appended to the mode parameter to enable PEC.
+ If the mode parameter is omitted, i2cset defaults to byte mode without
+ PEC. The value provided must be within range for the specified data
+ type (0x00-0xFF for bytes, 0x0000-0xFFFF for words).
+
+ The mask parameter, if specified, describes which bits of value will be
+ actually written to data-address. Bits set to 1 in the mask are taken
+ from value, while bits set to 0 will be read from data-address and thus
+ preserved by the operation.
+ at endverbatim
+
+AUTHOR
+ at verbatim
+ Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+ This manual page was originally written by David Z Maze
+ <dmaze@debian.org> for the Debian GNU/Linux system.
+ at endverbatim
+*/
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 7/9]U-boot-V2:ARM:OMAP: OMAP classes
2008-06-18 20:44 ` Robert Schwebel
` (7 preceding siblings ...)
2008-06-19 15:12 ` [U-Boot-Users] [Patch 6/9]U-boot-V2:cmd: I2C commands support Menon, Nishanth
@ 2008-06-19 15:13 ` Menon, Nishanth
2008-06-19 15:13 ` [U-Boot-Users] [Patch 8/9]U-boot-V2:I2C:Busses: OMAP I2C Adapter Menon, Nishanth
2008-06-19 15:13 ` [U-Boot-Users] [Patch 9/9]U-boot-V2:Boards:SDP3430 I2C bus1 Menon, Nishanth
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:13 UTC (permalink / raw)
To: u-boot
Introduce cpu_is_xxxx macros similar to the one
in 2.6.26 rc5 kernel, this allows for compile
time optimization of CPU specific code in common
drivers. Resending this for keeping the series
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
include/asm-arm/arch-omap/silicon.h | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
Index: u-boot-v2.git/include/asm-arm/arch-omap/silicon.h
===================================================================
--- u-boot-v2.git.orig/include/asm-arm/arch-omap/silicon.h 2008-06-19 08:39:58.000000000 -0500
+++ u-boot-v2.git/include/asm-arm/arch-omap/silicon.h 2008-06-19 08:51:07.000000000 -0500
@@ -24,6 +24,34 @@
/* Each platform silicon header comes here */
#ifdef CONFIG_ARCH_OMAP3
#include <asm/arch/omap3-silicon.h>
+#define cpu_is_omap34xx() 1
+#else
+#define cpu_is_omap34xx() 0
+#endif
+
+/* The following architectures are TBD */
+#ifdef CONFIG_ARCH_OMAP2430
+#define cpu_is_omap2430() 1
+#else
+#define cpu_is_omap2430() 0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+#define cpu_is_omap2420() 1
+#else
+#define cpu_is_omap2420() 0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define cpu_is_omap16xx() 1
+#else
+#define cpu_is_omap16xx() 0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP15XX
+#define cpu_is_omap15xx() 1
+#else
+#define cpu_is_omap15xx() 0
#endif
/* If Architecture specific init functions are present */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 8/9]U-boot-V2:I2C:Busses: OMAP I2C Adapter
2008-06-18 20:44 ` Robert Schwebel
` (8 preceding siblings ...)
2008-06-19 15:13 ` [U-Boot-Users] [Patch 7/9]U-boot-V2:ARM:OMAP: OMAP classes Menon, Nishanth
@ 2008-06-19 15:13 ` Menon, Nishanth
2008-06-19 15:13 ` [U-Boot-Users] [Patch 9/9]U-boot-V2:Boards:SDP3430 I2C bus1 Menon, Nishanth
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:13 UTC (permalink / raw)
To: u-boot
Introduce the i2c adapter for OMAP i2c controller
This is mostly a port from 2.6.26 rc5 kernel at:
http://git.kernel.org/git/?p=linux/kernel/git/tmlind/linux-omap-2.6.git
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
drivers/i2c/busses/Kconfig | 7
drivers/i2c/busses/i2c-omap.c | 678 ++++++++++++++++++++++++++++++++++++++++
include/asm-arm/arch-omap/i2c.h | 154 +++++++++
3 files changed, 839 insertions(+)
Index: u-boot-v2.git/drivers/i2c/busses/i2c-omap.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/busses/i2c-omap.c 2008-06-19 08:51:23.000000000 -0500
@@ -0,0 +1,678 @@
+/**
+ * @file
+ * @brief OMAP I2C Adapter driver
+ *
+ * FileName: drivers/i2c/busses/i2c-omap.c
+ *
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * based on Linux kernel omap i2c adapter driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjola <juha.yrjola@nokia.com>
+ * Syed Khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <errno.h>
+#include <init.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <clock.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
+#include <asm/arch/silicon.h>
+#include <asm/arch/i2c.h>
+
+/*---------------------- Debug Messages -------------------------------------*/
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define DBG_MODULE_NAME "omap-i2c"
+#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
+#define dev_warn(ARGS...) fprintf(stderr, ARGS);
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
+ DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
+ __func__, __LINE__, ARGS)
+#else
+#define dev_dbg(ARGS...)
+#define dev_warn(ARGS...)
+#define dbg_entry(FORMAT, ARGS...)
+#define dbg_exit(FORMAT, ARGS...)
+#endif
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+/*---------------------- Defines --------------------------------------------*/
+/* Hack to enable zero length transfers and smbus quick until clean fix
+ is available */
+#define OMAP_HACK
+
+/*---------------------- Private Data Structures ----------------------------*/
+struct omap_i2c_dev {
+ unsigned long base; /* virtual */
+ u32 speed; /* Speed of bus in Khz */
+ u32 fclk; /* Functional clock speed */
+ u16 cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ u8 fifo_size; /* use as flag and value
+ * fifo_size==0 implies no fifo
+ * if set, should be trsh+1
+ */
+ unsigned rev1:1;
+ unsigned b_hw:1; /* bad h/w fixes */
+};
+
+/*---------------------- Implementation -------------------------------------*/
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ dbg_entry("i2c_dev=%x reg=%x val=%x", (u32) i2c_dev, reg, val);
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+ dbg_entry("i2c_dev=%x reg=%x", (u32) i2c_dev, reg);
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+ u16 psc = 0, scll = 0, sclh = 0;
+ u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
+ unsigned long fclk_rate = 12000000;
+ unsigned long internal_clk = 0;
+
+ dbg_entry("dev=%x", (u32) dev);
+ if (!dev->rev1) {
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ uint64_t timeout = OMAP_I2C_TIMEOUT;
+ uint64_t start;
+
+ start = get_time_ns();
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+ OMAP_I2C_SYSS_RDONE)) {
+ if (is_timeout(start, timeout)) {
+ dev_err("timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ }
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+
+ /* HSI2C controller internal clk rate should be 19.2 Mhz */
+ if (dev->speed > 400)
+ internal_clk = 19200;
+ else if (dev->speed > 100)
+ internal_clk = 9600;
+ else
+ internal_clk = 4000;
+ fclk_rate = dev->fclk / 1000;
+
+ /* Compute prescaler divisor */
+ psc = fclk_rate / internal_clk;
+ psc = psc - 1;
+
+ /* If configured for High Speed */
+ if (dev->speed > 400) {
+ /* For first phase of HS mode */
+ fsscll = internal_clk / (400 * 2) - 7;
+ fssclh = internal_clk / (400 * 2) - 5;
+
+ /* For second phase of HS mode */
+ hsscll = fclk_rate / (dev->speed * 2) - 7;
+ hssclh = fclk_rate / (dev->speed * 2) - 5;
+ } else {
+ /* To handle F/S modes */
+ fsscll = internal_clk / (dev->speed * 2) - 7;
+ fssclh = internal_clk / (dev->speed * 2) - 5;
+ }
+ scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+ sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+ dev_dbg("base=%x,fclk=%d fclk_rate =%d, iclk=%d dev->speed=%d\n"
+ "psc=%x fsscll=%x fssclh=%x hsscll=%x hssclh=%x\n"
+ "scll=%x sclh=%x\n",
+ dev->base, dev->fclk, fclk_rate, internal_clk,
+ dev->speed, psc, fsscll, fssclh, hsscll, hssclh,
+ scll, sclh);
+ } else {
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+ scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+ sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* SCL low and high time values */
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
+
+ if (dev->fifo_size)
+ /* Note: setup required fifo size - 1 */
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+ (dev->fifo_size - 1) << 8 | /* RTRSH */
+ OMAP_I2C_BUF_RXFIF_CLR |
+ (dev->fifo_size - 1) | /* XTRSH */
+ OMAP_I2C_BUF_TXFIF_CLR);
+
+ /* DO NOT Enable interrupts -we work in polling mode */
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ uint64_t start, timeout;
+
+ dbg_entry("dev=%x", (u32) dev);
+
+ timeout = OMAP_I2C_TIMEOUT;
+ start = get_time_ns();
+
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (is_timeout(start, timeout)) {
+ dev_err("timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int omap_i2c_rev1_wait_event(struct omap_i2c_dev *dev, uint64_t timeout)
+{
+ u16 iv, w;
+ int stat = 0;
+ uint64_t start;
+
+ start = get_time_ns();
+ dbg_entry("dev=%x", (u32) dev);
+ /* we dont have anything better to do..
+ * So poll the status reg
+ */
+ while (!stat) {
+ if (is_timeout(start, timeout)) {
+ dev_err("waitevent Timeout!");
+ stat = -ETIMEDOUT;
+ continue;
+ }
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x01: /* Arbitration lost */
+ dev_err("Arbitration lost\n");
+ dev->cmd_err = OMAP_I2C_STAT_AL;
+ return 0;
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
+ dev->cmd_err = OMAP_I2C_STAT_NACK;
+ return 0;
+ break;
+ case 0x03: /* Register access ready */
+ dev->cmd_err = 0;
+ return 0;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else {
+ dev_err("RRDY IRQ while no data requested\n");
+ stat = -2;
+ }
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else {
+ dev_err("XRDY IRQ while no data to send\n");
+ stat = -1;
+ }
+ case 0x00: /* None */
+ /* default.. continue to wait */
+ break;
+ }
+ }
+
+ return stat;
+}
+
+static int omap_i2c_wait_event(struct omap_i2c_dev *dev, uint64_t timeout)
+{
+ u16 bits;
+ u16 stat, w;
+ int err;
+ uint64_t start;
+ dev_dbg("dev=%x timeout=%x", (u32) dev, timeout);
+
+ bits = OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ARDY |
+ OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR;
+
+ start = get_time_ns();
+ /* We will exit out of this loop eventually.
+ * Trusting the hardware?
+ */
+ while (1) {
+ stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)) & bits;
+
+ /* No Stat update? re-read */
+ if (!stat) {
+ if (is_timeout(start, timeout)) {
+ dev_err("waitevent Timeout!\n");
+ return -ETIMEDOUT;
+ }
+ continue;
+ }
+
+ /* Ack other signals, but NOT RDY signals -> we need to do
+ * that after transfer of data
+ */
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+ ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+ OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
+ err = 0;
+ if (stat & OMAP_I2C_STAT_NACK) {
+ dev_dbg("Nacked!\n", stat);
+ err |= OMAP_I2C_STAT_NACK;
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err("Arbitration lost\n");
+ err |= OMAP_I2C_STAT_AL;
+ }
+ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+ OMAP_I2C_STAT_AL)) {
+ dev->cmd_err = err;
+ return 0;
+ }
+
+ if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ num_bytes =
+ (stat & OMAP_I2C_STAT_RRDY) ? dev->
+ fifo_size : omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ dev_err
+ ("RRDY IRQ while no data "
+ "requested\n");
+ if (stat & OMAP_I2C_STAT_RDR)
+ dev_err("RDR IRQ while no data "
+ "requested\n");
+ return -2;
+ }
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+ (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+ }
+ if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ num_bytes =
+ (stat & OMAP_I2C_STAT_XRDY) ? dev->
+ fifo_size : omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ dev_err("XRDY IRQ while no "
+ "data to send\n");
+ if (stat & OMAP_I2C_STAT_XDR)
+ dev_err("XDR IRQ while no "
+ "data to send\n");
+ return -2;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+ (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err("Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err("Transmit overflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+#ifdef OMAP_HACK
+ u8 zero_byte = 0;
+#endif
+ int r;
+ u16 w;
+
+ dbg_entry("adap=%x msg=%s stop=%x", (u32) adap, (u32) msg, stop);
+ dev_dbg("addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+#ifndef OMAP_HACK
+ if (msg->len == 0)
+ return -EINVAL;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+#else
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+ /* REVISIT: Remove this hack when we can get I2C chips from board-*.c
+ * files
+ * Sigh, seems we can't do zero length transactions. Thus, we
+ * can't probe for devices w/o actually sending/receiving at least
+ * a single byte. So we'll set count to 1 for the zero length
+ * transaction case and hope we don't cause grief for some
+ * arbitrary device due to random byte write/read during
+ * probes.
+ */
+ if (msg->len == 0) {
+ dev->buf = &zero_byte;
+ dev->buf_len = 1;
+ } else {
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+ }
+#endif
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ /* Clear the FIFO Buffers */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+ /* High speed configuration */
+ if (dev->speed > 400)
+ w |= OMAP_I2C_CON_OPMODE_HS;
+
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+
+ if (!dev->b_hw && stop)
+ w |= OMAP_I2C_CON_STP;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ if (dev->b_hw && stop) {
+ /* H/w behavior: dont write stt and stp together.. */
+ while (omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+ OMAP_I2C_CON_STT) {
+ /* Dont do anything - this will come in a
+ * couple of loops at max */
+ }
+ w |= OMAP_I2C_CON_STP;
+ w &= ~OMAP_I2C_CON_STT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ /* We dont get data in one millisec.. some thing is definitely
+ * and badly wrong!! */
+ if ((cpu_is_omap15xx()) && dev->rev1)
+ r = omap_i2c_rev1_wait_event(dev, MSECOND);
+ else
+ r = omap_i2c_wait_event(dev, MSECOND);
+ dev->buf_len = 0;
+ if (r < 0) {
+ dev_err("controller error %d\n", r);
+ omap_i2c_init(dev);
+ return r;
+ }
+
+ if (!dev->cmd_err)
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF)) {
+ /* Reprogram the controller ->NOTE 2 as in flow chart of TRM */
+ omap_i2c_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ /* Reprogram the controller ->NOTE 2 as in flow chart of TRM */
+ omap_i2c_init(dev);
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during transfer processing
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ dbg_entry("adap=%x msgs=%x num=%x", (u32) adap, (u32) msgs, num);
+ r = omap_i2c_wait_for_bb(dev);
+ if (r < 0) {
+ dev_err("timedout waiting for bus to free\n");
+ goto out;
+ }
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+out:
+ return r;
+}
+
+static u32 omap_i2c_func(struct i2c_adapter *adap)
+{
+ dbg_entry("adap=%x", (u32) adap);
+ return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int omap_register_i2c_bus(int bus_id, unsigned long base,
+ u32 clkrate, u32 func_clk)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ int r = 0;
+ dbg_entry("bus_id=%x base=%x clkrate=%x func_clk=%x info=%x len=%x",
+ bus_id, base, clkrate, func_clk, (u32) info, len);
+ dev = calloc(sizeof(struct omap_i2c_dev), 1);
+ if (!dev) {
+ dev_err("malloc failed for omap_i2c_dev");
+ return -ENOMEM;
+ }
+
+ if (!clkrate)
+ clkrate = 100;
+
+ dev->speed = clkrate;
+ dev->fclk = func_clk;
+ dev->base = base;
+
+ if (cpu_is_omap15xx())
+ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ /* Set up the fifo size - Get total size */
+ dev->fifo_size = 0x8 <<
+ ((omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) &
+ 0x3);
+ /*
+ * Set up notification threshold as half the total available
+ * size. This is to ensure that we can handle the status on
+ * int call back latencies
+ */
+ dev->fifo_size = (dev->fifo_size / 2);
+ dev->b_hw = 1; /* Enable hardware fixes */
+ }
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(dev);
+
+ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev_dbg("bus %d rev%d.%d at %d kHz\n",
+ bus_id, r >> 4, r & 0xf, dev->speed);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = NULL;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ adap->nr = bus_id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err("failure adding adapter %d\n", r);
+ free(dev);
+ }
+ return r;
+}
+
+static int omap_i2c_probe(struct device_d *dev)
+{
+ struct i2c_omap_platform_data *i2cp =
+ (struct i2c_omap_platform_data *) (dev->platform_data);
+ if (i2cp == NULL) {
+ dev_err("I2c_OMAP: need platform data\n");
+ return -EINVAL;
+ }
+ return omap_register_i2c_bus(i2cp->bus_id,
+ dev->map_base,
+ i2cp->i2c_clock_speed,
+ i2cp->func_clk);
+}
+
+static struct driver_d omapi2c_drv = {
+ .name = OMAP_I2C_ADAPTER_NAME,
+ .probe = omap_i2c_probe,
+ .type = DEVICE_TYPE_I2C,
+};
+
+static int omap_i2cdrv_init(void)
+{
+ int ret;
+ ret = register_driver(&omapi2c_drv);
+ return ret;
+}
+device_initcall(omap_i2cdrv_init);
Index: u-boot-v2.git/drivers/i2c/busses/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/busses/Kconfig 2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/busses/Kconfig 2008-06-19 08:51:23.000000000 -0500
@@ -4,4 +4,11 @@
menu "I2C Hardware Bus support"
+config I2C_OMAP
+ bool "OMAP I2C adapter"
+ depends on ARCH_OMAP
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP family of processors.
+ For details see http://www.ti.com/omap.
endmenu
Index: u-boot-v2.git/include/asm-arm/arch-omap/i2c.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/asm-arm/arch-omap/i2c.h 2008-06-19 08:51:23.000000000 -0500
@@ -0,0 +1,154 @@
+/**
+ * @file
+ * @brief definitions for OMAP I2C Adapter driver
+ *
+ * FileName: include/asm-arm/arch-omap/i2c.h
+ *
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan@ti.com>
+ *
+ * based on Linux kernel omap i2c adapter driver.
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjola <juha.yrjola@nokia.com>
+ * Syed Khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_I2C_H
+#define __ASM_ARCH_OMAP_I2C_H
+
+/*********** Stuff Interesting to board files ***********/
+
+#define OMAP_I2C_FCLK_96MHZ (96 * 1000 * 1000)
+#define OMAP_I2C_FCLK_48MHZ (48 * 1000 * 1000)
+
+/* Some Common i2c speeds */
+#define OMAP_I2C_CLK_2P6M (2600)
+#define OMAP_I2C_CLK_400K (400)
+#define OMAP_I2C_CLK_100K (100)
+
+/** I2c platform data that is registered by board files */
+struct i2c_omap_platform_data {
+ /** Give the bus index here */
+ int bus_id;
+ /** required i2c clock speed in khz */
+ u32 i2c_clock_speed;
+ /** Func clk speed of i2c -based on clock arch */
+ u32 func_clk;
+};
+
+/** Use this when you define an adapter instance in board file */
+#define OMAP_I2C_ADAPTER_NAME "omap-i2c"
+
+/*********** Stuff Interesting to OMAP Adapter ***********/
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT MSECOND
+
+/* I2C Register defines */
+#define OMAP_I2C_REV_REG 0x00
+#define OMAP_I2C_IE_REG 0x04
+#define OMAP_I2C_STAT_REG 0x08
+#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_SYSS_REG 0x10
+#define OMAP_I2C_BUF_REG 0x14
+#define OMAP_I2C_CNT_REG 0x18
+#define OMAP_I2C_DATA_REG 0x1c
+#define OMAP_I2C_SYSC_REG 0x20
+#define OMAP_I2C_CON_REG 0x24
+#define OMAP_I2C_OA_REG 0x28
+#define OMAP_I2C_SA_REG 0x2c
+#define OMAP_I2C_PSC_REG 0x30
+#define OMAP_I2C_SCLL_REG 0x34
+#define OMAP_I2C_SCLH_REG 0x38
+#define OMAP_I2C_SYSTEST_REG 0x3c
+#define OMAP_I2C_BUFSTAT_REG 0x40
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drn int enable */
+#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drn int enable */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL 8
+#define OMAP_I2C_SCLH_HSSCLH 8
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+#endif
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
+#endif /* __ASM_ARCH_OMAP_I2C_H */
^ permalink raw reply [flat|nested] 43+ messages in thread* [U-Boot-Users] [Patch 9/9]U-boot-V2:Boards:SDP3430 I2C bus1
2008-06-18 20:44 ` Robert Schwebel
` (9 preceding siblings ...)
2008-06-19 15:13 ` [U-Boot-Users] [Patch 8/9]U-boot-V2:I2C:Busses: OMAP I2C Adapter Menon, Nishanth
@ 2008-06-19 15:13 ` Menon, Nishanth
10 siblings, 0 replies; 43+ messages in thread
From: Menon, Nishanth @ 2008-06-19 15:13 UTC (permalink / raw)
To: u-boot
Registers i2c adapters used when CONFIG_I2C_OMAP
is enabled in config.
This patch additionally fixes a minor sparse
warning sdram_dev
Signed-off-by: Nishanth Menon <x0nishan@ti.com>
---
board/omap/board-sdp343x.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
Index: u-boot-v2.git/board/omap/board-sdp343x.c
===================================================================
--- u-boot-v2.git.orig/board/omap/board-sdp343x.c 2008-06-19 08:39:57.000000000 -0500
+++ u-boot-v2.git/board/omap/board-sdp343x.c 2008-06-19 08:51:37.000000000 -0500
@@ -54,6 +54,7 @@
#include <asm/arch/syslib.h>
#include <asm/arch/control.h>
#include <asm/arch/omap3-mux.h>
+#include <asm/arch/i2c.h>
#include "board-sdp343x.h"
/******************** Board Boot Time *******************/
@@ -642,7 +643,7 @@
console_initcall(sdp3430_console_init);
#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
-struct device_d sdram_dev = {
+static struct device_d sdram_dev = {
.name = "ram",
.id = "ram0",
@@ -665,6 +666,21 @@
};
#endif
+#ifdef CONFIG_I2C_OMAP
+static struct i2c_omap_platform_data sdp343_i2c1 = {
+ .bus_id = 0,
+ .i2c_clock_speed = OMAP_I2C_CLK_2P6M,
+ .func_clk = OMAP_I2C_FCLK_96MHZ,
+};
+static struct device_d sdp3430_i2c1 = {
+ .name = OMAP_I2C_ADAPTER_NAME,
+ .id = "omap-i2c0",
+ .map_base = OMAP_I2C1_BASE,
+ .platform_data = (void *)&sdp343_i2c1,
+ .type = DEVICE_TYPE_I2C,
+};
+#endif
+
static int sdp3430_devices_init(void)
{
int ret;
@@ -676,6 +692,12 @@
if (ret)
goto failed;
#endif
+#ifdef CONFIG_I2C_OMAP
+ ret = register_device(&sdp3430_i2c1);
+ if (ret)
+ goto failed;
+#endif
+
failed:
return ret;
}
^ permalink raw reply [flat|nested] 43+ messages in thread