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 <[EMAIL PROTECTED]> --- 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 <[EMAIL PROTECTED]> + */ +/* + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard <[EMAIL PROTECTED]> + + 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 <[EMAIL PROTECTED]> + */ +/* + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard <[EMAIL PROTECTED]> + Copyright (C) 2003 Greg Kroah-Hartman <[EMAIL PROTECTED]> + + 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 */ ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ U-Boot-Users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/u-boot-users
