summaryrefslogtreecommitdiff
path: root/drivers/i2c/i2c-core-base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/i2c-core-base.c')
-rw-r--r--drivers/i2c/i2c-core-base.c228
1 files changed, 132 insertions, 96 deletions
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 60746652fd52..ae7e9c8b65a6 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -16,6 +16,7 @@
#include <linux/acpi.h>
#include <linux/clk/clk-conf.h>
#include <linux/completion.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -25,14 +26,13 @@
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/irqflags.h>
+#include <linux/irq.h>
#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pm_domain.h>
@@ -41,6 +41,7 @@
#include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include "i2c-core.h"
@@ -67,6 +68,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key);
static bool is_registered;
+static struct dentry *i2c_debugfs_root;
+
int i2c_transfer_trace_reg(void)
{
static_branch_inc(&i2c_trace_msg_key);
@@ -133,10 +136,10 @@ const void *i2c_get_match_data(const struct i2c_client *client)
}
EXPORT_SYMBOL(i2c_get_match_data);
-static int i2c_device_match(struct device *dev, struct device_driver *drv)
+static int i2c_device_match(struct device *dev, const struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
- struct i2c_driver *driver;
+ const struct i2c_driver *driver;
/* Attempt an OF style match */
@@ -487,6 +490,7 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
static int i2c_device_probe(struct device *dev)
{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
bool do_power_on;
@@ -505,11 +509,11 @@ static int i2c_device_probe(struct device *dev)
/* Keep adapter active when Host Notify is required */
pm_runtime_get_sync(&client->adapter->dev);
irq = i2c_smbus_host_notify_to_irq(client);
- } else if (dev->of_node) {
- irq = of_irq_get_byname(dev->of_node, "irq");
+ } else if (is_of_node(fwnode)) {
+ irq = fwnode_irq_get_byname(fwnode, "irq");
if (irq == -EINVAL || irq == -ENODATA)
- irq = of_irq_get(dev->of_node, 0);
- } else if (ACPI_COMPANION(dev)) {
+ irq = fwnode_irq_get(fwnode, 0);
+ } else if (is_acpi_device_node(fwnode)) {
bool wake_capable;
irq = i2c_acpi_get_irq(client, &wake_capable);
@@ -517,7 +521,7 @@ static int i2c_device_probe(struct device *dev)
client->flags |= I2C_CLIENT_WAKE;
}
if (irq == -EPROBE_DEFER) {
- status = irq;
+ status = dev_err_probe(dev, irq, "can't get irq\n");
goto put_sync_adapter;
}
@@ -543,9 +547,9 @@ static int i2c_device_probe(struct device *dev)
if (client->flags & I2C_CLIENT_WAKE) {
int wakeirq;
- wakeirq = of_irq_get_byname(dev->of_node, "wakeup");
+ wakeirq = fwnode_irq_get_byname(fwnode, "wakeup");
if (wakeirq == -EPROBE_DEFER) {
- status = wakeirq;
+ status = dev_err_probe(dev, wakeirq, "can't get wakeirq\n");
goto put_sync_adapter;
}
@@ -564,12 +568,13 @@ static int i2c_device_probe(struct device *dev)
dev_dbg(dev, "probe\n");
- status = of_clk_set_defaults(dev->of_node, false);
+ status = of_clk_set_defaults(to_of_node(fwnode), false);
if (status < 0)
goto err_clear_wakeup_irq;
do_power_on = !i2c_acpi_waive_d0_probe(dev);
- status = dev_pm_domain_attach(&client->dev, do_power_on);
+ status = dev_pm_domain_attach(&client->dev, PD_FLAG_DETACH_POWER_OFF |
+ (do_power_on ? PD_FLAG_ATTACH_POWER_ON : 0));
if (status)
goto err_clear_wakeup_irq;
@@ -577,9 +582,12 @@ static int i2c_device_probe(struct device *dev)
GFP_KERNEL);
if (!client->devres_group_id) {
status = -ENOMEM;
- goto err_detach_pm_domain;
+ goto err_clear_wakeup_irq;
}
+ client->debugfs = debugfs_create_dir(dev_name(&client->dev),
+ client->adapter->debugfs);
+
if (driver->probe)
status = driver->probe(client);
else
@@ -599,9 +607,8 @@ static int i2c_device_probe(struct device *dev)
return 0;
err_release_driver_resources:
+ debugfs_remove_recursive(client->debugfs);
devres_release_group(&client->dev, client->devres_group_id);
-err_detach_pm_domain:
- dev_pm_domain_detach(&client->dev, do_power_on);
err_clear_wakeup_irq:
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
@@ -624,9 +631,9 @@ static void i2c_device_remove(struct device *dev)
driver->remove(client);
}
- devres_release_group(&client->dev, client->devres_group_id);
+ debugfs_remove_recursive(client->debugfs);
- dev_pm_domain_detach(&client->dev, true);
+ devres_release_group(&client->dev, client->devres_group_id);
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
@@ -689,7 +696,7 @@ static struct attribute *i2c_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(i2c_dev);
-struct bus_type i2c_bus_type = {
+const struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
@@ -698,7 +705,7 @@ struct bus_type i2c_bus_type = {
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
-struct device_type i2c_client_type = {
+const struct device_type i2c_client_type = {
.groups = i2c_dev_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
@@ -912,6 +919,27 @@ int i2c_dev_irq_from_resources(const struct resource *resources,
return 0;
}
+/*
+ * Serialize device instantiation in case it can be instantiated explicitly
+ * and by auto-detection
+ */
+static int i2c_lock_addr(struct i2c_adapter *adap, unsigned short addr,
+ unsigned short flags)
+{
+ if (!(flags & I2C_CLIENT_TEN) &&
+ test_and_set_bit(addr, adap->addrs_in_instantiation))
+ return -EBUSY;
+
+ return 0;
+}
+
+static void i2c_unlock_addr(struct i2c_adapter *adap, unsigned short addr,
+ unsigned short flags)
+{
+ if (!(flags & I2C_CLIENT_TEN))
+ clear_bit(addr, adap->addrs_in_instantiation);
+}
+
/**
* i2c_new_client_device - instantiate an i2c device
* @adap: the adapter managing the device
@@ -931,8 +959,10 @@ int i2c_dev_irq_from_resources(const struct resource *resources,
struct i2c_client *
i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
- struct i2c_client *client;
- int status;
+ struct fwnode_handle *fwnode = info->fwnode;
+ struct i2c_client *client;
+ bool need_put = false;
+ int status;
client = kzalloc(sizeof *client, GFP_KERNEL);
if (!client)
@@ -958,6 +988,10 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
goto out_err_silent;
}
+ status = i2c_lock_addr(adap, client->addr, client->flags);
+ if (status)
+ goto out_err_silent;
+
/* Check for address business */
status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client));
if (status)
@@ -966,11 +1000,10 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
- client->dev.of_node = of_node_get(info->of_node);
- client->dev.fwnode = info->fwnode;
device_enable_async_suspend(&client->dev);
- i2c_dev_set_name(adap, client, info);
+
+ device_set_node(&client->dev, fwnode_handle_get(fwnode));
if (info->swnode) {
status = device_add_software_node(&client->dev, info->swnode);
@@ -978,10 +1011,11 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
dev_err(&adap->dev,
"Failed to add software node to client %s: %d\n",
client->name, status);
- goto out_err_put_of_node;
+ goto out_err_put_fwnode;
}
}
+ i2c_dev_set_name(adap, client, info);
status = device_register(&client->dev);
if (status)
goto out_remove_swnode;
@@ -989,18 +1023,25 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
+ i2c_unlock_addr(adap, client->addr, client->flags);
+
return client;
out_remove_swnode:
device_remove_software_node(&client->dev);
-out_err_put_of_node:
- of_node_put(info->of_node);
+ need_put = true;
+out_err_put_fwnode:
+ fwnode_handle_put(fwnode);
out_err:
dev_err(&adap->dev,
"Failed to register i2c client %s at 0x%02x (%d)\n",
client->name, client->addr, status);
+ i2c_unlock_addr(adap, client->addr, client->flags);
out_err_silent:
- kfree(client);
+ if (need_put)
+ put_device(&client->dev);
+ else
+ kfree(client);
return ERR_PTR(status);
}
EXPORT_SYMBOL_GPL(i2c_new_client_device);
@@ -1012,16 +1053,24 @@ EXPORT_SYMBOL_GPL(i2c_new_client_device);
*/
void i2c_unregister_device(struct i2c_client *client)
{
+ struct fwnode_handle *fwnode;
+
if (IS_ERR_OR_NULL(client))
return;
- if (client->dev.of_node) {
- of_node_clear_flag(client->dev.of_node, OF_POPULATED);
- of_node_put(client->dev.of_node);
- }
+ fwnode = dev_fwnode(&client->dev);
+ if (is_of_node(fwnode))
+ of_node_clear_flag(to_of_node(fwnode), OF_POPULATED);
+ else if (is_acpi_device_node(fwnode))
+ acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
+
+ /*
+ * If the primary fwnode is a software node it is free-ed by
+ * device_remove_software_node() below, avoid double-free.
+ */
+ if (!is_software_node(fwnode))
+ fwnode_handle_put(fwnode);
- if (ACPI_COMPANION(&client->dev))
- acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev));
device_remove_software_node(&client->dev);
device_unregister(&client->dev);
}
@@ -1058,8 +1107,9 @@ EXPORT_SYMBOL(i2c_find_device_by_fwnode);
static const struct i2c_device_id dummy_id[] = {
- { "dummy", 0 },
- { },
+ { "dummy", },
+ { "smbus_host_notify", },
+ { }
};
static int dummy_probe(struct i2c_client *client)
@@ -1165,11 +1215,9 @@ struct i2c_client *i2c_new_ancillary_device(struct i2c_client *client,
u32 addr = default_addr;
int i;
- if (np) {
- i = of_property_match_string(np, "reg-names", name);
- if (i >= 0)
- of_property_read_u32_index(np, "reg", i, &addr);
- }
+ i = of_property_match_string(np, "reg-names", name);
+ if (i >= 0)
+ of_property_read_u32_index(np, "reg", i, &addr);
dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr);
return i2c_new_dummy_device(client->adapter, addr);
@@ -1189,9 +1237,11 @@ static void i2c_adapter_dev_release(struct device *dev)
unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
{
unsigned int depth = 0;
+ struct device *parent;
- while ((adapter = i2c_parent_is_i2c_adapter(adapter)))
- depth++;
+ for (parent = adapter->dev.parent; parent; parent = parent->parent)
+ if (parent->type == &i2c_adapter_type)
+ depth++;
WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES,
"adapter depth exceeds lockdep subclass limit\n");
@@ -1333,7 +1383,7 @@ static struct attribute *i2c_adapter_attrs[] = {
};
ATTRIBUTE_GROUPS(i2c_adapter);
-struct device_type i2c_adapter_type = {
+const struct device_type i2c_adapter_type = {
.groups = i2c_adapter_groups,
.release = i2c_adapter_dev_release,
};
@@ -1356,10 +1406,6 @@ struct i2c_adapter *i2c_verify_adapter(struct device *dev)
}
EXPORT_SYMBOL(i2c_verify_adapter);
-#ifdef CONFIG_I2C_COMPAT
-static struct class_compat *i2c_adapter_compat_class;
-#endif
-
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;
@@ -1458,6 +1504,8 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
if (!adap)
return -EINVAL;
+ dev_dbg(&adap->dev, "Detected HostNotify from address 0x%02x", addr);
+
irq = irq_find_mapping(adap->host_notify_domain, addr);
if (irq <= 0)
return -ENXIO;
@@ -1511,35 +1559,36 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
- res = device_register(&adap->dev);
+ device_initialize(&adap->dev);
+
+ /*
+ * This adapter can be used as a parent immediately after device_add(),
+ * setup runtime-pm (especially ignore-children) before hand.
+ */
+ device_enable_async_suspend(&adap->dev);
+ pm_runtime_no_callbacks(&adap->dev);
+ pm_suspend_ignore_children(&adap->dev, true);
+ pm_runtime_enable(&adap->dev);
+
+ res = device_add(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
+ put_device(&adap->dev);
goto out_list;
}
+ adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
+
res = i2c_setup_smbus_alert(adap);
if (res)
goto out_reg;
- device_enable_async_suspend(&adap->dev);
- pm_runtime_no_callbacks(&adap->dev);
- pm_suspend_ignore_children(&adap->dev, true);
- pm_runtime_enable(&adap->dev);
-
res = i2c_init_recovery(adap);
if (res == -EPROBE_DEFER)
goto out_reg;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
-#ifdef CONFIG_I2C_COMPAT
- res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
- adap->dev.parent);
- if (res)
- dev_warn(&adap->dev,
- "Failed to create compatibility class link\n");
-#endif
-
/* create pre-declared device nodes */
of_i2c_register_devices(adap);
i2c_acpi_install_space_handler(adap);
@@ -1556,6 +1605,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return 0;
out_reg:
+ debugfs_remove_recursive(adap->debugfs);
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
wait_for_completion(&adap->dev_released);
@@ -1605,12 +1655,10 @@ int i2c_add_adapter(struct i2c_adapter *adapter)
struct device *dev = &adapter->dev;
int id;
- if (dev->of_node) {
- id = of_alias_get_id(dev->of_node, "i2c");
- if (id >= 0) {
- adapter->nr = id;
- return __i2c_add_numbered_adapter(adapter);
- }
+ id = of_alias_get_id(dev->of_node, "i2c");
+ if (id >= 0) {
+ adapter->nr = id;
+ return __i2c_add_numbered_adapter(adapter);
}
mutex_lock(&core_lock);
@@ -1745,11 +1793,6 @@ void i2c_del_adapter(struct i2c_adapter *adap)
device_for_each_child(&adap->dev, NULL, __unregister_client);
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
-#ifdef CONFIG_I2C_COMPAT
- class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
- adap->dev.parent);
-#endif
-
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
@@ -1757,6 +1800,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
i2c_host_notify_irq_teardown(adap);
+ debugfs_remove_recursive(adap->debugfs);
+
/* wait until all references to the device are gone
*
* FIXME: This is old code and should ideally be replaced by an
@@ -2054,13 +2099,8 @@ static int __init i2c_init(void)
is_registered = true;
-#ifdef CONFIG_I2C_COMPAT
- i2c_adapter_compat_class = class_compat_register("i2c-adapter");
- if (!i2c_adapter_compat_class) {
- retval = -ENOMEM;
- goto bus_err;
- }
-#endif
+ i2c_debugfs_root = debugfs_create_dir("i2c", NULL);
+
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
@@ -2073,10 +2113,6 @@ static int __init i2c_init(void)
return 0;
class_err:
-#ifdef CONFIG_I2C_COMPAT
- class_compat_unregister(i2c_adapter_compat_class);
-bus_err:
-#endif
is_registered = false;
bus_unregister(&i2c_bus_type);
return retval;
@@ -2089,9 +2125,7 @@ static void __exit i2c_exit(void)
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
i2c_del_driver(&dummy_driver);
-#ifdef CONFIG_I2C_COMPAT
- class_compat_unregister(i2c_adapter_compat_class);
-#endif
+ debugfs_remove_recursive(i2c_debugfs_root);
bus_unregister(&i2c_bus_type);
tracepoint_synchronize_unregister();
}
@@ -2114,7 +2148,7 @@ static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *
{
dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n",
err_msg, msg->addr, msg->len,
- msg->flags & I2C_M_RD ? "read" : "write");
+ str_read_write(msg->flags & I2C_M_RD));
return -EOPNOTSUPP;
}
@@ -2182,13 +2216,18 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs,
* Returns negative errno, else the number of messages executed.
*
* Adapter lock must be held when calling this function. No debug logging
- * takes place. adap->algo->master_xfer existence isn't checked.
+ * takes place.
*/
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
+ if (!adap->algo->master_xfer) {
+ dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+
if (WARN_ON(!msgs || num < 1))
return -EINVAL;
@@ -2255,11 +2294,6 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
int ret;
- if (!adap->algo->master_xfer) {
- dev_dbg(&adap->dev, "I2C level transfers not supported\n");
- return -EOPNOTSUPP;
- }
-
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
@@ -2495,9 +2529,10 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
return 0;
/* Set up a temporary client to help detect callback */
- temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ temp_client = kzalloc(sizeof(*temp_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
+
temp_client->adapter = adapter;
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
@@ -2511,6 +2546,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
}
kfree(temp_client);
+
return err;
}