summaryrefslogtreecommitdiff
path: root/drivers/i2c/i2c-core.c
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/i2c/i2c-core.c
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r--drivers/i2c/i2c-core.c115
1 files changed, 80 insertions, 35 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 987c12443..c83e4d13c 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -107,7 +107,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
}
- } else if (info->irq < 0) {
+ } else if (!info->irq) {
struct resource r;
if (acpi_dev_resource_interrupt(ares, 0, &r))
@@ -134,7 +134,6 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
memset(&info, 0, sizeof(info));
info.fwnode = acpi_fwnode_handle(adev);
- info.irq = -1;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
@@ -258,7 +257,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
struct acpi_connection_info *info = &data->info;
struct acpi_resource_i2c_serialbus *sb;
struct i2c_adapter *adapter = data->adapter;
- struct i2c_client client;
+ struct i2c_client *client;
struct acpi_resource *ares;
u32 accessor_type = function >> 16;
u8 action = function & ACPI_IO_MASK;
@@ -269,6 +268,12 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
if (ACPI_FAILURE(ret))
return ret;
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client) {
+ ret = AE_NO_MEMORY;
+ goto err;
+ }
+
if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
ret = AE_BAD_PARAMETER;
goto err;
@@ -280,75 +285,73 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
goto err;
}
- memset(&client, 0, sizeof(client));
- client.adapter = adapter;
- client.addr = sb->slave_address;
- client.flags = 0;
+ client->adapter = adapter;
+ client->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
- client.flags |= I2C_CLIENT_TEN;
+ client->flags |= I2C_CLIENT_TEN;
switch (accessor_type) {
case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
if (action == ACPI_READ) {
- status = i2c_smbus_read_byte(&client);
+ status = i2c_smbus_read_byte(client);
if (status >= 0) {
gsb->bdata = status;
status = 0;
}
} else {
- status = i2c_smbus_write_byte(&client, gsb->bdata);
+ status = i2c_smbus_write_byte(client, gsb->bdata);
}
break;
case ACPI_GSB_ACCESS_ATTRIB_BYTE:
if (action == ACPI_READ) {
- status = i2c_smbus_read_byte_data(&client, command);
+ status = i2c_smbus_read_byte_data(client, command);
if (status >= 0) {
gsb->bdata = status;
status = 0;
}
} else {
- status = i2c_smbus_write_byte_data(&client, command,
+ status = i2c_smbus_write_byte_data(client, command,
gsb->bdata);
}
break;
case ACPI_GSB_ACCESS_ATTRIB_WORD:
if (action == ACPI_READ) {
- status = i2c_smbus_read_word_data(&client, command);
+ status = i2c_smbus_read_word_data(client, command);
if (status >= 0) {
gsb->wdata = status;
status = 0;
}
} else {
- status = i2c_smbus_write_word_data(&client, command,
+ status = i2c_smbus_write_word_data(client, command,
gsb->wdata);
}
break;
case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
if (action == ACPI_READ) {
- status = i2c_smbus_read_block_data(&client, command,
+ status = i2c_smbus_read_block_data(client, command,
gsb->data);
if (status >= 0) {
gsb->len = status;
status = 0;
}
} else {
- status = i2c_smbus_write_block_data(&client, command,
+ status = i2c_smbus_write_block_data(client, command,
gsb->len, gsb->data);
}
break;
case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
if (action == ACPI_READ) {
- status = acpi_gsb_i2c_read_bytes(&client, command,
+ status = acpi_gsb_i2c_read_bytes(client, command,
gsb->data, info->access_length);
if (status > 0)
status = 0;
} else {
- status = acpi_gsb_i2c_write_bytes(&client, command,
+ status = acpi_gsb_i2c_write_bytes(client, command,
gsb->data, info->access_length);
}
break;
@@ -362,6 +365,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
gsb->status = status;
err:
+ kfree(client);
ACPI_FREE(ares);
return ret;
}
@@ -563,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
if (bri->prepare_recovery)
bri->prepare_recovery(adap);
+ bri->set_scl(adap, val);
+ ndelay(RECOVERY_NDELAY);
+
/*
* By this time SCL is high, as we need to give 9 falling-rising edges
*/
@@ -593,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
- adap->bus_recovery_info->set_scl(adap, 1);
return i2c_generic_recovery(adap);
}
EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
@@ -632,8 +638,13 @@ static int i2c_device_probe(struct device *dev)
if (!client)
return 0;
- if (!client->irq && dev->of_node) {
- int irq = of_irq_get(dev->of_node, 0);
+ if (!client->irq) {
+ int irq = -ENOENT;
+
+ if (dev->of_node)
+ irq = of_irq_get(dev->of_node, 0);
+ else if (ACPI_COMPANION(dev))
+ irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
if (irq == -EPROBE_DEFER)
return irq;
@@ -1003,6 +1014,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
*/
void i2c_unregister_device(struct i2c_client *client)
{
+ if (client->dev.of_node)
+ of_node_clear_flag(client->dev.of_node, OF_POPULATED);
device_unregister(&client->dev);
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
@@ -1272,7 +1285,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
}
addr = of_get_property(node, "reg", &len);
- if (!addr || (len < sizeof(int))) {
+ if (!addr || (len < sizeof(*addr))) {
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
node->full_name);
return ERR_PTR(-EINVAL);
@@ -1311,8 +1324,11 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
- for_each_available_child_of_node(adap->dev.of_node, node)
+ for_each_available_child_of_node(adap->dev.of_node, node) {
+ if (of_node_test_and_set_flag(node, OF_POPULATED))
+ continue;
of_i2c_register_device(adap, node);
+ }
}
static int of_dev_node_match(struct device *dev, void *data)
@@ -1324,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data)
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
struct device *dev;
+ struct i2c_client *client;
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
+ dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
if (!dev)
return NULL;
- return i2c_verify_client(dev);
+ client = i2c_verify_client(dev);
+ if (!client)
+ put_device(dev);
+
+ return client;
}
EXPORT_SYMBOL(of_find_i2c_device_by_node);
@@ -1338,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
{
struct device *dev;
+ struct i2c_adapter *adapter;
- dev = bus_find_device(&i2c_bus_type, NULL, node,
- of_dev_node_match);
+ dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
if (!dev)
return NULL;
- return i2c_verify_adapter(dev);
+ adapter = i2c_verify_adapter(dev);
+ if (!adapter)
+ put_device(dev);
+
+ return adapter;
}
EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
#else
@@ -1673,7 +1697,7 @@ void i2c_del_adapter(struct i2c_adapter *adap)
* FIXME: This is old code and should ideally be replaced by an
* alternative which results in decoupling the lifetime of the struct
* device from the i2c_adapter, like spi or netdev do. Any solution
- * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
+ * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled!
*/
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
@@ -1844,6 +1868,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
if (adap == NULL)
return NOTIFY_OK; /* not for us */
+ if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
+ put_device(&adap->dev);
+ return NOTIFY_OK;
+ }
+
client = of_i2c_register_device(adap, rd->dn);
put_device(&adap->dev);
@@ -1854,6 +1883,10 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
}
break;
case OF_RECONFIG_CHANGE_REMOVE:
+ /* already depopulated? */
+ if (!of_node_check_flag(rd->dn, OF_POPULATED))
+ return NOTIFY_OK;
+
/* find our device by node */
client = of_find_i2c_device_by_node(rd->dn);
if (client == NULL)
@@ -2914,18 +2947,24 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
{
int ret;
- if (!client || !slave_cb)
+ if (!client || !slave_cb) {
+ WARN(1, "insufficent data\n");
return -EINVAL;
+ }
if (!(client->flags & I2C_CLIENT_TEN)) {
/* Enforce stricter address checking */
ret = i2c_check_addr_validity(client->addr);
- if (ret)
+ if (ret) {
+ dev_err(&client->dev, "%s: invalid address\n", __func__);
return ret;
+ }
}
- if (!client->adapter->algo->reg_slave)
+ if (!client->adapter->algo->reg_slave) {
+ dev_err(&client->dev, "%s: not supported by adapter\n", __func__);
return -EOPNOTSUPP;
+ }
client->slave_cb = slave_cb;
@@ -2933,8 +2972,10 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
ret = client->adapter->algo->reg_slave(client);
i2c_unlock_adapter(client->adapter);
- if (ret)
+ if (ret) {
client->slave_cb = NULL;
+ dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret);
+ }
return ret;
}
@@ -2944,8 +2985,10 @@ int i2c_slave_unregister(struct i2c_client *client)
{
int ret;
- if (!client->adapter->algo->unreg_slave)
+ if (!client->adapter->algo->unreg_slave) {
+ dev_err(&client->dev, "%s: not supported by adapter\n", __func__);
return -EOPNOTSUPP;
+ }
i2c_lock_adapter(client->adapter);
ret = client->adapter->algo->unreg_slave(client);
@@ -2953,6 +2996,8 @@ int i2c_slave_unregister(struct i2c_client *client)
if (ret == 0)
client->slave_cb = NULL;
+ else
+ dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret);
return ret;
}