Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

63
drivers/i2c/muxes/Kconfig Normal file
View file

@ -0,0 +1,63 @@
#
# Multiplexer I2C chip drivers configuration
#
menu "Multiplexer I2C Chip support"
depends on I2C_MUX
config I2C_ARB_GPIO_CHALLENGE
tristate "GPIO-based I2C arbitration"
depends on GPIOLIB && OF
help
If you say yes to this option, support will be included for an
I2C multimaster arbitration scheme using GPIOs and a challenge &
response mechanism where masters have to claim the bus by asserting
a GPIO.
This driver can also be built as a module. If so, the module
will be called i2c-arb-gpio-challenge.
config I2C_MUX_GPIO
tristate "GPIO-based I2C multiplexer"
depends on GPIOLIB
help
If you say yes to this option, support will be included for a
GPIO based I2C multiplexer. This driver provides access to
I2C busses connected through a MUX, which is controlled
through GPIO pins.
This driver can also be built as a module. If so, the module
will be called i2c-mux-gpio.
config I2C_MUX_PCA9541
tristate "NXP PCA9541 I2C Master Selector"
help
If you say yes here you get support for the NXP PCA9541
I2C Master Selector.
This driver can also be built as a module. If so, the module
will be called i2c-mux-pca9541.
config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches"
depends on GPIOLIB
help
If you say yes here you get support for the Philips PCA954x
I2C mux/switch devices.
This driver can also be built as a module. If so, the module
will be called i2c-mux-pca954x.
config I2C_MUX_PINCTRL
tristate "pinctrl-based I2C multiplexer"
depends on PINCTRL
help
If you say yes to this option, support will be included for an I2C
multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing.
This is useful for SoCs whose I2C module's signals can be routed to
different sets of pins at run-time.
This driver can also be built as a module. If so, the module will be
called pinctrl-i2cmux.
endmenu

View file

@ -0,0 +1,11 @@
#
# Makefile for multiplexer I2C chip drivers.
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG

View file

@ -0,0 +1,249 @@
/*
* GPIO-based I2C Arbitration Using a Challenge & Response Mechanism
*
* Copyright (C) 2012 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
* @parent: Parent adapter
* @child: Child bus
* @our_gpio: GPIO we'll use to claim.
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
* @their_gpio: GPIO that the other side will use to claim.
* @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
* @slew_delay_us: microseconds to wait for a GPIO to go high.
* @wait_retry_us: we'll attempt another claim after this many microseconds.
* @wait_free_us: we'll give up after this many microseconds.
*/
struct i2c_arbitrator_data {
struct i2c_adapter *parent;
struct i2c_adapter *child;
int our_gpio;
int our_gpio_release;
int their_gpio;
int their_gpio_release;
unsigned int slew_delay_us;
unsigned int wait_retry_us;
unsigned int wait_free_us;
};
/**
* i2c_arbitrator_select - claim the I2C bus
*
* Use the GPIO-based signalling protocol; return -EBUSY if we fail.
*/
static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
{
const struct i2c_arbitrator_data *arb = data;
unsigned long stop_retry, stop_time;
/* Start a round of trying to claim the bus */
stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1;
do {
/* Indicate that we want to claim the bus */
gpio_set_value(arb->our_gpio, !arb->our_gpio_release);
udelay(arb->slew_delay_us);
/* Wait for the other master to release it */
stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1;
while (time_before(jiffies, stop_retry)) {
int gpio_val = !!gpio_get_value(arb->their_gpio);
if (gpio_val == arb->their_gpio_release) {
/* We got it, so return */
return 0;
}
usleep_range(50, 200);
}
/* It didn't release, so give up, wait, and try again */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2);
} while (time_before(jiffies, stop_time));
/* Give up, release our claim */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
udelay(arb->slew_delay_us);
dev_err(&adap->dev, "Could not claim bus, timeout\n");
return -EBUSY;
}
/**
* i2c_arbitrator_deselect - release the I2C bus
*
* Release the I2C bus using the GPIO-based signalling protocol.
*/
static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
u32 chan)
{
const struct i2c_arbitrator_data *arb = data;
/* Release the bus and wait for the other master to notice */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
udelay(arb->slew_delay_us);
return 0;
}
static int i2c_arbitrator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *parent_np;
struct i2c_arbitrator_data *arb;
enum of_gpio_flags gpio_flags;
unsigned long out_init;
int ret;
/* We only support probing from device tree; no platform_data */
if (!np) {
dev_err(dev, "Cannot find device tree node\n");
return -ENODEV;
}
if (dev_get_platdata(dev)) {
dev_err(dev, "Platform data is not supported\n");
return -EINVAL;
}
arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
if (!arb) {
dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, arb);
/* Request GPIOs */
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
if (!gpio_is_valid(ret)) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error getting our-claim-gpio\n");
return ret;
}
arb->our_gpio = ret;
arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
ret = devm_gpio_request_one(dev, arb->our_gpio, out_init,
"our-claim-gpio");
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error requesting our-claim-gpio\n");
return ret;
}
ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags);
if (!gpio_is_valid(ret)) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error getting their-claim-gpio\n");
return ret;
}
arb->their_gpio = ret;
arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN,
"their-claim-gpio");
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Error requesting their-claim-gpio\n");
return ret;
}
/* At the moment we only support a single two master (us + 1 other) */
if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) {
dev_err(dev, "Only one other master is supported\n");
return -EINVAL;
}
/* Arbitration parameters */
if (of_property_read_u32(np, "slew-delay-us", &arb->slew_delay_us))
arb->slew_delay_us = 10;
if (of_property_read_u32(np, "wait-retry-us", &arb->wait_retry_us))
arb->wait_retry_us = 3000;
if (of_property_read_u32(np, "wait-free-us", &arb->wait_free_us))
arb->wait_free_us = 50000;
/* Find our parent */
parent_np = of_parse_phandle(np, "i2c-parent", 0);
if (!parent_np) {
dev_err(dev, "Cannot parse i2c-parent\n");
return -EINVAL;
}
arb->parent = of_find_i2c_adapter_by_node(parent_np);
if (!arb->parent) {
dev_err(dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
/* Actually add the mux adapter */
arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
i2c_arbitrator_select,
i2c_arbitrator_deselect);
if (!arb->child) {
dev_err(dev, "Failed to add adapter\n");
ret = -ENODEV;
i2c_put_adapter(arb->parent);
}
return ret;
}
static int i2c_arbitrator_remove(struct platform_device *pdev)
{
struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev);
i2c_del_mux_adapter(arb->child);
i2c_put_adapter(arb->parent);
return 0;
}
static const struct of_device_id i2c_arbitrator_of_match[] = {
{ .compatible = "i2c-arb-gpio-challenge", },
{},
};
MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match);
static struct platform_driver i2c_arbitrator_driver = {
.probe = i2c_arbitrator_probe,
.remove = i2c_arbitrator_remove,
.driver = {
.owner = THIS_MODULE,
.name = "i2c-arb-gpio-challenge",
.of_match_table = i2c_arbitrator_of_match,
},
};
module_platform_driver(i2c_arbitrator_driver);
MODULE_DESCRIPTION("GPIO-based I2C Arbitration");
MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-arb-gpio-challenge");

View file

@ -0,0 +1,294 @@
/*
* I2C multiplexer using GPIO API
*
* Peter Korsgaard <peter.korsgaard@barco.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/i2c-mux-gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
struct gpiomux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_gpio_platform_data data;
unsigned gpio_base;
};
static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
{
int i;
for (i = 0; i < mux->data.n_gpios; i++)
gpio_set_value_cansleep(mux->gpio_base + mux->data.gpios[i],
val & (1 << i));
}
static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
{
struct gpiomux *mux = data;
i2c_mux_gpio_set(mux, chan);
return 0;
}
static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
{
struct gpiomux *mux = data;
i2c_mux_gpio_set(mux, mux->data.idle);
return 0;
}
static int match_gpio_chip_by_label(struct gpio_chip *chip,
void *data)
{
return !strcmp(chip->label, data);
}
#ifdef CONFIG_OF
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
unsigned *values, *gpios;
int i = 0, ret;
if (!np)
return -ENODEV;
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
if (!adapter) {
dev_err(&pdev->dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev);
mux->data.n_values = of_get_child_count(np);
values = devm_kzalloc(&pdev->dev,
sizeof(*mux->data.values) * mux->data.n_values,
GFP_KERNEL);
if (!values) {
dev_err(&pdev->dev, "Cannot allocate values array");
return -ENOMEM;
}
for_each_child_of_node(np, child) {
of_property_read_u32(child, "reg", values + i);
i++;
}
mux->data.values = values;
if (of_property_read_u32(np, "idle-state", &mux->data.idle))
mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios");
if (mux->data.n_gpios < 0) {
dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n");
return -EINVAL;
}
gpios = devm_kzalloc(&pdev->dev,
sizeof(*mux->data.gpios) * mux->data.n_gpios, GFP_KERNEL);
if (!gpios) {
dev_err(&pdev->dev, "Cannot allocate gpios array");
return -ENOMEM;
}
for (i = 0; i < mux->data.n_gpios; i++) {
ret = of_get_named_gpio(np, "mux-gpios", i);
if (ret < 0)
return ret;
gpios[i] = ret;
}
mux->data.gpios = gpios;
return 0;
}
#else
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
{
return 0;
}
#endif
static int i2c_mux_gpio_probe(struct platform_device *pdev)
{
struct gpiomux *mux;
struct i2c_adapter *parent;
int (*deselect) (struct i2c_adapter *, void *, u32);
unsigned initial_state, gpio_base;
int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) {
dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
return -ENOMEM;
}
platform_set_drvdata(pdev, mux);
if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev);
if (ret < 0)
return ret;
} else {
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
sizeof(mux->data));
}
/*
* If a GPIO chip name is provided, the GPIO pin numbers provided are
* relative to its base GPIO number. Otherwise they are absolute.
*/
if (mux->data.gpio_chip) {
struct gpio_chip *gpio;
gpio = gpiochip_find(mux->data.gpio_chip,
match_gpio_chip_by_label);
if (!gpio)
return -EPROBE_DEFER;
gpio_base = gpio->base;
} else {
gpio_base = 0;
}
parent = i2c_get_adapter(mux->data.parent);
if (!parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
mux->data.parent);
return -EPROBE_DEFER;
}
mux->parent = parent;
mux->gpio_base = gpio_base;
mux->adap = devm_kzalloc(&pdev->dev,
sizeof(*mux->adap) * mux->data.n_values,
GFP_KERNEL);
if (!mux->adap) {
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
ret = -ENOMEM;
goto alloc_failed;
}
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
deselect = i2c_mux_gpio_deselect;
} else {
initial_state = mux->data.values[0];
deselect = NULL;
}
for (i = 0; i < mux->data.n_gpios; i++) {
ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n",
mux->data.gpios[i]);
goto err_request_gpio;
}
ret = gpio_direction_output(gpio_base + mux->data.gpios[i],
initial_state & (1 << i));
if (ret) {
dev_err(&pdev->dev,
"Failed to set direction of GPIO %d to output\n",
mux->data.gpios[i]);
i++; /* gpio_request above succeeded, so must free */
goto err_request_gpio;
}
}
for (i = 0; i < mux->data.n_values; i++) {
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
mux->data.values[i], class,
i2c_mux_gpio_select, deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
}
dev_info(&pdev->dev, "%d port mux on %s adapter\n",
mux->data.n_values, parent->name);
return 0;
add_adapter_failed:
for (; i > 0; i--)
i2c_del_mux_adapter(mux->adap[i - 1]);
i = mux->data.n_gpios;
err_request_gpio:
for (; i > 0; i--)
gpio_free(gpio_base + mux->data.gpios[i - 1]);
alloc_failed:
i2c_put_adapter(parent);
return ret;
}
static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
struct gpiomux *mux = platform_get_drvdata(pdev);
int i;
for (i = 0; i < mux->data.n_values; i++)
i2c_del_mux_adapter(mux->adap[i]);
for (i = 0; i < mux->data.n_gpios; i++)
gpio_free(mux->gpio_base + mux->data.gpios[i]);
i2c_put_adapter(mux->parent);
return 0;
}
static const struct of_device_id i2c_mux_gpio_of_match[] = {
{ .compatible = "i2c-mux-gpio", },
{},
};
MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match);
static struct platform_driver i2c_mux_gpio_driver = {
.probe = i2c_mux_gpio_probe,
.remove = i2c_mux_gpio_remove,
.driver = {
.owner = THIS_MODULE,
.name = "i2c-mux-gpio",
.of_match_table = i2c_mux_gpio_of_match,
},
};
module_platform_driver(i2c_mux_gpio_driver);
MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:i2c-mux-gpio");

View file

@ -0,0 +1,400 @@
/*
* I2C multiplexer driver for PCA9541 bus master selector
*
* Copyright (c) 2010 Ericsson AB.
*
* Author: Guenter Roeck <linux@roeck-us.net>
*
* Derived from:
* pca954x.c
*
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h>
/*
* The PCA9541 is a bus master selector. It supports two I2C masters connected
* to a single slave bus.
*
* Before each bus transaction, a master has to acquire bus ownership. After the
* transaction is complete, bus ownership has to be released. This fits well
* into the I2C multiplexer framework, which provides select and release
* functions for this purpose. For this reason, this driver is modeled as
* single-channel I2C bus multiplexer.
*
* This driver assumes that the two bus masters are controlled by two different
* hosts. If a single host controls both masters, platform code has to ensure
* that only one of the masters is instantiated at any given time.
*/
#define PCA9541_CONTROL 0x01
#define PCA9541_ISTAT 0x02
#define PCA9541_CTL_MYBUS (1 << 0)
#define PCA9541_CTL_NMYBUS (1 << 1)
#define PCA9541_CTL_BUSON (1 << 2)
#define PCA9541_CTL_NBUSON (1 << 3)
#define PCA9541_CTL_BUSINIT (1 << 4)
#define PCA9541_CTL_TESTON (1 << 6)
#define PCA9541_CTL_NTESTON (1 << 7)
#define PCA9541_ISTAT_INTIN (1 << 0)
#define PCA9541_ISTAT_BUSINIT (1 << 1)
#define PCA9541_ISTAT_BUSOK (1 << 2)
#define PCA9541_ISTAT_BUSLOST (1 << 3)
#define PCA9541_ISTAT_MYTEST (1 << 6)
#define PCA9541_ISTAT_NMYTEST (1 << 7)
#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
#define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
#define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON)
/* arbitration timeouts, in jiffies */
#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */
#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */
/* arbitration retry delays, in us */
#define SELECT_DELAY_SHORT 50
#define SELECT_DELAY_LONG 1000
struct pca9541 {
struct i2c_adapter *mux_adap;
unsigned long select_timeout;
unsigned long arb_timeout;
};
static const struct i2c_device_id pca9541_id[] = {
{"pca9541", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pca9541_id);
/*
* Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
* as they will try to lock the adapter a second time.
*/
static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
{
struct i2c_adapter *adap = client->adapter;
int ret;
if (adap->algo->master_xfer) {
struct i2c_msg msg;
char buf[2];
msg.addr = client->addr;
msg.flags = 0;
msg.len = 2;
buf[0] = command;
buf[1] = val;
msg.buf = buf;
ret = adap->algo->master_xfer(adap, &msg, 1);
} else {
union i2c_smbus_data data;
data.byte = val;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_WRITE,
command,
I2C_SMBUS_BYTE_DATA, &data);
}
return ret;
}
/*
* Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
* as they will try to lock adapter a second time.
*/
static int pca9541_reg_read(struct i2c_client *client, u8 command)
{
struct i2c_adapter *adap = client->adapter;
int ret;
u8 val;
if (adap->algo->master_xfer) {
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &command
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &val
}
};
ret = adap->algo->master_xfer(adap, msg, 2);
if (ret == 2)
ret = val;
else if (ret >= 0)
ret = -EIO;
} else {
union i2c_smbus_data data;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_READ,
command,
I2C_SMBUS_BYTE_DATA, &data);
if (!ret)
ret = data.byte;
}
return ret;
}
/*
* Arbitration management functions
*/
/* Release bus. Also reset NTESTON and BUSINIT if it was set. */
static void pca9541_release_bus(struct i2c_client *client)
{
int reg;
reg = pca9541_reg_read(client, PCA9541_CONTROL);
if (reg >= 0 && !busoff(reg) && mybus(reg))
pca9541_reg_write(client, PCA9541_CONTROL,
(reg & PCA9541_CTL_NBUSON) >> 1);
}
/*
* Arbitration is defined as a two-step process. A bus master can only activate
* the slave bus if it owns it; otherwise it has to request ownership first.
* This multi-step process ensures that access contention is resolved
* gracefully.
*
* Bus Ownership Other master Action
* state requested access
* ----------------------------------------------------
* off - yes wait for arbitration timeout or
* for other master to drop request
* off no no take ownership
* off yes no turn on bus
* on yes - done
* on no - wait for arbitration timeout or
* for other master to release bus
*
* The main contention point occurs if the slave bus is off and both masters
* request ownership at the same time. In this case, one master will turn on
* the slave bus, believing that it owns it. The other master will request
* bus ownership. Result is that the bus is turned on, and master which did
* _not_ own the slave bus before ends up owning it.
*/
/* Control commands per PCA9541 datasheet */
static const u8 pca9541_control[16] = {
4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1
};
/*
* Channel arbitration
*
* Return values:
* <0: error
* 0 : bus not acquired
* 1 : bus acquired
*/
static int pca9541_arbitrate(struct i2c_client *client)
{
struct pca9541 *data = i2c_get_clientdata(client);
int reg;
reg = pca9541_reg_read(client, PCA9541_CONTROL);
if (reg < 0)
return reg;
if (busoff(reg)) {
int istat;
/*
* Bus is off. Request ownership or turn it on unless
* other master requested ownership.
*/
istat = pca9541_reg_read(client, PCA9541_ISTAT);
if (!(istat & PCA9541_ISTAT_NMYTEST)
|| time_is_before_eq_jiffies(data->arb_timeout)) {
/*
* Other master did not request ownership,
* or arbitration timeout expired. Take the bus.
*/
pca9541_reg_write(client,
PCA9541_CONTROL,
pca9541_control[reg & 0x0f]
| PCA9541_CTL_NTESTON);
data->select_timeout = SELECT_DELAY_SHORT;
} else {
/*
* Other master requested ownership.
* Set extra long timeout to give it time to acquire it.
*/
data->select_timeout = SELECT_DELAY_LONG * 2;
}
} else if (mybus(reg)) {
/*
* Bus is on, and we own it. We are done with acquisition.
* Reset NTESTON and BUSINIT, then return success.
*/
if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT))
pca9541_reg_write(client,
PCA9541_CONTROL,
reg & ~(PCA9541_CTL_NTESTON
| PCA9541_CTL_BUSINIT));
return 1;
} else {
/*
* Other master owns the bus.
* If arbitration timeout has expired, force ownership.
* Otherwise request it.
*/
data->select_timeout = SELECT_DELAY_LONG;
if (time_is_before_eq_jiffies(data->arb_timeout)) {
/* Time is up, take the bus and reset it. */
pca9541_reg_write(client,
PCA9541_CONTROL,
pca9541_control[reg & 0x0f]
| PCA9541_CTL_BUSINIT
| PCA9541_CTL_NTESTON);
} else {
/* Request bus ownership if needed */
if (!(reg & PCA9541_CTL_NTESTON))
pca9541_reg_write(client,
PCA9541_CONTROL,
reg | PCA9541_CTL_NTESTON);
}
}
return 0;
}
static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
{
struct pca9541 *data = i2c_get_clientdata(client);
int ret;
unsigned long timeout = jiffies + ARB2_TIMEOUT;
/* give up after this time */
data->arb_timeout = jiffies + ARB_TIMEOUT;
/* force bus ownership after this time */
do {
ret = pca9541_arbitrate(client);
if (ret)
return ret < 0 ? ret : 0;
if (data->select_timeout == SELECT_DELAY_SHORT)
udelay(data->select_timeout);
else
msleep(data->select_timeout / 1000);
} while (time_is_after_eq_jiffies(timeout));
return -ETIMEDOUT;
}
static int pca9541_release_chan(struct i2c_adapter *adap,
void *client, u32 chan)
{
pca9541_release_bus(client);
return 0;
}
/*
* I2C init/probing/exit functions
*/
static int pca9541_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca9541 *data;
int force;
int ret = -ENODEV;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
goto err;
data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err;
}
i2c_set_clientdata(client, data);
/*
* I2C accesses are unprotected here.
* We have to lock the adapter before releasing the bus.
*/
i2c_lock_adapter(adap);
pca9541_release_bus(client);
i2c_unlock_adapter(adap);
/* Create mux adapter */
force = 0;
if (pdata)
force = pdata->modes[0].adap_id;
data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
force, 0, 0,
pca9541_select_chan,
pca9541_release_chan);
if (data->mux_adap == NULL) {
dev_err(&client->dev, "failed to register master selector\n");
goto exit_free;
}
dev_info(&client->dev, "registered master selector for I2C %s\n",
client->name);
return 0;
exit_free:
kfree(data);
err:
return ret;
}
static int pca9541_remove(struct i2c_client *client)
{
struct pca9541 *data = i2c_get_clientdata(client);
i2c_del_mux_adapter(data->mux_adap);
kfree(data);
return 0;
}
static struct i2c_driver pca9541_driver = {
.driver = {
.name = "pca9541",
.owner = THIS_MODULE,
},
.probe = pca9541_probe,
.remove = pca9541_remove,
.id_table = pca9541_id,
};
module_i2c_driver(pca9541_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,305 @@
/*
* I2C multiplexer
*
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
*
* This module supports the PCA954x series of I2C multiplexer/switch chips
* made by Philips Semiconductors.
* This includes the:
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
* and PCA9548.
*
* These chips are all controlled via the I2C bus itself, and all have a
* single 8-bit register. The upstream "parent" bus fans out to two,
* four, or eight downstream busses or channels; which of these
* are selected is determined by the chip type and register contents. A
* mux can select only one sub-bus at a time; a switch can select any
* combination simultaneously.
*
* Based on:
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
* Copyright (C) 2006
*
* Based on:
* pca954x.c from Ken Harrenstien
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
*
* Based on:
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
* and
* pca9540.c from Jean Delvare <jdelvare@suse.de>.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/slab.h>
#define PCA954X_MAX_NCHANS 8
enum pca_type {
pca_9540,
pca_9542,
pca_9543,
pca_9544,
pca_9545,
pca_9546,
pca_9547,
pca_9548,
};
struct pca954x {
enum pca_type type;
struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
u8 last_chan; /* last register value */
};
struct chip_desc {
u8 nchans;
u8 enable; /* used for muxes only */
enum muxtype {
pca954x_ismux = 0,
pca954x_isswi
} muxtype;
};
/* Provide specs for the PCA954x types we know about */
static const struct chip_desc chips[] = {
[pca_9540] = {
.nchans = 2,
.enable = 0x4,
.muxtype = pca954x_ismux,
},
[pca_9543] = {
.nchans = 2,
.muxtype = pca954x_isswi,
},
[pca_9544] = {
.nchans = 4,
.enable = 0x4,
.muxtype = pca954x_ismux,
},
[pca_9545] = {
.nchans = 4,
.muxtype = pca954x_isswi,
},
[pca_9547] = {
.nchans = 8,
.enable = 0x8,
.muxtype = pca954x_ismux,
},
[pca_9548] = {
.nchans = 8,
.muxtype = pca954x_isswi,
},
};
static const struct i2c_device_id pca954x_id[] = {
{ "pca9540", pca_9540 },
{ "pca9542", pca_9540 },
{ "pca9543", pca_9543 },
{ "pca9544", pca_9544 },
{ "pca9545", pca_9545 },
{ "pca9546", pca_9545 },
{ "pca9547", pca_9547 },
{ "pca9548", pca_9548 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
for this as they will try to lock adapter a second time */
static int pca954x_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
{
int ret = -ENODEV;
if (adap->algo->master_xfer) {
struct i2c_msg msg;
char buf[1];
msg.addr = client->addr;
msg.flags = 0;
msg.len = 1;
buf[0] = val;
msg.buf = buf;
ret = adap->algo->master_xfer(adap, &msg, 1);
} else {
union i2c_smbus_data data;
ret = adap->algo->smbus_xfer(adap, client->addr,
client->flags,
I2C_SMBUS_WRITE,
val, I2C_SMBUS_BYTE, &data);
}
return ret;
}
static int pca954x_select_chan(struct i2c_adapter *adap,
void *client, u32 chan)
{
struct pca954x *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
u8 regval;
int ret = 0;
/* we make switches look like muxes, not sure how to be smarter */
if (chip->muxtype == pca954x_ismux)
regval = chan | chip->enable;
else
regval = 1 << chan;
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = pca954x_reg_write(adap, client, regval);
data->last_chan = regval;
}
return ret;
}
static int pca954x_deselect_mux(struct i2c_adapter *adap,
void *client, u32 chan)
{
struct pca954x *data = i2c_get_clientdata(client);
/* Deselect active channel */
data->last_chan = 0;
return pca954x_reg_write(adap, client, data->last_chan);
}
/*
* I2C init/probing/exit functions
*/
static int pca954x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct gpio_desc *gpio;
int num, force, class;
struct pca954x *data;
int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
/* Get the mux out of reset if a reset GPIO is specified. */
gpio = devm_gpiod_get(&client->dev, "reset");
if (!IS_ERR(gpio))
gpiod_direction_output(gpio, 0);
/* Write the mux register at addr to verify
* that the mux is in fact present. This also
* initializes the mux to disconnected state.
*/
if (i2c_smbus_write_byte(client, 0) < 0) {
dev_warn(&client->dev, "probe failed\n");
return -ENODEV;
}
data->type = id->driver_data;
data->last_chan = 0; /* force the first selection */
/* Now create an adapter for each channel */
for (num = 0; num < chips[data->type].nchans; num++) {
force = 0; /* dynamic adap number */
class = 0; /* no class by default */
if (pdata) {
if (num < pdata->num_modes) {
/* force static number */
force = pdata->modes[num].adap_id;
class = pdata->modes[num].class;
} else
/* discard unconfigured channels */
break;
}
data->virt_adaps[num] =
i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan,
(pdata && pdata->modes[num].deselect_on_exit)
? pca954x_deselect_mux : NULL);
if (data->virt_adaps[num] == NULL) {
ret = -ENODEV;
dev_err(&client->dev,
"failed to register multiplexed adapter"
" %d as bus %d\n", num, force);
goto virt_reg_failed;
}
}
dev_info(&client->dev,
"registered %d multiplexed busses for I2C %s %s\n",
num, chips[data->type].muxtype == pca954x_ismux
? "mux" : "switch", client->name);
return 0;
virt_reg_failed:
for (num--; num >= 0; num--)
i2c_del_mux_adapter(data->virt_adaps[num]);
return ret;
}
static int pca954x_remove(struct i2c_client *client)
{
struct pca954x *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
int i;
for (i = 0; i < chip->nchans; ++i)
if (data->virt_adaps[i]) {
i2c_del_mux_adapter(data->virt_adaps[i]);
data->virt_adaps[i] = NULL;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pca954x_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pca954x *data = i2c_get_clientdata(client);
data->last_chan = 0;
return i2c_smbus_write_byte(client, 0);
}
#endif
static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume);
static struct i2c_driver pca954x_driver = {
.driver = {
.name = "pca954x",
.pm = &pca954x_pm,
.owner = THIS_MODULE,
},
.probe = pca954x_probe,
.remove = pca954x_remove,
.id_table = pca954x_id,
};
module_i2c_driver(pca954x_driver);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,278 @@
/*
* I2C multiplexer using pinctrl API
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/i2c-mux-pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
struct i2c_mux_pinctrl {
struct device *dev;
struct i2c_mux_pinctrl_platform_data *pdata;
struct pinctrl *pinctrl;
struct pinctrl_state **states;
struct pinctrl_state *state_idle;
struct i2c_adapter *parent;
struct i2c_adapter **busses;
};
static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
u32 chan)
{
struct i2c_mux_pinctrl *mux = data;
return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
}
static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
u32 chan)
{
struct i2c_mux_pinctrl *mux = data;
return pinctrl_select_state(mux->pinctrl, mux->state_idle);
}
#ifdef CONFIG_OF
static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int num_names, i, ret;
struct device_node *adapter_np;
struct i2c_adapter *adapter;
if (!np)
return 0;
mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
if (!mux->pdata) {
dev_err(mux->dev,
"Cannot allocate i2c_mux_pinctrl_platform_data\n");
return -ENOMEM;
}
num_names = of_property_count_strings(np, "pinctrl-names");
if (num_names < 0) {
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
num_names);
return num_names;
}
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
sizeof(*mux->pdata->pinctrl_states) * num_names,
GFP_KERNEL);
if (!mux->pdata->pinctrl_states) {
dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
return -ENOMEM;
}
for (i = 0; i < num_names; i++) {
ret = of_property_read_string_index(np, "pinctrl-names", i,
&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
if (ret < 0) {
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
ret);
return ret;
}
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
"idle")) {
if (i != num_names - 1) {
dev_err(mux->dev, "idle state must be last\n");
return -EINVAL;
}
mux->pdata->pinctrl_state_idle = "idle";
} else {
mux->pdata->bus_count++;
}
}
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
dev_err(mux->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
if (!adapter) {
dev_err(mux->dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
put_device(&adapter->dev);
return 0;
}
#else
static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
struct platform_device *pdev)
{
return 0;
}
#endif
static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
{
struct i2c_mux_pinctrl *mux;
int (*deselect)(struct i2c_adapter *, void *, u32);
int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) {
dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
ret = -ENOMEM;
goto err;
}
platform_set_drvdata(pdev, mux);
mux->dev = &pdev->dev;
mux->pdata = dev_get_platdata(&pdev->dev);
if (!mux->pdata) {
ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
if (ret < 0)
goto err;
}
if (!mux->pdata) {
dev_err(&pdev->dev, "Missing platform data\n");
ret = -ENODEV;
goto err;
}
mux->states = devm_kzalloc(&pdev->dev,
sizeof(*mux->states) * mux->pdata->bus_count,
GFP_KERNEL);
if (!mux->states) {
dev_err(&pdev->dev, "Cannot allocate states\n");
ret = -ENOMEM;
goto err;
}
mux->busses = devm_kzalloc(&pdev->dev,
sizeof(*mux->busses) * mux->pdata->bus_count,
GFP_KERNEL);
if (!mux->busses) {
dev_err(&pdev->dev, "Cannot allocate busses\n");
ret = -ENOMEM;
goto err;
}
mux->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(mux->pinctrl)) {
ret = PTR_ERR(mux->pinctrl);
dev_err(&pdev->dev, "Cannot get pinctrl: %d\n", ret);
goto err;
}
for (i = 0; i < mux->pdata->bus_count; i++) {
mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
mux->pdata->pinctrl_states[i]);
if (IS_ERR(mux->states[i])) {
ret = PTR_ERR(mux->states[i]);
dev_err(&pdev->dev,
"Cannot look up pinctrl state %s: %d\n",
mux->pdata->pinctrl_states[i], ret);
goto err;
}
}
if (mux->pdata->pinctrl_state_idle) {
mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
mux->pdata->pinctrl_state_idle);
if (IS_ERR(mux->state_idle)) {
ret = PTR_ERR(mux->state_idle);
dev_err(&pdev->dev,
"Cannot look up pinctrl state %s: %d\n",
mux->pdata->pinctrl_state_idle, ret);
goto err;
}
deselect = i2c_mux_pinctrl_deselect;
} else {
deselect = NULL;
}
mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
if (!mux->parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
mux->pdata->parent_bus_num);
ret = -EPROBE_DEFER;
goto err;
}
for (i = 0; i < mux->pdata->bus_count; i++) {
u32 bus = mux->pdata->base_bus_num ?
(mux->pdata->base_bus_num + i) : 0;
mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
mux, bus, i, 0,
i2c_mux_pinctrl_select,
deselect);
if (!mux->busses[i]) {
ret = -ENODEV;
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto err_del_adapter;
}
}
return 0;
err_del_adapter:
for (; i > 0; i--)
i2c_del_mux_adapter(mux->busses[i - 1]);
i2c_put_adapter(mux->parent);
err:
return ret;
}
static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
{
struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
int i;
for (i = 0; i < mux->pdata->bus_count; i++)
i2c_del_mux_adapter(mux->busses[i]);
i2c_put_adapter(mux->parent);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id i2c_mux_pinctrl_of_match[] = {
{ .compatible = "i2c-mux-pinctrl", },
{},
};
MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
#endif
static struct platform_driver i2c_mux_pinctrl_driver = {
.driver = {
.name = "i2c-mux-pinctrl",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
},
.probe = i2c_mux_pinctrl_probe,
.remove = i2c_mux_pinctrl_remove,
};
module_platform_driver(i2c_mux_pinctrl_driver);
MODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-mux-pinctrl");