/* 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> */
+ SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
+ Jean Delvare <khali@linux-fr.org> */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/seq_file.h>
+#include <linux/platform_device.h>
#include <asm/uaccess.h>
int rc = 0;
if (dev->driver && dev->driver->suspend)
- rc = dev->driver->suspend(dev,state,0);
+ rc = dev->driver->suspend(dev, state);
return rc;
}
int rc = 0;
if (dev->driver && dev->driver->resume)
- rc = dev->driver->resume(dev,0);
+ rc = dev->driver->resume(dev);
return rc;
}
-static struct bus_type i2c_bus_type = {
- .name = "i2c",
- .match = i2c_device_match,
- .suspend = i2c_bus_suspend,
- .resume = i2c_bus_resume,
-};
-
static int i2c_device_probe(struct device *dev)
{
return -ENODEV;
return 0;
}
-static void i2c_adapter_dev_release(struct device *dev)
+struct bus_type i2c_bus_type = {
+ .name = "i2c",
+ .match = i2c_device_match,
+ .probe = i2c_device_probe,
+ .remove = i2c_device_remove,
+ .suspend = i2c_bus_suspend,
+ .resume = i2c_bus_resume,
+};
+
+void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
complete(&adap->dev_released);
}
-static struct device_driver i2c_adapter_driver = {
+struct device_driver i2c_adapter_driver = {
+ .owner = THIS_MODULE,
.name = "i2c_adapter",
.bus = &i2c_bus_type,
- .probe = i2c_device_probe,
- .remove = i2c_device_remove,
};
static void i2c_adapter_class_dev_release(struct class_device *dev)
complete(&adap->class_dev_released);
}
-static struct class i2c_adapter_class = {
+struct class i2c_adapter_class = {
+ .owner = THIS_MODULE,
.name = "i2c-adapter",
.release = &i2c_adapter_class_dev_release,
};
goto out_unlock;
}
- res = idr_get_new(&i2c_adapter_idr, NULL, &id);
+ res = idr_get_new(&i2c_adapter_idr, adap, &id);
if (res < 0) {
if (res == -EAGAIN)
res = -ENOMEM;
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
class_device_register(&adap->class_dev);
+ dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
/* inform drivers of new adapters */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
- if (driver->flags & I2C_DF_NOTIFY)
+ if (driver->attach_adapter)
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
- dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
-
out_unlock:
up(&core_lists);
return res;
break;
}
if (adap_from_list != adap) {
- pr_debug("I2C: Attempting to delete an unregistered "
- "adapter\n");
+ pr_debug("i2c-core: attempting to delete unregistered "
+ "adapter [%s]\n", adap->name);
res = -EINVAL;
goto out_unlock;
}
driver = list_entry(item, struct i2c_driver, list);
if (driver->detach_adapter)
if ((res = driver->detach_adapter(adap))) {
- dev_warn(&adap->dev, "can't detach adapter "
- "while detaching driver %s: driver not "
- "detached!", driver->name);
+ dev_err(&adap->dev, "detach_adapter failed "
+ "for driver [%s]\n",
+ driver->driver.name);
goto out_unlock;
}
}
/* detach any active clients. This must be done first, because
- * it can fail; in which case we give upp. */
+ * it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
client = list_entry(item, struct i2c_client, list);
- /* detaching devices is unconditional of the set notify
- * flag, as _all_ clients that reside on the adapter
- * must be deleted, as this would cause invalid states.
- */
if ((res=client->driver->detach_client(client))) {
- dev_err(&adap->dev, "adapter not "
- "unregistered, because client at "
- "address %02x can't be detached. ",
+ dev_err(&adap->dev, "detach_client failed for client "
+ "[%s] at address 0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
/* free dynamically allocated bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
- dev_dbg(&adap->dev, "adapter unregistered\n");
+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
out_unlock:
up(&core_lists);
* chips.
*/
-int i2c_add_driver(struct i2c_driver *driver)
+int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
struct list_head *item;
struct i2c_adapter *adapter;
down(&core_lists);
/* add the driver to the list of i2c drivers in the driver core */
- driver->driver.name = driver->name;
+ driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
- driver->driver.probe = i2c_device_probe;
- driver->driver.remove = i2c_device_remove;
res = driver_register(&driver->driver);
if (res)
goto out_unlock;
list_add_tail(&driver->list,&drivers);
- pr_debug("i2c-core: driver %s registered.\n", driver->name);
+ pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* now look for instances of driver on our adapters */
- if (driver->flags & I2C_DF_NOTIFY) {
+ if (driver->attach_adapter) {
list_for_each(item,&adapters) {
adapter = list_entry(item, struct i2c_adapter, list);
driver->attach_adapter(adapter);
up(&core_lists);
return res;
}
+EXPORT_SYMBOL(i2c_register_driver);
int i2c_del_driver(struct i2c_driver *driver)
{
* attached. If so, detach them to be able to kill the driver
* afterwards.
*/
- pr_debug("i2c-core: unregister_driver - looking for clients.\n");
- /* removing clients does not depend on the notify flag, else
- * invalid operation might (will!) result, when using stale client
- * pointers.
- */
list_for_each(item1,&adapters) {
adap = list_entry(item1, struct i2c_adapter, list);
- dev_dbg(&adap->dev, "examining adapter\n");
if (driver->detach_adapter) {
if ((res = driver->detach_adapter(adap))) {
- dev_warn(&adap->dev, "while unregistering "
- "dummy driver %s, adapter could "
- "not be detached properly; driver "
- "not unloaded!",driver->name);
+ dev_err(&adap->dev, "detach_adapter failed "
+ "for driver [%s]\n",
+ driver->driver.name);
goto out_unlock;
}
} else {
client = list_entry(item2, struct i2c_client, list);
if (client->driver != driver)
continue;
- pr_debug("i2c-core.o: detaching client %s:\n", client->name);
+ dev_dbg(&adap->dev, "detaching client [%s] "
+ "at 0x%02x\n", client->name,
+ client->addr);
if ((res = driver->detach_client(client))) {
- dev_err(&adap->dev, "while "
- "unregistering driver "
- "`%s', the client at "
- "address %02x of "
- "adapter could not "
- "be detached; driver "
- "not unloaded!",
- driver->name,
+ dev_err(&adap->dev, "detach_client "
+ "failed for client [%s] at "
+ "0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
driver_unregister(&driver->driver);
list_del(&driver->list);
- pr_debug("i2c-core: driver unregistered: %s\n", driver->name);
+ pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
out_unlock:
up(&core_lists);
if (adapter->client_register) {
if (adapter->client_register(client)) {
- dev_warn(&adapter->dev, "warning: client_register "
- "seems to have failed for client %02x\n",
- client->addr);
+ dev_dbg(&adapter->dev, "client_register "
+ "failed for client [%s] at 0x%02x\n",
+ client->name, client->addr);
}
}
- dev_dbg(&adapter->dev, "client [%s] registered to adapter\n",
- client->name);
-
- if (client->flags & I2C_CLIENT_ALLOW_USE)
- client->usage_count = 0;
+ client->usage_count = 0;
client->dev.parent = &client->adapter->dev;
client->dev.driver = &client->driver->driver;
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
- pr_debug("registering %s\n", client->dev.bus_id);
+ dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+ client->name, client->dev.bus_id);
device_register(&client->dev);
device_create_file(&client->dev, &dev_attr_client_name);
struct i2c_adapter *adapter = client->adapter;
int res = 0;
- if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
+ if (client->usage_count > 0) {
+ dev_warn(&client->dev, "Client [%s] still busy, "
+ "can't detach\n", client->name);
return -EBUSY;
+ }
if (adapter->client_unregister) {
res = adapter->client_unregister(client);
if (res) {
dev_err(&client->dev,
- "client_unregister [%s] failed, "
- "client not detached", client->name);
+ "client_unregister [%s] failed, "
+ "client not detached\n", client->name);
goto out;
}
}
static int i2c_inc_use_client(struct i2c_client *client)
{
- if (!try_module_get(client->driver->owner))
+ if (!try_module_get(client->driver->driver.owner))
return -ENODEV;
if (!try_module_get(client->adapter->owner)) {
- module_put(client->driver->owner);
+ module_put(client->driver->driver.owner);
return -ENODEV;
}
static void i2c_dec_use_client(struct i2c_client *client)
{
- module_put(client->driver->owner);
+ module_put(client->driver->driver.owner);
module_put(client->adapter->owner);
}
if (ret)
return ret;
- if (client->flags & I2C_CLIENT_ALLOW_USE) {
- if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
- client->usage_count++;
- else if (client->usage_count > 0)
- goto busy;
- else
- client->usage_count++;
- }
+ client->usage_count++;
return 0;
- busy:
- i2c_dec_use_client(client);
- return -EBUSY;
}
int i2c_release_client(struct i2c_client *client)
{
- if(client->flags & I2C_CLIENT_ALLOW_USE) {
- if(client->usage_count>0)
- client->usage_count--;
- else {
- pr_debug("i2c-core: %s used one too many times\n",
- __FUNCTION__);
- return -EPERM;
- }
+ if (!client->usage_count) {
+ pr_debug("i2c-core: %s used one too many times\n",
+ __FUNCTION__);
+ return -EPERM;
}
+ client->usage_count--;
i2c_dec_use_client(client);
return 0;
down(&adap->clist_lock);
list_for_each(item,&adap->clients) {
client = list_entry(item, struct i2c_client, list);
- if (!try_module_get(client->driver->owner))
+ if (!try_module_get(client->driver->driver.owner))
continue;
if (NULL != client->driver->command) {
up(&adap->clist_lock);
client->driver->command(client,cmd,arg);
down(&adap->clist_lock);
}
- module_put(client->driver->owner);
+ module_put(client->driver->driver.owner);
}
up(&adap->clist_lock);
}
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
- if (client->adapter->algo->master_xfer) {
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.len = count;
- msg.buf = (char *)buf;
-
- dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
- count);
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (char *)buf;
- down(&adap->bus_lock);
- ret = adap->algo->master_xfer(adap,&msg,1);
- up(&adap->bus_lock);
+ 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;
- } else {
- dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
- return -ENOSYS;
- }
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ return (ret == 1) ? count : ret;
}
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
- if (client->adapter->algo->master_xfer) {
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.flags |= I2C_M_RD;
- msg.len = count;
- msg.buf = buf;
-
- dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
- count);
-
- down(&adap->bus_lock);
- ret = adap->algo->master_xfer(adap,&msg,1);
- up(&adap->bus_lock);
-
- dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n",
- ret, count, client->addr);
-
- /* if everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
- */
- return (ret == 1 )? count : ret;
- } else {
- dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
- return -ENOSYS;
- }
+
+ 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;
}
* Will not work for 10-bit addresses!
* ----------------------------------------------------
*/
+static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
+ int (*found_proc) (struct i2c_adapter *, int, int))
+{
+ int err;
+
+ /* Make sure the address is valid */
+ if (addr < 0x03 || addr > 0x77) {
+ dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+ addr);
+ return -EINVAL;
+ }
+
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter, addr))
+ return 0;
+
+ /* Make sure there is something at this address, unless forced */
+ if (kind < 0) {
+ if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL) < 0)
+ return 0;
+
+ /* prevent 24RF08 corruption */
+ if ((addr & ~0x0f) == 0x50)
+ i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL);
+ }
+
+ /* Finally call the custom detection function */
+ err = found_proc(adapter, addr, kind);
+
+ /* -ENODEV can be returned if there is a chip at the given address
+ but it isn't supported by this chip driver. We catch it here as
+ this isn't an error. */
+ return (err == -ENODEV) ? 0 : err;
+}
+
int i2c_probe(struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
{
- int addr,i,found,err;
+ int i, err;
int adap_id = i2c_adapter_id(adapter);
- /* Forget it if we can't probe using SMBUS_QUICK */
- if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
- return -1;
-
- for (addr = 0x00; addr <= 0x7f; addr++) {
-
- /* Skip if already in use */
- if (i2c_check_addr(adapter,addr))
- continue;
-
- /* If it is in one of the force entries, we don't do any detection
- at all */
- found = 0;
-
- for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) {
- if (((adap_id == address_data->force[i]) ||
- (address_data->force[i] == ANY_I2C_BUS)) &&
- (addr == address_data->force[i+1])) {
- dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n",
- adap_id, addr);
- if ((err = found_proc(adapter,addr,0)))
- return err;
- found = 1;
+ /* Force entries are done first, and are not affected by ignore
+ entries */
+ if (address_data->forces) {
+ unsigned short **forces = address_data->forces;
+ int kind;
+
+ for (kind = 0; forces[kind]; kind++) {
+ for (i = 0; forces[kind][i] != I2C_CLIENT_END;
+ i += 2) {
+ if (forces[kind][i] == adap_id
+ || forces[kind][i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found force "
+ "parameter for adapter %d, "
+ "addr 0x%02x, kind %d\n",
+ adap_id, forces[kind][i + 1],
+ kind);
+ err = i2c_probe_address(adapter,
+ forces[kind][i + 1],
+ kind, found_proc);
+ if (err)
+ return err;
+ }
}
}
- if (found)
- continue;
+ }
- /* If this address is in one of the ignores, we can forget about
- it right now */
- for (i = 0;
- !found && (address_data->ignore[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->ignore[i]) ||
- ((address_data->ignore[i] == ANY_I2C_BUS))) &&
- (addr == address_data->ignore[i+1])) {
- dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, "
- "addr %04x\n", adap_id ,addr);
- found = 1;
- }
- }
- for (i = 0;
- !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->ignore_range[i]) ||
- ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
- (addr >= address_data->ignore_range[i+1]) &&
- (addr <= address_data->ignore_range[i+2])) {
- dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
- found = 1;
- }
- }
- if (found)
- continue;
+ /* Stop here if we can't use SMBUS_QUICK */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
+ if (address_data->probe[0] == I2C_CLIENT_END
+ && address_data->normal_i2c[0] == I2C_CLIENT_END)
+ return 0;
- /* Now, we will do a detection, but only if it is in the normal or
- probe entries */
- for (i = 0;
- !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
- i += 1) {
- if (addr == address_data->normal_i2c[i]) {
- found = 1;
- dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, "
- "addr %02x\n", adap_id, addr);
- }
- }
+ dev_warn(&adapter->dev, "SMBus Quick command not supported, "
+ "can't probe for chips\n");
+ return -1;
+ }
- for (i = 0;
- !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
- i += 2) {
- if ((addr >= address_data->normal_i2c_range[i]) &&
- (addr <= address_data->normal_i2c_range[i+1])) {
- found = 1;
- dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, "
- "addr %04x\n", adap_id,addr);
- }
+ /* Probe entries are done second, and are not affected by ignore
+ entries either */
+ for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
+ if (address_data->probe[i] == adap_id
+ || address_data->probe[i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found probe parameter for "
+ "adapter %d, addr 0x%02x\n", adap_id,
+ address_data->probe[i + 1]);
+ err = i2c_probe_address(adapter,
+ address_data->probe[i + 1],
+ -1, found_proc);
+ if (err)
+ return err;
}
+ }
- for (i = 0;
- !found && (address_data->probe[i] != I2C_CLIENT_END);
- i += 2) {
- if (((adap_id == address_data->probe[i]) ||
- ((address_data->probe[i] == ANY_I2C_BUS))) &&
- (addr == address_data->probe[i+1])) {
- found = 1;
- dev_dbg(&adapter->dev, "found probe parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
- }
- }
- for (i = 0;
- !found && (address_data->probe_range[i] != I2C_CLIENT_END);
- i += 3) {
- if (((adap_id == address_data->probe_range[i]) ||
- (address_data->probe_range[i] == ANY_I2C_BUS)) &&
- (addr >= address_data->probe_range[i+1]) &&
- (addr <= address_data->probe_range[i+2])) {
- found = 1;
- dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, "
- "addr %04x\n", adap_id,addr);
+ /* Normal entries are done last, unless shadowed by an ignore entry */
+ for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
+ int j, ignore;
+
+ ignore = 0;
+ for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
+ j += 2) {
+ if ((address_data->ignore[j] == adap_id ||
+ address_data->ignore[j] == ANY_I2C_BUS)
+ && address_data->ignore[j + 1]
+ == address_data->normal_i2c[i]) {
+ dev_dbg(&adapter->dev, "found ignore "
+ "parameter for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->ignore[j + 1]);
}
+ ignore = 1;
+ break;
}
- if (!found)
+ if (ignore)
continue;
- /* OK, so we really should examine this address. First check
- whether there is some client here at all! */
- if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
- if ((err = found_proc(adapter,addr,-1)))
- return err;
+ dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->normal_i2c[i]);
+ err = i2c_probe_address(adapter, address_data->normal_i2c[i],
+ -1, found_proc);
+ if (err)
+ return err;
}
- return 0;
-}
-/*
- * return id number for a specific adapter
- */
-int i2c_adapter_id(struct i2c_adapter *adap)
-{
- return adap->nr;
+ return 0;
}
struct i2c_adapter* i2c_get_adapter(int id)
{
- struct list_head *item;
struct i2c_adapter *adapter;
down(&core_lists);
- list_for_each(item,&adapters) {
- adapter = list_entry(item, struct i2c_adapter, list);
- if (id == adapter->nr &&
- try_module_get(adapter->owner)) {
- up(&core_lists);
- return adapter;
- }
- }
+ adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+ if (adapter && !try_module_get(adapter->owner))
+ adapter = NULL;
+
up(&core_lists);
- return NULL;
+ return adapter;
}
void i2c_put_adapter(struct i2c_adapter *adap)
return (u8)(data >> 8);
}
-/* CRC over count bytes in the first array plus the bytes in the rest
- array if it is non-null. rest[0] is the (length of rest) - 1
- and is included. */
-static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest)
+/* Incremental CRC8 over count bytes in the array pointed to by p */
+static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
{
int i;
for(i = 0; i < count; i++)
- crc = crc8((crc ^ first[i]) << 8);
- if(rest != NULL)
- for(i = 0; i <= rest[0]; i++)
- crc = crc8((crc ^ rest[i]) << 8);
+ crc = crc8((crc ^ p[i]) << 8);
return crc;
}
-static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest)
+/* Assume a 7-bit address, which is reasonable for SMBus */
+static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
{
- return i2c_smbus_partial_pec(0, count, first, rest);
+ /* The address will be sent first */
+ u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
+ pec = i2c_smbus_pec(pec, &addr, 1);
+
+ /* The data buffer follows */
+ return i2c_smbus_pec(pec, msg->buf, msg->len);
}
-/* Returns new "size" (transaction type)
- Note that we convert byte to byte_data and byte_data to word_data
- rather than invent new xxx_PEC transactions. */
-static int i2c_smbus_add_pec(u16 addr, u8 command, int size,
- union i2c_smbus_data *data)
+/* Used for write only transactions */
+static inline void i2c_smbus_add_pec(struct i2c_msg *msg)
{
- u8 buf[3];
-
- buf[0] = addr << 1;
- buf[1] = command;
- switch(size) {
- case I2C_SMBUS_BYTE:
- data->byte = i2c_smbus_pec(2, buf, NULL);
- size = I2C_SMBUS_BYTE_DATA;
- break;
- case I2C_SMBUS_BYTE_DATA:
- buf[2] = data->byte;
- data->word = buf[2] ||
- (i2c_smbus_pec(3, buf, NULL) << 8);
- size = I2C_SMBUS_WORD_DATA;
- break;
- case I2C_SMBUS_WORD_DATA:
- /* unsupported */
- break;
- case I2C_SMBUS_BLOCK_DATA:
- data->block[data->block[0] + 1] =
- i2c_smbus_pec(2, buf, data->block);
- size = I2C_SMBUS_BLOCK_DATA_PEC;
- break;
- }
- return size;
+ msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg);
+ msg->len++;
}
-static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
- union i2c_smbus_data *data)
+/* Return <0 on CRC error
+ If there was a write before this read (most cases) we need to take the
+ partial CRC from the write part into account.
+ Note that this function does modify the message (we need to decrease the
+ message length to hide the CRC byte from the caller). */
+static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
{
- u8 buf[3], rpec, cpec;
+ u8 rpec = msg->buf[--msg->len];
+ cpec = i2c_smbus_msg_pec(cpec, msg);
- buf[1] = command;
- switch(size) {
- case I2C_SMBUS_BYTE_DATA:
- buf[0] = (addr << 1) | 1;
- cpec = i2c_smbus_pec(2, buf, NULL);
- rpec = data->byte;
- break;
- case I2C_SMBUS_WORD_DATA:
- buf[0] = (addr << 1) | 1;
- buf[2] = data->word & 0xff;
- cpec = i2c_smbus_pec(3, buf, NULL);
- rpec = data->word >> 8;
- break;
- case I2C_SMBUS_WORD_DATA_PEC:
- /* unsupported */
- cpec = rpec = 0;
- break;
- case I2C_SMBUS_PROC_CALL_PEC:
- /* unsupported */
- cpec = rpec = 0;
- break;
- case I2C_SMBUS_BLOCK_DATA_PEC:
- buf[0] = (addr << 1);
- buf[2] = (addr << 1) | 1;
- cpec = i2c_smbus_pec(3, buf, data->block);
- rpec = data->block[data->block[0] + 1];
- break;
- case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
- buf[0] = (addr << 1) | 1;
- rpec = i2c_smbus_partial_pec(partial, 1,
- buf, data->block);
- cpec = data->block[data->block[0] + 1];
- break;
- default:
- cpec = rpec = 0;
- break;
- }
if (rpec != cpec) {
pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
rpec, cpec);
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
{
- union i2c_smbus_data data; /* only for PEC */
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
+ I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
}
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
need to use only one message; when reading, we need two. We initialize
most things with sane defaults, to keep the code below somewhat
simpler. */
- unsigned char msgbuf0[34];
- unsigned char msgbuf1[34];
+ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
+ unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ?2:1;
struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
int i;
+ u8 partial_pec = 0;
msgbuf0[0] = command;
switch(size) {
msgbuf0[2] = (data->word >> 8) & 0xff;
break;
case I2C_SMBUS_BLOCK_DATA:
- case I2C_SMBUS_BLOCK_DATA_PEC:
if (read_write == I2C_SMBUS_READ) {
dev_err(&adapter->dev, "Block read not supported "
"under I2C emulation!\n");
data->block[0]);
return -1;
}
- if(size == I2C_SMBUS_BLOCK_DATA_PEC)
- (msg[0].len)++;
- for (i = 1; i <= msg[0].len; i++)
+ for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
- case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
dev_dbg(&adapter->dev, "Block process call not supported "
"under I2C emulation!\n");
return -1;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
- msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;
+ msg[1].len = I2C_SMBUS_BLOCK_MAX;
} else {
msg[0].len = data->block[0] + 1;
- if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) {
+ if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
"invalid block write size (%d)\n",
data->block[0]);
return -1;
}
+ i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
+ && size != I2C_SMBUS_I2C_BLOCK_DATA);
+ if (i) {
+ /* Compute PEC if first message is a write */
+ if (!(msg[0].flags & I2C_M_RD)) {
+ if (num == 1) /* Write only */
+ i2c_smbus_add_pec(&msg[0]);
+ else /* Write followed by read */
+ partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
+ }
+ /* Ask for PEC if last message is a read */
+ if (msg[num-1].flags & I2C_M_RD)
+ msg[num-1].len++;
+ }
+
if (i2c_transfer(adapter, msg, num) < 0)
return -1;
+ /* Check PEC if last message is a read */
+ if (i && (msg[num-1].flags & I2C_M_RD)) {
+ if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)
+ return -1;
+ }
+
if (read_write == I2C_SMBUS_READ)
switch(size) {
case I2C_SMBUS_BYTE:
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
/* fixed at 32 for now */
- data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;
- for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
data->block[i+1] = msgbuf1[i];
break;
}
union i2c_smbus_data * data)
{
s32 res;
- int swpec = 0;
- u8 partial = 0;
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
- if((flags & I2C_CLIENT_PEC) &&
- !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) {
- swpec = 1;
- if(read_write == I2C_SMBUS_READ &&
- size == I2C_SMBUS_BLOCK_DATA)
- size = I2C_SMBUS_BLOCK_DATA_PEC;
- else if(size == I2C_SMBUS_PROC_CALL)
- size = I2C_SMBUS_PROC_CALL_PEC;
- else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {
- i2c_smbus_add_pec(addr, command,
- I2C_SMBUS_BLOCK_DATA, data);
- partial = data->block[data->block[0] + 1];
- size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;
- } else if(read_write == I2C_SMBUS_WRITE &&
- size != I2C_SMBUS_QUICK &&
- size != I2C_SMBUS_I2C_BLOCK_DATA)
- size = i2c_smbus_add_pec(addr, command, size, data);
- }
if (adapter->algo->smbus_xfer) {
down(&adapter->bus_lock);
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command,size,data);
- if(res >= 0 && swpec &&
- size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&
- (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||
- size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {
- if(i2c_smbus_check_pec(addr, command, size, partial, data))
- return -1;
- }
return res;
}
+/* Next four are needed by i2c-isa */
+EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
+EXPORT_SYMBOL_GPL(i2c_adapter_driver);
+EXPORT_SYMBOL_GPL(i2c_adapter_class);
+EXPORT_SYMBOL_GPL(i2c_bus_type);
+
EXPORT_SYMBOL(i2c_add_adapter);
EXPORT_SYMBOL(i2c_del_adapter);
-EXPORT_SYMBOL(i2c_add_driver);
EXPORT_SYMBOL(i2c_del_driver);
EXPORT_SYMBOL(i2c_attach_client);
EXPORT_SYMBOL(i2c_detach_client);
EXPORT_SYMBOL(i2c_master_recv);
EXPORT_SYMBOL(i2c_control);
EXPORT_SYMBOL(i2c_transfer);
-EXPORT_SYMBOL(i2c_adapter_id);
EXPORT_SYMBOL(i2c_get_adapter);
EXPORT_SYMBOL(i2c_put_adapter);
EXPORT_SYMBOL(i2c_probe);