X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fi2c%2Fi2c-core.c;h=9011627d7eb030569524437fd10ef00c4523702b;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=8663e1b8ae4bc6ab2d627e219ff20150f4abbb54;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8663e1b8a..9011627d7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -35,13 +36,45 @@ static LIST_HEAD(adapters); static LIST_HEAD(drivers); static DECLARE_MUTEX(core_lists); +static DEFINE_IDR(i2c_adapter_idr); -int i2c_device_probe(struct device *dev) +/* 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) +{ + int rc = 0; + + if (dev->driver && dev->driver->suspend) + rc = dev->driver->suspend(dev,state,0); + return rc; +} + +static int i2c_bus_resume(struct device * dev) +{ + int rc = 0; + + if (dev->driver && dev->driver->resume) + rc = dev->driver->resume(dev,0); + 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; } -int i2c_device_remove(struct device *dev) +static int i2c_device_remove(struct device *dev) { return 0; } @@ -113,13 +146,25 @@ static struct device_attribute dev_attr_client_name = { */ int i2c_add_adapter(struct i2c_adapter *adap) { - static int nr = 0; + int id, res = 0; struct list_head *item; struct i2c_driver *driver; down(&core_lists); - adap->nr = nr++; + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) { + res = -ENOMEM; + goto out_unlock; + } + + res = idr_get_new(&i2c_adapter_idr, NULL, &id); + if (res < 0) { + if (res == -EAGAIN) + res = -ENOMEM; + goto out_unlock; + } + + adap->nr = id & MAX_ID_MASK; init_MUTEX(&adap->bus_lock); init_MUTEX(&adap->clist_lock); list_add_tail(&adap->list,&adapters); @@ -151,22 +196,37 @@ int i2c_add_adapter(struct i2c_adapter *adap) /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } - up(&core_lists); dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr); - return 0; + +out_unlock: + up(&core_lists); + return res; } int i2c_del_adapter(struct i2c_adapter *adap) { struct list_head *item, *_n; + struct i2c_adapter *adap_from_list; struct i2c_driver *driver; struct i2c_client *client; int res = 0; down(&core_lists); + /* First make sure that this adapter was ever added */ + list_for_each_entry(adap_from_list, &adapters, list) { + if (adap_from_list == adap) + break; + } + if (adap_from_list != adap) { + pr_debug("I2C: Attempting to delete an unregistered " + "adapter\n"); + res = -EINVAL; + goto out_unlock; + } + list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); if (driver->detach_adapter) @@ -208,6 +268,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) 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); + dev_dbg(&adap->dev, "adapter unregistered\n"); out_unlock: @@ -491,18 +554,6 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) up(&adap->clist_lock); } - -/* 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; -} - -struct bus_type i2c_bus_type = { - .name = "i2c", - .match = i2c_device_match, -}; - static int __init i2c_init(void) { int retval; @@ -531,12 +582,18 @@ module_exit(i2c_exit); * ---------------------------------------------------- */ -int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) +int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) { int ret; if (adap->algo->master_xfer) { - dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num); +#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); + } +#endif down(&adap->bus_lock); ret = adap->algo->master_xfer(adap,msgs,num); @@ -658,7 +715,7 @@ int i2c_probe(struct i2c_adapter *adapter, at all */ found = 0; - for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) { + 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])) { @@ -708,7 +765,7 @@ int i2c_probe(struct i2c_adapter *adapter, if (addr == address_data->normal_i2c[i]) { found = 1; dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, " - "addr %02x", adap_id,addr); + "addr %02x\n", adap_id, addr); } } @@ -808,7 +865,7 @@ crc8(u16 data) /* 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. */ -u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) { int i; @@ -820,7 +877,7 @@ u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) return crc; } -u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) { return i2c_smbus_partial_pec(0, count, first, rest); } @@ -828,8 +885,8 @@ u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) /* 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. */ -int i2c_smbus_add_pec(u16 addr, u8 command, int size, - union i2c_smbus_data *data) +static int i2c_smbus_add_pec(u16 addr, u8 command, int size, + union i2c_smbus_data *data) { u8 buf[3]; @@ -858,8 +915,8 @@ int i2c_smbus_add_pec(u16 addr, u8 command, int size, return size; } -int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, - union i2c_smbus_data *data) +static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, + union i2c_smbus_data *data) { u8 buf[3], rpec, cpec; @@ -969,35 +1026,8 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) I2C_SMBUS_WORD_DATA,&data); } -s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value) -{ - union i2c_smbus_data data; - data.word = value; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, - I2C_SMBUS_PROC_CALL, &data)) - return -1; - else - return 0x0FFFF & data.word; -} - -/* Returns the number of read bytes */ -s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values) -{ - union i2c_smbus_data data; - int i; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, - I2C_SMBUS_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values) +s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) { union i2c_smbus_data data; int i; @@ -1007,27 +1037,8 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, - I2C_SMBUS_BLOCK_DATA,&data); -} - -/* Returns the number of read bytes */ -s32 i2c_smbus_block_process_call(struct i2c_client *client, u8 command, u8 length, u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > I2C_SMBUS_BLOCK_MAX - 1) - return -1; - data.block[0] = length; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - if(i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_BLOCK_PROC_CALL, &data)) - return -1; - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; + I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA,&data); } /* Returns the number of read bytes */ @@ -1046,20 +1057,6 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val } } -s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values) -{ - union i2c_smbus_data data; - int i; - if (length > I2C_SMBUS_I2C_BLOCK_MAX) - length = I2C_SMBUS_I2C_BLOCK_MAX; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,command, - I2C_SMBUS_I2C_BLOCK_DATA,&data); -} - /* 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, @@ -1239,22 +1236,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, } -/* You should always define `functionality'; the 'else' is just for - backward compatibility. */ -u32 i2c_get_functionality (struct i2c_adapter *adap) -{ - if (adap->algo->functionality) - return adap->algo->functionality(adap); - else - return 0xffffffff; -} - -int i2c_check_functionality (struct i2c_adapter *adap, u32 func) -{ - u32 adap_func = i2c_get_functionality (adap); - return (func & adap_func) == func; -} - EXPORT_SYMBOL(i2c_add_adapter); EXPORT_SYMBOL(i2c_del_adapter); EXPORT_SYMBOL(i2c_add_driver); @@ -1283,14 +1264,8 @@ EXPORT_SYMBOL(i2c_smbus_read_byte_data); EXPORT_SYMBOL(i2c_smbus_write_byte_data); EXPORT_SYMBOL(i2c_smbus_read_word_data); EXPORT_SYMBOL(i2c_smbus_write_word_data); -EXPORT_SYMBOL(i2c_smbus_process_call); -EXPORT_SYMBOL(i2c_smbus_read_block_data); EXPORT_SYMBOL(i2c_smbus_write_block_data); EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); -EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); - -EXPORT_SYMBOL(i2c_get_functionality); -EXPORT_SYMBOL(i2c_check_functionality); MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module");