#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <asm/uaccess.h>
static DEFINE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
+
+/* ------------------------------------------------------------------------- */
+
/* match always succeeds, as we want the probe() to tell if we really accept this match */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
-static int i2c_bus_suspend(struct device * dev, pm_message_t state)
+static int i2c_device_probe(struct device *dev)
{
- int rc = 0;
+ return -ENODEV;
+}
- if (dev->driver && dev->driver->suspend)
- rc = dev->driver->suspend(dev, state);
- return rc;
+static int i2c_device_remove(struct device *dev)
+{
+ return 0;
}
-static int i2c_bus_resume(struct device * dev)
+static void i2c_device_shutdown(struct device *dev)
{
- int rc = 0;
-
- if (dev->driver && dev->driver->resume)
- rc = dev->driver->resume(dev);
- return rc;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return;
+ driver = to_i2c_driver(dev->driver);
+ if (driver->shutdown)
+ driver->shutdown(to_i2c_client(dev));
}
-static int i2c_device_probe(struct device *dev)
+static int i2c_device_suspend(struct device * dev, pm_message_t mesg)
{
- return -ENODEV;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->suspend)
+ return 0;
+ return driver->suspend(to_i2c_client(dev), mesg);
}
-static int i2c_device_remove(struct device *dev)
+static int i2c_device_resume(struct device * dev)
{
- return 0;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->resume)
+ return 0;
+ return driver->resume(to_i2c_client(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,
+ .name = "i2c",
+ .match = i2c_device_match,
+ .probe = i2c_device_probe,
+ .remove = i2c_device_remove,
+ .shutdown = i2c_device_shutdown,
+ .suspend = i2c_device_suspend,
+ .resume = i2c_device_resume,
};
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
void i2c_adapter_dev_release(struct device *dev)
{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
}
-struct device_driver i2c_adapter_driver = {
- .owner = THIS_MODULE,
- .name = "i2c_adapter",
- .bus = &i2c_bus_type,
-};
-
-static void i2c_adapter_class_dev_release(struct class_device *dev)
+static ssize_t
+show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
- complete(&adap->class_dev_released);
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ return sprintf(buf, "%s\n", adap->name);
}
-struct class i2c_adapter_class = {
- .owner = THIS_MODULE,
- .name = "i2c-adapter",
- .release = &i2c_adapter_class_dev_release,
+static struct device_attribute i2c_adapter_attrs[] = {
+ __ATTR(name, S_IRUGO, show_adapter_name, NULL),
+ { },
};
-static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
- return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+struct class i2c_adapter_class = {
+ .owner = THIS_MODULE,
+ .name = "i2c-adapter",
+ .dev_attrs = i2c_adapter_attrs,
+};
static void i2c_client_release(struct device *dev)
return sprintf(buf, "%s\n", client->name);
}
-/*
- * We can't use the DEVICE_ATTR() macro here as we want the same filename for a
- * different type of a device. So beware if the DEVICE_ATTR() macro ever
- * changes, this definition will also have to change.
+/*
+ * We can't use the DEVICE_ATTR() macro here, as we used the same name for
+ * an i2c adapter attribute (above).
*/
-static struct device_attribute dev_attr_client_name = {
- .attr = {.name = "name", .mode = S_IRUGO, .owner = THIS_MODULE },
- .show = &show_client_name,
-};
+static struct device_attribute dev_attr_client_name =
+ __ATTR(name, S_IRUGO, &show_client_name, NULL);
/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
+ * registering functions
+ * ---------------------------------------------------
*/
/* -----
* If the parent pointer is not set up,
* we add this adapter to the host bus.
*/
- if (adap->dev.parent == NULL)
+ if (adap->dev.parent == NULL) {
adap->dev.parent = &platform_bus;
+ pr_debug("I2C adapter driver [%s] forgot to specify "
+ "physical device\n", adap->name);
+ }
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
- adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
+ adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev);
if (res)
goto out_list;
- res = device_create_file(&adap->dev, &dev_attr_name);
- if (res)
- goto out_unregister;
-
- /* Add this adapter to the i2c_adapter class */
- memset(&adap->class_dev, 0x00, sizeof(struct class_device));
- adap->class_dev.dev = &adap->dev;
- adap->class_dev.class = &i2c_adapter_class;
- strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
- res = class_device_register(&adap->class_dev);
- if (res)
- goto out_remove_name;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
mutex_unlock(&core_lists);
return res;
-out_remove_name:
- device_remove_file(&adap->dev, &dev_attr_name);
-out_unregister:
- init_completion(&adap->dev_released); /* Needed? */
- device_unregister(&adap->dev);
- wait_for_completion(&adap->dev_released);
out_list:
list_del(&adap->list);
idr_remove(&i2c_adapter_idr, adap->nr);
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
- init_completion(&adap->class_dev_released);
- class_device_unregister(&adap->class_dev);
- device_remove_file(&adap->dev, &dev_attr_name);
device_unregister(&adap->dev);
list_del(&adap->list);
/* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released);
- wait_for_completion(&adap->class_dev_released);
/* free dynamically allocated bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
- struct list_head *item;
- struct i2c_adapter *adapter;
int res;
/* add the driver to the list of i2c drivers in the driver core */
res = driver_register(&driver->driver);
if (res)
return res;
-
+
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers);
/* now look for instances of driver on our adapters */
if (driver->attach_adapter) {
- list_for_each(item,&adapters) {
- adapter = list_entry(item, struct i2c_adapter, list);
+ struct i2c_adapter *adapter;
+
+ list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
}
}
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
-
+
int res = 0;
mutex_lock(&core_lists);
/* Have a look at each adapter, if clients of this driver are still
- * attached. If so, detach them to be able to kill the driver
+ * attached. If so, detach them to be able to kill the driver
* afterwards.
*/
list_for_each(item1,&adapters) {
goto out_unlock;
}
list_add_tail(&client->list,&adapter->clients);
-
+
client->usage_count = 0;
client->dev.parent = &client->adapter->dev;
client->dev.driver = &client->driver->driver;
client->dev.bus = &i2c_bus_type;
client->dev.release = &i2c_client_release;
-
+
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
{
struct i2c_adapter *adapter = client->adapter;
int res = 0;
-
+
if (client->usage_count > 0) {
dev_warn(&client->dev, "Client [%s] still busy, "
"can't detach\n", client->name);
__FUNCTION__);
return -EPERM;
}
-
+
client->usage_count--;
i2c_dec_use_client(client);
-
+
return 0;
}
int retval;
retval = bus_register(&i2c_bus_type);
- if (retval)
- return retval;
- retval = driver_register(&i2c_adapter_driver);
if (retval)
return retval;
return class_register(&i2c_adapter_class);
static void __exit i2c_exit(void)
{
class_unregister(&i2c_adapter_class);
- driver_unregister(&i2c_adapter_driver);
bus_unregister(&i2c_bus_type);
}
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
- "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
- 'R' : 'W', msgs[ret].addr, msgs[ret].len);
+ "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
- mutex_lock(&adap->bus_lock);
+ mutex_lock_nested(&adap->bus_lock, adap->level);
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);
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
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;
+ return 0;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
"can't probe for chips\n");
struct i2c_adapter* i2c_get_adapter(int id)
{
struct i2c_adapter *adapter;
-
+
mutex_lock(&core_lists);
adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
if (adapter && !try_module_get(adapter->owner))
/* The SMBus parts */
-#define POLY (0x1070U << 3)
+#define POLY (0x1070U << 3)
static u8
crc8(u16 data)
{
int i;
-
+
for(i = 0; i < 8; i++) {
- if (data & 0x8000)
+ if (data & 0x8000)
data = data ^ POLY;
data = data << 1;
}
rpec, cpec);
return -1;
}
- return 0;
+ return 0;
}
s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
- value,0,I2C_SMBUS_QUICK,NULL);
+ value,0,I2C_SMBUS_QUICK,NULL);
}
s32 i2c_smbus_read_byte(struct i2c_client *client)
I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
-/* Simulate a SMBus command using the i2c protocol
+/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
-static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
unsigned short flags,
- char read_write, u8 command, int size,
+ char read_write, u8 command, int size,
union i2c_smbus_data * data)
{
/* So we need to generate a series of msgs. In the case of writing, we
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 },
+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
int i;
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
- dev_err(&adapter->dev, "Block read not supported "
- "under I2C emulation!\n");
- return -1;
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
} else {
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
- dev_dbg(&adapter->dev, "Block process call not supported "
- "under I2C emulation!\n");
- return -1;
+ num = 2; /* Another special case */
+ read_write = I2C_SMBUS_READ;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&adapter->dev, "%s called with invalid "
+ "block proc call size (%d)\n", __FUNCTION__,
+ data->block[0]);
+ return -1;
+ }
+ msg[0].len = data->block[0] + 2;
+ for (i = 1; i < msg[0].len; i++)
+ msgbuf0[i] = data->block[i-1];
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
+ break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].len = I2C_SMBUS_BLOCK_MAX;
if (i) {
/* Compute PEC if first message is a write */
if (!(msg[0].flags & I2C_M_RD)) {
- if (num == 1) /* Write only */
+ 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++;
+ msg[num-1].len++;
}
if (i2c_transfer(adapter, msg, num) < 0)
case I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break;
- case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
data->block[i+1] = msgbuf1[i];
break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ for (i = 0; i < msgbuf1[0] + 1; i++)
+ data->block[i] = msgbuf1[i];
+ break;
}
return 0;
}
s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
+ char read_write, u8 command, int size,
union i2c_smbus_data * data)
{
s32 res;
}
-/* Next four are needed by i2c-isa */
+/* Next three 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);