mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
![Alexander Sverdlin](/assets/img/avatar_default.png)
Currently of_i2c_register_devices() function registers all i2c devices, independently from their status property in device tree. According to "ePAPR 1.1" spec, device should only be registered if there is no "status" property, or it has "ok" (or "okay") value (see of_device_is_available()). In case of "platform devices", of_platform_device_create_pdata() checks for "status" and ensures that disabled devices are not populated. But such check for i2c buses was missing until now. Fix it. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@sysgo.com> Acked-by: Rob Herring <robherring2@gmail.com> Acked-by: Wolfram Sang <w.sang@pengutronix.de> Reviewed-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
114 lines
2.9 KiB
C
114 lines
2.9 KiB
C
/*
|
|
* OF helpers for the I2C API
|
|
*
|
|
* Copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
|
|
*
|
|
* Based on a previous patch from Jon Smirl <jonsmirl@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/i2c.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_i2c.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/module.h>
|
|
|
|
void of_i2c_register_devices(struct i2c_adapter *adap)
|
|
{
|
|
void *result;
|
|
struct device_node *node;
|
|
|
|
/* Only register child devices if the adapter has a node pointer set */
|
|
if (!adap->dev.of_node)
|
|
return;
|
|
|
|
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
|
|
|
|
for_each_available_child_of_node(adap->dev.of_node, node) {
|
|
struct i2c_board_info info = {};
|
|
struct dev_archdata dev_ad = {};
|
|
const __be32 *addr;
|
|
int len;
|
|
|
|
dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
|
|
|
|
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
|
|
dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
|
|
node->full_name);
|
|
continue;
|
|
}
|
|
|
|
addr = of_get_property(node, "reg", &len);
|
|
if (!addr || (len < sizeof(int))) {
|
|
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
|
|
node->full_name);
|
|
continue;
|
|
}
|
|
|
|
info.addr = be32_to_cpup(addr);
|
|
if (info.addr > (1 << 10) - 1) {
|
|
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
|
|
info.addr, node->full_name);
|
|
continue;
|
|
}
|
|
|
|
info.irq = irq_of_parse_and_map(node, 0);
|
|
info.of_node = of_node_get(node);
|
|
info.archdata = &dev_ad;
|
|
|
|
if (of_get_property(node, "wakeup-source", NULL))
|
|
info.flags |= I2C_CLIENT_WAKE;
|
|
|
|
request_module("%s%s", I2C_MODULE_PREFIX, info.type);
|
|
|
|
result = i2c_new_device(adap, &info);
|
|
if (result == NULL) {
|
|
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
|
|
node->full_name);
|
|
of_node_put(node);
|
|
irq_dispose_mapping(info.irq);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(of_i2c_register_devices);
|
|
|
|
static int of_dev_node_match(struct device *dev, void *data)
|
|
{
|
|
return dev->of_node == data;
|
|
}
|
|
|
|
/* must call put_device() when done with returned i2c_client device */
|
|
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
|
|
{
|
|
struct device *dev;
|
|
|
|
dev = bus_find_device(&i2c_bus_type, NULL, node,
|
|
of_dev_node_match);
|
|
if (!dev)
|
|
return NULL;
|
|
|
|
return i2c_verify_client(dev);
|
|
}
|
|
EXPORT_SYMBOL(of_find_i2c_device_by_node);
|
|
|
|
/* must call put_device() when done with returned i2c_adapter device */
|
|
struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
|
|
{
|
|
struct device *dev;
|
|
|
|
dev = bus_find_device(&i2c_bus_type, NULL, node,
|
|
of_dev_node_match);
|
|
if (!dev)
|
|
return NULL;
|
|
|
|
return i2c_verify_adapter(dev);
|
|
}
|
|
EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
|
|
|
|
MODULE_LICENSE("GPL");
|