cregit-Linux how code gets into the kernel

Release 4.14 drivers/i2c/i2c-core-base.c

Directory: drivers/i2c
/*
 * Linux I2C core
 *
 * Copyright (C) 1995-99 Simon G. Vogl
 *   With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
 *   Mux support by Rodolfo Giometti <giometti@enneenne.com> and
 *   Michael Lawnick <michael.lawnick.ext@nsn.com>
 *
 * Copyright (C) 2013-2017 Wolfram Sang <wsa@the-dreams.de>
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 */


#define pr_fmt(fmt) "i2c-core: " fmt

#include <dt-bindings/i2c/i2c.h>
#include <linux/acpi.h>
#include <linux/clk/clk-conf.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/irqflags.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/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
#include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>

#include "i2c-core.h"


#define CREATE_TRACE_POINTS
#include <trace/events/i2c.h>


#define I2C_ADDR_OFFSET_TEN_BIT	0xa000

#define I2C_ADDR_OFFSET_SLAVE	0x1000


#define I2C_ADDR_7BITS_MAX	0x77

#define I2C_ADDR_7BITS_COUNT	(I2C_ADDR_7BITS_MAX + 1)

/*
 * core_lock protects i2c_adapter_idr, and guarantees that device detection,
 * deletion of detected devices, and attach_adapter calls are serialized
 */
static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);


static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;

static bool is_registered;


int i2c_transfer_trace_reg(void) { static_key_slow_inc(&i2c_trace_msg); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Howells1275.00%150.00%
Steven Rostedt425.00%150.00%
Total16100.00%2100.00%


void i2c_transfer_trace_unreg(void) { static_key_slow_dec(&i2c_trace_msg); }

Contributors

PersonTokensPropCommitsCommitProp
David Howells13100.00%1100.00%
Total13100.00%1100.00%


const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client) { if (!(id && client)) return NULL; while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; id++; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare5582.09%150.00%
Lee Jones1217.91%150.00%
Total67100.00%2100.00%

EXPORT_SYMBOL_GPL(i2c_match_id);
static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; /* Attempt an OF style match */ if (i2c_of_match_device(drv->of_match_table, client)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver = to_i2c_driver(drv); /* Finally an I2C match */ if (i2c_match_id(driver->id_table, client)) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar4148.81%114.29%
Adrian Bunk1517.86%114.29%
David Brownell1315.48%114.29%
Lee Jones910.71%228.57%
Grant C. Likely44.76%114.29%
Jean Delvare22.38%114.29%
Total84100.00%7100.00%


static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); int rc; rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; return add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar3962.90%133.33%
Rui Zhang2235.48%133.33%
Wolfram Sang11.61%133.33%
Total62100.00%3100.00%

/* i2c bus recovery routines */
static int get_scl_gpio_value(struct i2c_adapter *adap) { return gpio_get_value(adap->bus_recovery_info->scl_gpio); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar21100.00%1100.00%
Total21100.00%1100.00%


static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { gpio_set_value(adap->bus_recovery_info->scl_gpio, val); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar25100.00%1100.00%
Total25100.00%1100.00%


static int get_sda_gpio_value(struct i2c_adapter *adap) { return gpio_get_value(adap->bus_recovery_info->sda_gpio); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar21100.00%1100.00%
Total21100.00%1100.00%


static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; struct device *dev = &adap->dev; int ret = 0; ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | GPIOF_OUT_INIT_HIGH, "i2c-scl"); if (ret) { dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); return ret; } if (bri->get_sda) { if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { /* work without SDA polling */ dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", bri->sda_gpio); bri->get_sda = NULL; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar114100.00%1100.00%
Total114100.00%1100.00%


static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; if (bri->get_sda) gpio_free(bri->sda_gpio); gpio_free(bri->scl_gpio); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar40100.00%1100.00%
Total40100.00%1100.00%

/* * We are generating clock pulses. ndelay() determines durating of clk pulses. * We will generate clock with rate 100 KHz and so duration of both clock levels * is: delay in ns = (10^6 / 100) / 2 */ #define RECOVERY_NDELAY 5000 #define RECOVERY_CLK_CNT 9
static int i2c_generic_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; int i = 0, val = 1, ret = 0; 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 */ while (i++ < RECOVERY_CLK_CNT * 2) { if (val) { /* Break if SDA is high */ if (bri->get_sda && bri->get_sda(adap)) break; /* SCL shouldn't be low here */ if (!bri->get_scl(adap)) { dev_err(&adap->dev, "SCL is stuck low, exit recovery\n"); ret = -EBUSY; break; } } val = !val; bri->set_scl(adap, val); ndelay(RECOVERY_NDELAY); } if (bri->unprepare_recovery) bri->unprepare_recovery(adap); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar14189.81%133.33%
Jan Lübbe148.92%133.33%
Grygorii Strashko21.27%133.33%
Total157100.00%3100.00%


int i2c_generic_scl_recovery(struct i2c_adapter *adap) { return i2c_generic_recovery(adap); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar1275.00%133.33%
Mika Westerberg318.75%133.33%
Grant C. Likely16.25%133.33%
Total16100.00%3100.00%

EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
int i2c_generic_gpio_recovery(struct i2c_adapter *adap) { int ret; ret = i2c_get_gpios_for_recovery(adap); if (ret) return ret; ret = i2c_generic_recovery(adap); i2c_put_gpios_for_recovery(adap); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar2969.05%125.00%
Jean Delvare819.05%250.00%
David Brownell511.90%125.00%
Total42100.00%4100.00%

EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery);
int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) return -EOPNOTSUPP; dev_dbg(&adap->dev, "Trying i2c bus recovery\n"); return adap->bus_recovery_info->recover_bus(adap); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar1946.34%125.00%
David Brownell1536.59%125.00%
Jean Delvare512.20%125.00%
Adrian Bunk24.88%125.00%
Total41100.00%4100.00%

EXPORT_SYMBOL_GPL(i2c_recover_bus);
static void i2c_init_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; char *err_str; if (!bri) return; if (!bri->recover_bus) { err_str = "no recover_bus() found"; goto err; } /* Generic GPIO recovery */ if (bri->recover_bus == i2c_generic_gpio_recovery) { if (!gpio_is_valid(bri->scl_gpio)) { err_str = "invalid SCL gpio"; goto err; } if (gpio_is_valid(bri->sda_gpio)) bri->get_sda = get_sda_gpio_value; else bri->get_sda = NULL; bri->get_scl = get_scl_gpio_value; bri->set_scl = set_scl_gpio_value; } else if (bri->recover_bus == i2c_generic_scl_recovery) { /* Generic SCL recovery */ if (!bri->set_scl || !bri->get_scl) { err_str = "no {get|set}_scl() found"; goto err; } } return; err: dev_err(&adap->dev, "Not using recovery: %s\n", err_str); adap->bus_recovery_info = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfram Sang164100.00%1100.00%
Total164100.00%1100.00%


static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client) { struct i2c_adapter *adap = client->adapter; unsigned int irq; if (!adap->host_notify_domain) return -ENXIO; if (client->flags & I2C_CLIENT_TEN) return -EINVAL; irq = irq_find_mapping(adap->host_notify_domain, client->addr); if (!irq) irq = irq_create_mapping(adap->host_notify_domain, client->addr); return irq > 0 ? irq : -ENXIO; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Tissoires89100.00%1100.00%
Total89100.00%1100.00%


static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; int status; if (!client) return 0; driver = to_i2c_driver(dev->driver); if (!client->irq && !driver->disable_i2c_core_irq_mapping) { int irq = -ENOENT; if (client->flags & I2C_CLIENT_HOST_NOTIFY) { dev_dbg(dev, "Using Host Notify IRQ\n"); irq = i2c_smbus_host_notify_to_irq(client); } else if (dev->of_node) { irq = of_irq_get_byname(dev->of_node, "irq"); if (irq == -EINVAL || irq == -ENODATA) 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; if (irq < 0) irq = 0; client->irq = irq; } /* * An I2C ID table is not mandatory, if and only if, a suitable OF * or ACPI ID table is supplied for the probing device. */ if (!driver->id_table && !i2c_acpi_match_device(dev->driver->acpi_match_table, client) && !i2c_of_match_device(dev->driver->of_match_table, client)) return -ENODEV; if (client->flags & I2C_CLIENT_WAKE) { int wakeirq = -ENOENT; if (dev->of_node) { wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); if (wakeirq == -EPROBE_DEFER) return wakeirq; } device_init_wakeup(&client->dev, true); if (wakeirq > 0 && wakeirq != client->irq) status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); else if (client->irq > 0) status = dev_pm_set_wake_irq(dev, client->irq); else status = 0; if (status) dev_warn(&client->dev, "failed to set up wakeup irq\n"); } dev_dbg(dev, "probe\n"); status = of_clk_set_defaults(dev->of_node, false); if (status < 0) goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true); if (status == -EPROBE_DEFER) goto err_clear_wakeup_irq; /* * When there are no more users of probe(), * rename probe_new to probe. */ if (driver->probe_new) status = driver->probe_new(client); else if (driver->probe) status = driver->probe(client, i2c_match_id(driver->id_table, client)); else status = -EINVAL; if (status) goto err_detach_pm_domain; return 0; err_detach_pm_domain: dev_pm_domain_detach(&client->dev, true); err_clear_wakeup_irq: dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov17537.00%28.33%
Lee Jones439.09%28.33%
Jean Delvare336.98%312.50%
Laurent Pinchart336.98%14.17%
Mika Westerberg326.77%14.17%
David Brownell296.13%28.33%
Marc Pignat194.02%14.17%
Lv Zheng183.81%14.17%
Sylwester Nawrocki173.59%14.17%
Hans de Goede142.96%14.17%
Andy Shevchenko132.75%28.33%
Geert Uytterhoeven132.75%14.17%
Ulf Hansson102.11%14.17%
Adrian Bunk91.90%14.17%
Hans Verkuil71.48%14.17%
Kieran Bingham40.85%14.17%
Grygorii Strashko30.63%14.17%
Javier Martinez Canillas10.21%14.17%
Total473100.00%24100.00%


static int i2c_device_remove(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; int status = 0; if (!client || !dev->driver) return 0; driver = to_i2c_driver(dev->driver); if (driver->remove) { dev_dbg(dev, "remove\n"); status = driver->remove(client); } dev_pm_domain_detach(&client->dev, true); dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); return status; }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell7266.67%225.00%
Dmitry Torokhov1816.67%112.50%
Lv Zheng98.33%112.50%
Jean Delvare43.70%112.50%
Wolfram Sang21.85%112.50%
Adrian Bunk21.85%112.50%
Ulf Hansson10.93%112.50%
Total108100.00%8100.00%


static void i2c_device_shutdown(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; if (!client || !dev->driver) return; driver = to_i2c_driver(dev->driver); if (driver->shutdown) driver->shutdown(client); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell2949.15%120.00%
Jean Delvare1423.73%120.00%
Adrian Bunk1322.03%120.00%
Mark Brown23.39%120.00%
Greg Kroah-Hartman11.69%120.00%
Total59100.00%5100.00%


static void i2c_client_dev_release(struct device *dev) { kfree(to_i2c_client(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell19100.00%1100.00%
Total19100.00%1100.00%


static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", dev->type == &i2c_client_type ? to_i2c_client(dev)->name : to_i2c_adapter(dev)->name); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell3061.22%150.00%
Jean Delvare1938.78%150.00%
Total49100.00%2100.00%

static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); int len; len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell3245.71%133.33%
Rui Zhang2637.14%133.33%
Jean Delvare1217.14%133.33%
Total70100.00%3100.00%

static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); static struct attribute *i2c_dev_attrs[] = { &dev_attr_name.attr, /* modalias helps coldplug: modprobe $(cat .../modalias) */ &dev_attr_modalias.attr, NULL }; ATTRIBUTE_GROUPS(i2c_dev); struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, }; EXPORT_SYMBOL_GPL(i2c_bus_type); struct device_type i2c_client_type = { .groups = i2c_dev_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, }; EXPORT_SYMBOL_GPL(i2c_client_type); /** * i2c_verify_client - return parameter as i2c_client, or NULL * @dev: device, probably from some driver model iterator * * When traversing the driver model tree, perhaps using driver model * iterators like @device_for_each_child(), you can't assume very much * about the nodes you find. Use this function to avoid oopses caused * by wrongly treating some non-I2C device as an i2c_client. */
struct i2c_client *i2c_verify_client(struct device *dev) { return (dev->type == &i2c_client_type) ? to_i2c_client(dev) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell2793.10%150.00%
Jean Delvare26.90%150.00%
Total29100.00%2100.00%

EXPORT_SYMBOL(i2c_verify_client); /* Return a unique address which takes the flags of the client into account */
static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) { unsigned short addr = client->addr; /* For some client flags, add an arbitrary offset to avoid collisions */ if (client->flags & I2C_CLIENT_TEN) addr |= I2C_ADDR_OFFSET_TEN_BIT; if (client->flags & I2C_CLIENT_SLAVE) addr |= I2C_ADDR_OFFSET_SLAVE; return addr; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfram Sang48100.00%1100.00%
Total48100.00%1100.00%

/* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */
int i2c_check_addr_validity(unsigned addr, unsigned short flags) { if (flags & I2C_CLIENT_TEN) { /* 10-bit address, all values are valid */ if (addr > 0x3ff) return -EINVAL; } else { /* 7-bit address, reject the general call address */ if (addr == 0x00 || addr > 0x7f) return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare4586.54%133.33%
Wolfram Sang713.46%266.67%
Total52100.00%3100.00%

/* And this is a strict address validity check, used when probing. If a * device uses a reserved address, then it shouldn't be probed. 7-bit * addressing is assumed, 10-bit address devices are rare and should be * explicitly enumerated. */
int i2c_check_7bit_addr_validity_strict(unsigned short addr) { /* * Reserved addresses per I2C specification: * 0x00 General call address / START byte * 0x01 CBUS address * 0x02 Reserved for different bus format * 0x03 Reserved for future purposes * 0x04-0x07 Hs-mode master code * 0x78-0x7b 10-bit slave addressing * 0x7c-0x7f Reserved for future purposes */ if (addr < 0x08 || addr > 0x77) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare2696.30%150.00%
Wolfram Sang13.70%150.00%
Total27100.00%2100.00%


static int __i2c_check_addr_busy(struct device *dev, void *addrp) { struct i2c_client *client = i2c_verify_client(dev); int addr = *(int *)addrp; if (client && i2c_encode_flags_to_addr(client) == addr) return -EBUSY; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare5094.34%150.00%
Wolfram Sang35.66%150.00%
Total53100.00%2100.00%

/* walk up mux tree */
static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr) { struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result; result = device_for_each_child(&adapter->dev, &addr, __i2c_check_addr_busy); if (!result && parent) result = i2c_check_mux_parents(parent, addr); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Lawnick5081.97%150.00%
Jean Delvare1118.03%150.00%
Total61100.00%2100.00%

/* recurse down mux tree */
static int i2c_check_mux_children(struct device *dev, void *addrp) { int result; if (dev->type == &i2c_adapter_type) result = device_for_each_child(dev, addrp, i2c_check_mux_children); else result = __i2c_check_addr_busy(dev, addrp); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Michael Lawnick51100.00%1100.00%
Total51100.00%1100.00%


static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) { struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); int result = 0; if (parent) result = i2c_check_mux_parents(parent, addr); if (!result) result = device_for_each_child(&adapter->dev, &addr, i2c_check_mux_children); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare3756.92%266.67%
Michael Lawnick2843.08%133.33%
Total65100.00%3100.00%

/** * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment * @adapter: Target I2C bus segment * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT * locks only this branch in the adapter tree */
static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { rt_mutex_lock(&adapter->bus_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare1773.91%150.00%
Peter Rosin626.09%150.00%
Total23100.00%2100.00%

/** * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment * @adapter: Target I2C bus segment * @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT * trylocks only this branch in the adapter tree */
static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) { return rt_mutex_trylock(&adapter->bus_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare1979.17%150.00%
Peter Rosin520.83%150.00%
Total24100.00%2100.00%

/** * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment * @adapter: Target I2C bus segment * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT * unlocks only this branch in the adapter tree */
static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { rt_mutex_unlock(&adapter->bus_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare1773.91%150.00%
Peter Rosin626.09%150.00%
Total23100.00%2100.00%


static void i2c_dev_set_name(struct i2c_adapter *adap, struct i2c_client *client) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); if (adev) { dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev)); return; } dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), i2c_encode_flags_to_addr(client)); }

Contributors

PersonTokensPropCommitsCommitProp
Jarkko Nikula6895.77%150.00%
Wolfram Sang34.23%150.00%
Total71100.00%2100.00%


static int i2c_dev_irq_from_resources(const struct resource *resources, unsigned int num_resources) { struct irq_data *irqd; int i; for (i = 0; i < num_resources; i++) { const struct resource *r = &resources[i]; if (resource_type(r) != IORESOURCE_IRQ) continue; if (r->flags & IORESOURCE_BITS) { irqd = irq_get_irq_data(r->start); if (!irqd) break; irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); } return r->start; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Torokhov105100.00%1100.00%
Total105100.00%1100.00%

/** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * * Create an i2c device. Binding is handled through driver model * probe()/remove() methods. A driver may be bound to this device when we * return from this function, or any later moment (e.g. maybe hotplugging will * load the driver module). This call is not appropriate for use by mainboard * initialization logic, which usually runs during an arch_initcall() long * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. */
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); if (!client) return NULL; client->adapter = adap; client->dev.platform_data = info->platform_data; if (info->archdata) client->dev.archdata = *info->archdata; client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; if (!client->irq) client->irq = i2c_dev_irq_from_resources(info->resources, info->num_resources); strlcpy(client->name, info->type, sizeof(client->name)); status = i2c_check_addr_validity(client->addr, client->flags); if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); goto out_err_silent; } /* Check for address business */ status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client)); if (status) goto out_err; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client); if (info->properties) { status = device_add_properties(&client->dev, info->properties); if (status) { dev_err(&adap->dev, "Failed to add properties to client %s: %d\n", client->name, status); goto out_err; } } status = device_register(&client->dev); if (status) goto out_free_props; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; out_free_props: if (info->properties) device_remove_properties(&client->dev); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", client->name, client->addr, status); out_err_silent: kfree(client); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare15037.22%425.00%
David Brownell11829.28%16.25%
Dmitry Torokhov8621.34%212.50%
Anton Vorontsov174.22%16.25%
Wolfram Sang102.48%318.75%
Grant C. Likely102.48%16.25%
Mika Westerberg61.49%16.25%
Rafael J. Wysocki40.99%16.25%
Andy Shevchenko10.25%16.25%
Jarkko Nikula10.25%16.25%
Total403100.00%16100.00%

EXPORT_SYMBOL_GPL(i2c_new_device); /** * i2c_unregister_device - reverse effect of i2c_new_device() * @client: value returned from i2c_new_device() * Context: can sleep */
void i2c_unregister_device(struct i2c_client *client) { if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); if (ACPI_COMPANION(&client->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila2136.21%133.33%
Pantelis Antoniou1932.76%133.33%
David Brownell1831.03%133.33%
Total58100.00%3100.00%

EXPORT_SYMBOL_GPL(i2c_unregister_device); static const struct i2c_device_id dummy_id[] = { { "dummy", 0 }, { }, };
static int dummy_probe(struct i2c_client *client, const struct i2c_device_id *id) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare20100.00%1100.00%
Total20100.00%1100.00%


static int dummy_remove(struct i2c_client *client) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell1392.86%150.00%
Jean Delvare17.14%150.00%
Total14100.00%2100.00%

static struct i2c_driver dummy_driver = { .driver.name = "dummy", .probe = dummy_probe, .remove = dummy_remove, .id_table = dummy_id, }; /** * i2c_new_dummy - return a new i2c device bound to a dummy driver * @adapter: the adapter managing the device * @address: seven bit address to be used * Context: can sleep * * This returns an I2C client bound to the "dummy" driver, intended for use * with devices that consume multiple addresses. Examples of such chips * include various EEPROMS (like 24c04 and 24c08 models). * * These dummy devices have two main uses. First, most I2C and SMBus calls * except i2c_transfer() need a client handle; the dummy will be that handle. * And second, this prevents the specified address from being bound to a * different driver. * * This returns the new i2c client, which should be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. */
struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) { struct i2c_board_info info = { I2C_BOARD_INFO("dummy", address), }; return i2c_new_device(adapter, &info); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell3389.19%150.00%
Jean Delvare410.81%150.00%
Total37100.00%2100.00%

EXPORT_SYMBOL_GPL(i2c_new_dummy); /** * i2c_new_secondary_device - Helper to get the instantiated secondary address * and create the associated device * @client: Handle to the primary client * @name: Handle to specify which secondary address to get * @default_addr: Used as a fallback if no secondary address was specified * Context: can sleep * * I2C clients can be composed of multiple I2C slaves bound together in a single * component. The I2C client driver then binds to the master I2C slave and needs * to create I2C dummy clients to communicate with all the other slaves. * * This function creates and returns an I2C dummy client whose I2C address is * retrieved from the platform firmware based on the given slave name. If no * address is specified by the firmware default_addr is used. * * On DT-based platforms the address is retrieved from the "reg" property entry * cell whose "reg-names" value matches the slave name. * * This returns the new i2c client, which should be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. */
struct i2c_client *i2c_new_secondary_device(struct i2c_client *client, const char *name, u16 default_addr) { struct device_node *np = client->dev.of_node; 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); } dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); return i2c_new_dummy(client->adapter, addr); }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Michel Hautbois100100.00%1100.00%
Total100100.00%1100.00%

EXPORT_SYMBOL_GPL(i2c_new_secondary_device); /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */
static void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = to_i2c_adapter(dev); complete(&adap->dev_released); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman2793.10%133.33%
David Brownell13.45%133.33%
Adrian Bunk13.45%133.33%
Total29100.00%3100.00%


unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) { unsigned int depth = 0; while ((adapter = i2c_parent_is_i2c_adapter(adapter))) depth++; WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES, "adapter depth exceeds lockdep subclass limit\n"); return depth; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare3479.07%150.00%
Bartosz Golaszewski920.93%150.00%
Total43100.00%2100.00%

EXPORT_SYMBOL_GPL(i2c_adapter_depth); /* * Let users instantiate I2C devices through sysfs. This can be used when * platform initialization code doesn't contain the proper data for * whatever reason. Also useful for drivers that do device detection and * detection fails, either because the device uses an unexpected address, * or this is a compatible device with different ID register values. * * Parameter checking may look overzealous, but we really don't want * the user to provide incorrect parameters. */
static ssize_t i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_adapter *adap = to_i2c_adapter(dev); struct i2c_board_info info; struct i2c_client *client; char *blank, end; int res; memset(&info, 0, sizeof(struct i2c_board_info)); blank = strchr(buf, ' '); if (!blank) { dev_err(dev, "%s: Missing parameters\n", "new_device"); return -EINVAL; } if (blank - buf > I2C_NAME_SIZE - 1) { dev_err(dev, "%s: Invalid device name\n", "new_device"); return -EINVAL; } memcpy(info.type, buf, blank - buf); /* Parse remaining parameters, reject extra parameters */ res = sscanf(++blank, "%hi%c", &info.addr, &end); if (res < 1) { dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); return -EINVAL; } if (res > 1 && end != '\n') { dev_err(dev, "%s: Extra parameters\n", "new_device"); return -EINVAL; } if ((info.addr & I2C_ADDR_OFFSET_TEN_BIT) == I2C_ADDR_OFFSET_TEN_BIT) { info.addr &= ~I2C_ADDR_OFFSET_TEN_BIT; info.flags |= I2C_CLIENT_TEN; } if (info.addr & I2C_ADDR_OFFSET_SLAVE) { info.addr &= ~I2C_ADDR_OFFSET_SLAVE; info.flags |= I2C_CLIENT_SLAVE; } client = i2c_new_device(adap, &info); if (!client) return -EINVAL; /* Keep track of the added device */ mutex_lock(&adap->userspace_clients_lock); list_add_tail(&client->detected, &adap->userspace_clients); mutex_unlock(&adap->userspace_clients_lock); dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", info.type, info.addr); return count; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare26784.23%480.00%
Wolfram Sang5015.77%120.00%
Total317100.00%5100.00%

static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device); /* * And of course let the users delete the devices they instantiated, if * they got it wrong. This interface can only be used to delete devices * instantiated by i2c_sysfs_new_device above. This guarantees that we * don't delete devices to which some kernel code still has references. * * Parameter checking may look overzealous, but we really don't want * the user to delete the wrong device. */
static ssize_t i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_adapter *adap = to_i2c_adapter(dev); struct i2c_client *client, *next; unsigned short addr; char end; int res; /* Parse parameters, reject extra parameters */ res = sscanf(buf, "%hi%c", &addr, &end); if (res < 1) { dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); return -EINVAL; } if (res > 1 && end != '\n') { dev_err(dev, "%s: Extra parameters\n", "delete_device"); return -EINVAL; } /* Make sure the device was added through sysfs */ res = -ENOENT; mutex_lock_nested(&adap->userspace_clients_lock, i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { if (i2c_encode_flags_to_addr(client) == addr) { dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", "delete_device", client->name, client->addr); list_del(&client->detected); i2c_unregister_device(client); res = count; break; } } mutex_unlock(&adap->userspace_clients_lock); if (res < 0) dev_err(dev, "%s: Can't find device in list\n", "delete_device"); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare21498.62%480.00%
Wolfram Sang31.38%120.00%
Total217100.00%5100.00%

static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device); static struct attribute *i2c_adapter_attrs[] = { &dev_attr_name.attr, &dev_attr_new_device.attr, &dev_attr_delete_device.attr, NULL }; ATTRIBUTE_GROUPS(i2c_adapter); struct device_type i2c_adapter_type = { .groups = i2c_adapter_groups, .release = i2c_adapter_dev_release, }; EXPORT_SYMBOL_GPL(i2c_adapter_type); /** * i2c_verify_adapter - return parameter as i2c_adapter or NULL * @dev: device, probably from some driver model iterator * * When traversing the driver model tree, perhaps using driver model * iterators like @device_for_each_child(), you can't assume very much * about the nodes you find. Use this function to avoid oopses caused * by wrongly treating some non-I2C device as an i2c_adapter. */
struct i2c_adapter *i2c_verify_adapter(struct device *dev) { return (dev->type == &i2c_adapter_type) ? to_i2c_adapter(dev) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Warren29100.00%1100.00%
Total29100.00%1100.00%

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; down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr); } up_read(&__i2c_board_lock); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell5877.33%120.00%
Wolfram Sang79.33%120.00%
Zhenwen Xu68.00%120.00%
Lee Jones34.00%120.00%
Rodolfo Giometti11.33%120.00%
Total75100.00%5100.00%


static int i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap) { /* Detect supported devices on that bus, and instantiate them */ i2c_detect(adap, driver); /* Let legacy drivers scan this bus for matching devices */ if (driver->attach_adapter) { dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", driver->driver.name); dev_warn(&adap->dev, "Please use another way to instantiate your i2c_client\n"); /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare6998.57%583.33%
Andy Shevchenko11.43%116.67%
Total70100.00%6100.00%


static int __process_new_adapter(struct device_driver *d, void *data) { return i2c_do_add_adapter(to_i2c_driver(d), data); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare26100.00%1100.00%
Total26100.00%1100.00%

static const struct i2c_lock_operations i2c_adapter_lock_ops = { .lock_bus = i2c_adapter_lock_bus, .trylock_bus = i2c_adapter_trylock_bus, .unlock_bus = i2c_adapter_unlock_bus, };
static void i2c_host_notify_irq_teardown(struct i2c_adapter *adap) { struct irq_domain *domain = adap->host_notify_domain; irq_hw_number_t hwirq; if (!domain) return; for (hwirq = 0 ; hwirq < I2C_ADDR_7BITS_COUNT ; hwirq++) irq_dispose_mapping(irq_find_mapping(domain, hwirq)); irq_domain_remove(domain); adap->host_notify_domain = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Tissoires63100.00%1100.00%
Total63100.00%1100.00%


static int i2c_host_notify_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw_irq_num) { irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Tissoires31100.00%1100.00%
Total31100.00%1100.00%

static const struct irq_domain_ops i2c_host_notify_irq_ops = { .map = i2c_host_notify_irq_map, };
static int i2c_setup_host_notify_irq_domain(struct i2c_adapter *adap) { struct irq_domain *domain; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY)) return 0; domain = irq_domain_create_linear(adap->dev.fwnode, I2C_ADDR_7BITS_COUNT, &i2c_host_notify_irq_ops, adap); if (!domain) return -ENOMEM; adap->host_notify_domain = domain; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Tissoires65100.00%1100.00%
Total65100.00%1100.00%

/** * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct * I2C client. * @adap: the adapter * @addr: the I2C address of the notifying device * Context: can't sleep * * Helper function to be called from an I2C bus driver's interrupt * handler. It will schedule the Host Notify IRQ. */
int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) { int irq; if (!adap) return -EINVAL; irq = irq_find_mapping(adap->host_notify_domain, addr); if (irq <= 0) return -ENXIO; generic_handle_irq(irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Tissoires55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
static int i2c_register_adapter(struct i2c_adapter *adap) { int res = -EINVAL; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) { res = -EAGAIN; goto out_list; } /* Sanity checks */ if (WARN(!adap->name[0], "i2c adapter has no name")) goto out_list; if (!adap->algo) { pr_err("adapter '%s': no algo supplied!\n", adap->name); goto out_list; } if (!adap->lock_ops) adap->lock_ops = &i2c_adapter_lock_ops; rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; /* register soft irqs for Host Notify */ res = i2c_setup_host_notify_irq_domain(adap); if (res) { pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n", adap->name, res); goto out_list; } 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); if (res) { pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); goto out_list; } dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); pm_runtime_no_callbacks(&adap->dev); pm_suspend_ignore_children(&adap->dev, true); pm_runtime_enable(&adap->dev); #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 i2c_init_recovery(adap); /* create pre-declared device nodes */ of_i2c_register_devices(adap); i2c_acpi_register_devices(adap); i2c_acpi_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); /* Notify drivers */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); mutex_unlock(&core_lock); return 0; out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare18246.31%1533.33%
Wolfram Sang4010.18%613.33%
Benjamin Tissoires287.12%12.22%
David Brownell287.12%24.44%
Greg Kroah-Hartman246.11%36.67%
Peter Rosin225.60%36.67%
Linus Torvalds (pre-git)164.07%24.44%
Linus Walleij102.54%12.22%
Faik Uygur92.29%12.22%
Charles Keepax82.04%12.22%
Gerd Knorr61.53%12.22%
Mika Westerberg41.02%12.22%
Lan Tianyu41.02%12.22%
Viresh Kumar41.02%12.22%
Kay Sievers20.51%12.22%
Jarkko Nikula20.51%12.22%
Arjan van de Ven10.25%12.22%
Sudip Mukherjee10.25%12.22%
Mika Kuoppala10.25%12.22%
Christoph Hellwig10.25%12.22%
Total393100.00%45100.00%

/** * __i2c_add_numbered_adapter - i2c_add_numbered_adapter where nr is never -1 * @adap: the adapter to register (with adap->nr initialized) * Context: can sleep * * See i2c_add_numbered_adapter() for details. */
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) { int id; mutex_lock(&core_lock); id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL); mutex_unlock(&core_lock); if (WARN(id < 0, "couldn't get idr")) return id == -ENOSPC ? -EBUSY : id; return i2c_register_adapter(adap); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell4255.26%120.00%
Douglas Anderson2127.63%120.00%
Tejun Heo67.89%120.00%
Wolfram Sang56.58%120.00%
Jean Delvare22.63%120.00%
Total76100.00%5100.00%

/** * i2c_add_adapter - declare i2c adapter, use dynamic bus number * @adapter: the adapter to add * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number * doesn't matter or when its bus number is specified by an dt alias. * Examples of bases when the bus number doesn't matter: I2C adapters * dynamically added by USB links or PCI plugin cards. * * When this returns zero, a new bus number was allocated and stored * in adap->nr, and the specified adapter became available for clients. * Otherwise, a negative errno value is returned. */
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); } } mutex_lock(&core_lock); id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); mutex_unlock(&core_lock); if (WARN(id < 0, "couldn't get idr")) return id; adapter->nr = id; return i2c_register_adapter(adapter); }

Contributors

PersonTokensPropCommitsCommitProp
Douglas Anderson6051.72%116.67%
David Brownell3731.90%116.67%
Tejun Heo76.03%116.67%
Grant C. Likely54.31%116.67%
Wolfram Sang54.31%116.67%
Jean Delvare21.72%116.67%
Total116100.00%6100.00%

EXPORT_SYMBOL(i2c_add_adapter); /** * i2c_add_numbered_adapter - declare i2c adapter, use static bus number * @adap: the adapter to register (with adap->nr initialized) * Context: can sleep * * This routine is used to declare an I2C adapter when its bus number * matters. For example, use it for I2C adapters from system-on-chip CPUs, * or otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * * If the requested bus number is set to -1, then this function will behave * identically to i2c_add_adapter, and will dynamically assign a bus number. * * If no devices have pre-been declared for this bus, then be sure to * register the adapter before any dynamically allocated ones. Otherwise * the required bus ID may not be available. * * When this returns zero, the specified adapter became available for * clients using the bus number provided in adap->nr. Also, the table * of I2C devices pre-declared using i2c_register_board_info() is scanned, * and the appropriate driver model device nodes are created. Otherwise, a * negative errno value is returned. */
int i2c_add_numbered_adapter(struct i2c_adapter *adap) { if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); return __i2c_add_numbered_adapter(adap); }

Contributors

PersonTokensPropCommitsCommitProp
Douglas Anderson2371.88%133.33%
David Brownell515.62%133.33%
Tejun Heo412.50%133.33%
Total32100.00%3100.00%

EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
static void i2c_do_del_adapter(struct i2c_driver *driver, struct i2c_adapter *adapter) { struct i2c_client *client, *_n; /* Remove the devices we created ourselves as the result of hardware * probing (using a driver's detect method) */ list_for_each_entry_safe(client, _n, &driver->clients, detected) { if (client->adapter == adapter) { dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", client->name, client->addr); list_del(&client->detected); i2c_unregister_device(client); } } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare7798.72%480.00%
Lars-Peter Clausen11.28%120.00%
Total78100.00%5100.00%


static int __unregister_client(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); if (client && strcmp(client->name, "dummy")) i2c_unregister_device(client); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare46100.00%2100.00%
Total46100.00%2100.00%


static int __unregister_dummy(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); if (client) i2c_unregister_device(client); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare37100.00%2100.00%
Total37100.00%2100.00%


static int __process_removed_adapter(struct device_driver *d, void *data) { i2c_do_del_adapter(to_i2c_driver(d), data); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare2589.29%150.00%
Lars-Peter Clausen310.71%150.00%
Total28100.00%2100.00%

/** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered * Context: can sleep * * This unregisters an I2C adapter which was previously registered * by @i2c_add_adapter or @i2c_add_numbered_adapter. */
void i2c_del_adapter(struct i2c_adapter *adap) { struct i2c_adapter *found; struct i2c_client *client, *next; /* First make sure that this adapter was ever added */ mutex_lock(&core_lock); found = idr_find(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); if (found != adap) { pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name); return; } i2c_acpi_remove_space_handler(adap); /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_removed_adapter); mutex_unlock(&core_lock); /* Remove devices instantiated from sysfs */ mutex_lock_nested(&adap->userspace_clients_lock, i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, client->addr); list_del(&client->detected); i2c_unregister_device(client); } mutex_unlock(&adap->userspace_clients_lock); /* Detach any active clients. This can't fail, thus we do not * check the returned value. This is a two-pass process, because * we can't remove the dummy devices during the first pass: they * could have been instantiated by real devices wishing to clean * them up properly, so we give them a chance to do that first. */ 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); pm_runtime_disable(&adap->dev); i2c_host_notify_irq_teardown(adap); /* wait until all references to the device are gone * * 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 thoroughly tested with DEBUG_KOBJECT_RELEASE enabled! */ init_completion(&adap->dev_released); device_unregister(&adap->dev); wait_for_completion(&adap->dev_released); /* free bus id */ mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); /* Clear the device structure in case this adapter is ever going to be added again */ memset(&adap->dev, 0, sizeof(adap->dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare20568.11%1542.86%
Greg Kroah-Hartman247.97%25.71%
Thadeu Lima de Souza Cascardo154.98%12.86%
Linus Torvalds (pre-git)113.65%25.71%
Faik Uygur103.32%12.86%
Wolfram Sang92.99%25.71%
Gerd Knorr51.66%12.86%
Benjamin Tissoires51.66%12.86%
Lan Tianyu41.33%12.86%
David Brownell31.00%25.71%
Christoph Hellwig31.00%12.86%
Lars-Peter Clausen20.66%12.86%
Shailendra Verma10.33%12.86%
Jarkko Nikula10.33%12.86%
Arjan van de Ven10.33%12.86%
Andreas Schultz10.33%12.86%
Matthias Kaehlcke10.33%12.86%
Total301100.00%35100.00%

EXPORT_SYMBOL(i2c_del_adapter); /** * i2c_parse_fw_timings - get I2C related timing parameters from firmware * @dev: The device to scan for I2C timing properties * @t: the i2c_timings struct to be filled with values * @use_defaults: bool to use sane defaults derived from the I2C specification * when properties are not found, otherwise use 0 * * Scan the device for the generic I2C properties describing timing parameters * for the signal and fill the given struct with the results. If a property was * not found and use_defaults was true, then maximum timings are assumed which * are derived from the I2C specification. If use_defaults is not used, the * results will be 0, so drivers can apply their own defaults later. The latter * is mainly intended for avoiding regressions of existing drivers which want * to switch to this function. New drivers almost always should use the defaults. */
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults) { int ret; memset(t, 0, sizeof(*t)); ret = device_property_read_u32(dev, "clock-frequency", &t->bus_freq_hz); if (ret && use_defaults) t->bus_freq_hz = 100000; ret = device_property_read_u32(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns); if (ret && use_defaults) { if (t->bus_freq_hz <= 100000) t->scl_rise_ns = 1000; else if (t->bus_freq_hz <= 400000) t->scl_rise_ns = 300; else t->scl_rise_ns = 120; } ret = device_property_read_u32(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns); if (ret && use_defaults) { if (t->bus_freq_hz <= 400000) t->scl_fall_ns = 300; else t->scl_fall_ns = 120; } device_property_read_u32(dev, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns); ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns); if (ret && use_defaults) t->sda_fall_ns = t->scl_fall_ns; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfram Sang201100.00%1100.00%
Total201100.00%1100.00%

EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); /* ------------------------------------------------------------------------- */
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)) { int res; mutex_lock(&core_lock); res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn); mutex_unlock(&core_lock); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare55100.00%1100.00%
Total55100.00%1100.00%

EXPORT_SYMBOL_GPL(i2c_for_each_dev);
static int __process_new_driver(struct device *dev, void *data) { if (dev->type != &i2c_adapter_type) return 0; return i2c_do_add_adapter(data, to_i2c_adapter(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare2257.89%266.67%
Dave Young1642.11%133.33%
Total38100.00%3100.00%

/* * An i2c_driver is used with one or more i2c_client (device) nodes to access * i2c slave chips, on a bus instance associated with some i2c_adapter. */
int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { int res; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) return -EAGAIN; /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; INIT_LIST_HEAD(&driver->clients); /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; pr_debug("driver [%s] registered\n", driver->driver.name); /* Walk the adapters that are already present */ i2c_for_each_dev(driver, __process_new_driver); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman3940.21%315.79%
Linus Torvalds (pre-git)1414.43%210.53%
David Brownell1212.37%15.26%
Jean Delvare1111.34%631.58%
Vladimir Zapolskiy88.25%15.26%
Gerd Knorr77.22%15.26%
Laurent Riffard22.06%15.26%
Wolfram Sang11.03%15.26%
Christoph Hellwig11.03%15.26%
Sudip Mukherjee11.03%15.26%
Dave Young11.03%15.26%
Total97100.00%19100.00%

EXPORT_SYMBOL(i2c_register_driver);
static int __process_removed_driver(struct device *dev, void *data) { if (dev->type == &i2c_adapter_type) i2c_do_del_adapter(data, to_i2c_adapter(dev)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare1848.65%350.00%
Dave Young924.32%116.67%
Linus Torvalds (pre-git)616.22%116.67%
Lars-Peter Clausen410.81%116.67%
Total37100.00%6100.00%

/** * i2c_del_driver - unregister I2C driver * @driver: the driver being unregistered * Context: can sleep */
void i2c_del_driver(struct i2c_driver *driver) { i2c_for_each_dev(driver, __process_removed_driver); driver_unregister(&driver->driver); pr_debug("driver [%s] unregistered\n", driver->driver.name); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Young1130.56%111.11%
Linus Torvalds (pre-git)822.22%111.11%
Gerd Knorr822.22%111.11%
Jean Delvare513.89%333.33%
Laurent Riffard25.56%111.11%
Wolfram Sang12.78%111.11%
Greg Kroah-Hartman12.78%111.11%
Total36100.00%9100.00%

EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced * * Each live reference to a client should be refcounted. The driver model does * that automatically as part of driver binding, so that most drivers don't * need to do this explicitly: they hold a reference until they're unbound * from the device. * * A pointer to the client with the incremented reference counter is returned. */
struct i2c_client *i2c_use_client(struct i2c_client *client) { if (client && get_device(&client->dev)) return client; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1136.67%233.33%
David Brownell826.67%116.67%
Jean Delvare826.67%233.33%
Christoph Hellwig310.00%116.67%
Total30100.00%6100.00%

EXPORT_SYMBOL(i2c_use_client); /** * i2c_release_client - release a use of the i2c client structure * @client: the client being no longer referenced * * Must be called when a user of a client is finished with it. */
void i2c_release_client(struct i2c_client *client) { if (client) put_device(&client->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1254.55%233.33%
Jean Delvare627.27%350.00%
David Brownell418.18%116.67%
Total22100.00%6100.00%

EXPORT_SYMBOL(i2c_release_client); struct i2c_cmd_arg { unsigned cmd; void *arg; };
static int i2c_cmd(struct device *dev, void *_arg) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_cmd_arg *arg = _arg; struct i2c_driver *driver; if (!client || !client->dev.driver) return 0; driver = to_i2c_driver(client->dev.driver); if (driver->command) driver->command(client, arg->cmd, arg->arg); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Gerd Knorr3843.68%133.33%
Lars-Peter Clausen2528.74%133.33%
David Brownell2427.59%133.33%
Total87100.00%3100.00%


void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { struct i2c_cmd_arg cmd_arg; cmd_arg.cmd = cmd; cmd_arg.arg = arg; device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); }

Contributors

PersonTokensPropCommitsCommitProp
David Brownell3880.85%133.33%
Gerd Knorr817.02%133.33%
Laurent Riffard12.13%133.33%
Total47100.00%3100.00%

EXPORT_SYMBOL(i2c_clients_command);
static int __init i2c_init(void) { int retval; retval = of_alias_get_highest_id("i2c"); down_write(&__i2c_board_lock); if (retval >= __i2c_first_dynamic_bus_num) __i2c_first_dynamic_bus_num = retval + 1; up_write(&__i2c_board_lock); retval = bus_register(&i2c_bus_type); if (retval) return retval; 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 retval = i2c_add_driver(&dummy_driver); if (retval) goto class_err; if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); if (IS_ENABLED(CONFIG_ACPI)) WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier)); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare4024.10%111.11%
Wolfram Sang3923.49%222.22%
David Brownell2716.27%111.11%
Greg Kroah-Hartman2414.46%222.22%
Pantelis Antoniou169.64%111.11%
Octavian Purdila169.64%111.11%
Linus Torvalds (pre-git)42.41%111.11%
Total166100.00%9100.00%


static void __exit i2c_exit(void) { if (IS_ENABLED(CONFIG_ACPI)) WARN_ON(acpi_reconfig_notifier_unregister(&i2c_acpi_notifier)); 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 bus_unregister(&i2c_bus_type); tracepoint_synchronize_unregister(); }

Contributors

PersonTokensPropCommitsCommitProp
Octavian Purdila1624.24%112.50%
Pantelis Antoniou1624.24%112.50%
Greg Kroah-Hartman1421.21%225.00%
Jean Delvare1015.15%112.50%
David Brownell69.09%112.50%
David Howells34.55%112.50%
Linus Torvalds (pre-git)11.52%112.50%
Total66100.00%8100.00%

/* We must initialize early, because some subsystems register i2c drivers * in subsys_initcall() code, but are linked (and initialized) before i2c. */ postcore_initcall(i2c_init); module_exit(i2c_exit); /* ---------------------------------------------------- * the functional interface to the i2c busses. * ---------------------------------------------------- */ /* Check if val is exceeding the quirk IFF quirk is non 0 */ #define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg) { 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"); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfram Sang54100.00%1100.00%
Total54100.00%1100.00%


static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { const struct i2c_adapter_quirks *q = adap->quirks; int max_num = q->max_num_msgs, i; bool do_len_check = true; if (q->flags & I2C_AQ_COMB) { max_num = 2; /* special checks for combined messages */ if (num == 2) { if (q->flags & I2C_AQ_COMB_WRITE_FIRST && msgs[0].flags & I2C_M_RD) return i2c_quirk_error(adap, &msgs[0], "1st comb msg must be write"); if (q->flags & I2C_AQ_COMB_READ_SECOND && !(msgs[1].flags & I2C_M_RD)) return i2c_quirk_error(adap, &msgs[1], "2nd comb msg must be read"); if (q->flags & I2C_AQ_COMB_SAME_ADDR && msgs[0].addr != msgs[1].addr) return i2c_quirk_error(adap, &msgs[0], "comb msg only to same addr"); if (i2c_quirk_exceeded(msgs[0].len, q->max_comb_1st_msg_len)) return i2c_quirk_error(adap, &msgs[0], "msg too long"); if (i2c_quirk_exceeded(msgs[1].len, q->max_comb_2nd_msg_len)) return i2c_quirk_error(adap, &msgs[1], "msg too long"); do_len_check = false; } } if (i2c_quirk_exceeded(num, max_num)) return i2c_quirk_error(adap, &msgs[0], "too many messages"); for (i = 0; i < num; i++) { u16 len = msgs[i].len; if (msgs[i].flags & I2C_M_RD) { if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len)) return i2c_quirk_error(adap, &msgs[i], "msg too long"); } else { if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len)) return i2c_quirk_error(adap, &msgs[i], "msg too long"); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wolfram Sang352100.00%1100.00%
Total352100.00%1100.00%

/** * __i2c_transfer - unlocked flavor of i2c_transfer * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. * * 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. */
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { unsigned long orig_jiffies; int ret, try; if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP; /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed. */ if (static_key_false(&i2c_trace_msg)) { int i; for (i = 0; i < num; i++) if (msgs[i].flags & I2C_M_RD) trace_i2c_read(adap, &msgs[i], i); else trace_i2c_write(adap, &msgs[i], i); } /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; for (ret = 0, try = 0; try <= adap->retries; try++) { ret = adap->algo->master_xfer(adap, msgs, num); if (ret != -EAGAIN) break; if (time_after(jiffies, orig_jiffies + adap->timeout)) break; } if (static_key_false(&i2c_trace_msg)) { int i; for (i = 0; i < ret; i++) if (msgs[i].flags & I2C_M_RD) trace_i2c_reply(adap, &msgs[i], i); trace_i2c_result(adap, i, ret); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
David Howells12452.54%116.67%
Jean Delvare6828.81%116.67%
Wolfram Sang198.05%116.67%
Linus Torvalds (pre-git)187.63%116.67%
Clifford Wolf62.54%116.67%
Mickey Stein10.42%116.67%
Total236100.00%6100.00%

EXPORT_SYMBOL(__i2c_transfer); /** * i2c_transfer - execute a single or combined I2C message * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. * * Returns negative errno, else the number of messages executed. * * Note that there is no requirement that each message be sent to * the same slave address, although that is the most common model. */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { int ret; /* REVISIT the fault reporting model here is weak: * * - When we get an error after receiving N bytes from a slave, * there is no way to report "N". * * - When we get a NAK after transmitting N bytes to a slave, * there is no way to report "N" ... or to let the master * continue executing the rest of this combined message, if * that's the appropriate response. * * - When for example "num" is two and we successfully complete * the first message but get an error part way through the * second, it's unclear whether that should be reported as * one (discarding status on the second message) or errno * (discarding status on the first one). */ if (adap->algo->master_xfer) { #ifdef DEBUG for (ret = 0; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, 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 if (in_atomic() || irqs_disabled()) { ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; } else { i2c_lock_bus(adap, I2C_LOCK_SEGMENT); } ret = __i2c_transfer(adap, msgs, num); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported\n"); return -EOPNOTSUPP; } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare8646.49%323.08%
Linus Torvalds (pre-git)4725.41%17.69%
Mike Rapoport2915.68%17.69%
Greg Kroah-Hartman94.86%215.38%
Peter Rosin94.86%215.38%
Clifford Wolf21.08%17.69%
David Brownell21.08%215.38%
Andy Shevchenko10.54%17.69%
Total185100.00%13100.00%

EXPORT_SYMBOL(i2c_transfer); /** * i2c_master_send - issue a single I2C message in master transmit mode * @client: Handle to slave device * @buf: Data that will be written to the slave * @count: How many bytes to write, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes written. */
int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; msg.addr = client->addr; 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 * transmitted, else error code. */ return (ret == 1) ? count : ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8692.47%120.00%
Greg Kroah-Hartman44.30%120.00%
Jean Delvare22.15%240.00%
Wolfram Sang11.08%120.00%
Total93100.00%5100.00%

EXPORT_SYMBOL(i2c_master_send); /** * i2c_master_recv - issue a single I2C message in master receive mode * @client: Handle to slave device * @buf: Where to store data read from slave * @count: How many bytes to read, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes read. */
int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; int ret; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; ret = i2c_transfer(adap, &msg, 1); /* * If everything went ok (i.e. 1 msg received), return #bytes received, * else error code. */ return (ret == 1) ? count : ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9196.81%125.00%
Jean Delvare22.13%250.00%
Wolfram Sang11.06%125.00%
Total94100.00%4100.00%

EXPORT_SYMBOL(i2c_master_recv); /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! * ---------------------------------------------------- */ /* * Legacy default probe function, mostly relevant for SMBus. The default * probe method is a quick write, but it is known to corrupt the 24RF08 * EEPROMs due to a state machine bug, and could also irreversibly * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f, * we use a short byte read instead. Also, some bus drivers don't implement * quick write, so we fallback to a byte read in that case too. * On x86, there is another special case for FSC hardware monitoring chips, * which want regular byte reads (address 0x73.) Fortunately, these are the * only known chips using this I2C address on PC hardware. * Returns 1 if probe succeeded, 0 if not. */
static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr) { int err; union i2c_smbus_data dummy; #ifdef CONFIG_X86 if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON) && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA)) err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE_DATA, &dummy); else #endif if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50) && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0, I2C_SMBUS_QUICK, NULL); else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy); else { dev_warn(&adap->dev, "No suitable probing method supported for address 0x%02X\n", addr); err = -EOPNOTSUPP; } return err >= 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare17098.27%266.67%
Andrew Lutomirski31.73%133.33%
Total173100.00%3100.00%


static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_driver *driver) { struct i2c_board_info info; struct i2c_adapter *adapter = temp_client->adapter; int addr = temp_client->addr; int err; /* Make sure the address is valid */ err = i2c_check_7bit_addr_validity_strict(addr); if (err) { dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", addr); return err; } /* Skip if already in use (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adapter, addr)) return 0; /* Make sure there is something at this address */ if (!i2c_default_probe(adapter, addr)) return 0; /* Finally call the custom detection function */ memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = addr; err = driver->detect(temp_client, &info); if (err) { /* -ENODEV is returned if the detection fails. We catch it here as this isn't an error. */ return err == -ENODEV ? 0 : err; } /* Consistency check */ if (info.type[0] == '\0') { dev_err(&adapter->dev, "%s detection function provided no name for 0x%x\n", driver->driver.name, addr); } else { struct i2c_client *client; /* Detection succeeded, instantiate the device */ if (adapter->class & I2C_CLASS_DEPRECATED) dev_warn(&adapter->dev, "This adapter will soon drop class based instantiation of devices. " "Please make sure client 0x%02x gets instantiated by other means. " "Check 'Documentation/i2c/instantiating-devices' for details.\n", info.addr); dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", info.type, info.addr); client = i2c_new_device(adapter, &info); if (client) list_add_tail(&client->detected, &driver->clients); else dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n", info.type, info.addr); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare25090.25%660.00%
Wolfram Sang269.39%330.00%
Andy Shevchenko10.36%110.00%
Total277100.00%10100.00%


static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) { const unsigned short *address_list; struct i2c_client *temp_client; int i, err = 0; int adap_id = i2c_adapter_id(adapter); address_list = driver->address_list; if (!driver->detect || !address_list) return 0; /* Warn that the adapter lost class based instantiation */ if (adapter->class == I2C_CLASS_DEPRECATED) { dev_dbg(&adapter->dev, "This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. " "If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n", driver->driver.name); return 0; } /* Stop here if the classes do not match */ if (!(adapter->class & driver->class)) return 0; /* Set up a temporary client to help detect callback */ temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!temp_client) return -ENOMEM; temp_client->adapter = adapter; for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { dev_dbg(&adapter->dev, "found normal entry for adapter %d, addr 0x%02x\n", adap_id, address_list[i]); temp_client->addr = address_list[i]; err = i2c_detect_address(temp_client, driver); if (unlikely(err)) break; } kfree(temp_client); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare17684.62%360.00%
Wolfram Sang2913.94%120.00%
Andy Shevchenko31.44%120.00%
Total208100.00%5100.00%


int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr) { return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_QUICK, NULL) >= 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare34100.00%1100.00%
Total34100.00%1100.00%

EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);
struct i2c_client * i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list, int (*probe)(struct i2c_adapter *, unsigned short addr)) { int i; if (!probe) probe = i2c_default_probe; for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address 0x%02x\n", addr_list[i]); continue; } /* Check address availability (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in use, not probing\n", addr_list[i]); continue; } /* Test address responsiveness */ if (probe(adap, addr_list[i])) break; } if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); return NULL; } info->addr = addr_list[i]; return i2c_new_device(adap, info); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare18197.84%562.50%
Wolfram Sang21.08%225.00%
Andy Shevchenko21.08%112.50%
Total185100.00%8100.00%

EXPORT_SYMBOL_GPL(i2c_new_probed_device);
struct i2c_adapter *i2c_get_adapter(int nr) { struct i2c_adapter *adapter; mutex_lock(&core_lock); adapter = idr_find(&i2c_adapter_idr, nr); if (!adapter) goto exit; if (try_module_get(adapter->owner)) get_device(&adapter->dev); else adapter = NULL; exit: mutex_unlock(&core_lock); return adapter; }

Contributors

PersonTokensPropCommitsCommitProp
Gerd Knorr3143.06%114.29%
Vladimir Zapolskiy1825.00%114.29%
Mark M. Hoffman912.50%114.29%
Linus Torvalds (pre-git)811.11%114.29%
Jean Delvare45.56%228.57%
Arjan van de Ven22.78%114.29%
Total72100.00%7100.00%

EXPORT_SYMBOL(i2c_get_adapter);
void i2c_put_adapter(struct i2c_adapter *adap) { if (!adap) return; put_device(&adap->dev); module_put(adap->owner); }

Contributors

PersonTokensPropCommitsCommitProp
Gerd Knorr1754.84%133.33%
Vladimir Zapolskiy1032.26%133.33%
Sebastian Hesselbarth412.90%133.33%
Total31100.00%3100.00%

EXPORT_SYMBOL(i2c_put_adapter); MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Jean Delvare305835.19%5726.64%
Wolfram Sang118513.63%2712.62%
David Brownell88710.21%167.48%
Viresh Kumar5205.98%10.47%
Dmitry Torokhov3914.50%52.34%
Benjamin Tissoires3634.18%10.47%
Linus Torvalds (pre-git)3564.10%31.40%
Greg Kroah-Hartman1772.04%125.61%
David Howells1671.92%10.47%
Michael Lawnick1361.56%10.47%
Gerd Knorr1211.39%20.93%
Douglas Anderson1121.29%10.47%
Jean-Michel Hautbois1061.22%10.47%
Peter Rosin740.85%41.87%
Jarkko Nikula720.83%20.93%
Lee Jones720.83%52.34%
Pantelis Antoniou530.61%31.40%
Octavian Purdila530.61%10.47%
Rui Zhang480.55%10.47%
Mika Westerberg470.54%31.40%
Adrian Bunk420.48%20.93%
Dave Young380.44%10.47%
Vladimir Zapolskiy360.41%20.93%
Stephen Warren350.40%10.47%
Lars-Peter Clausen350.40%31.40%
Mike Rapoport330.38%10.47%
Laurent Pinchart330.38%10.47%
Russell King280.32%10.47%
Lv Zheng270.31%10.47%
Faik Uygur250.29%10.47%
Andy Shevchenko220.25%20.93%
Grant C. Likely220.25%31.40%
Mark Brown190.22%20.93%
Marc Pignat190.22%10.47%
Sylwester Nawrocki190.22%10.47%
Christoph Hellwig180.21%31.40%
Anton Vorontsov170.20%10.47%
Tejun Heo170.20%10.47%
Thadeu Lima de Souza Cascardo150.17%10.47%
Jan Lübbe140.16%10.47%
Bartosz Golaszewski140.16%20.93%
Hans de Goede140.16%10.47%
Ulf Hansson130.15%20.93%
Geert Uytterhoeven130.15%10.47%
Linus Walleij100.12%10.47%
Mark M. Hoffman90.10%10.47%
Charles Keepax80.09%10.47%
Lan Tianyu80.09%10.47%
Clifford Wolf80.09%10.47%
Hans Verkuil70.08%10.47%
Arjan van de Ven70.08%10.47%
Sudip Mukherjee60.07%10.47%
Zhenwen Xu60.07%10.47%
Rafael J. Wysocki60.07%20.93%
Linus Torvalds50.06%10.47%
Grygorii Strashko50.06%20.93%
Laurent Riffard50.06%10.47%
Jon Smirl50.06%10.47%
Kieran Bingham40.05%10.47%
Steven Rostedt40.05%10.47%
Sebastian Hesselbarth40.05%10.47%
Rodolfo Giometti30.03%10.47%
Andrew Lutomirski30.03%10.47%
Kay Sievers20.02%10.47%
Zhangfei Gao20.02%10.47%
Alexander Sverdlin10.01%10.47%
Matthias Kaehlcke10.01%10.47%
Andreas Schultz10.01%10.47%
Mika Kuoppala10.01%10.47%
Javier Martinez Canillas10.01%10.47%
Mickey Stein10.01%10.47%
Shailendra Verma10.01%10.47%
Lucas De Marchi10.01%10.47%
Total8691100.00%214100.00%
Directory: drivers/i2c
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.