Merge branch 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wilfram Sang:
 "I2C has the following updates for you:

   - an immutable cross-subsystem branch fixing PMIC access on Intel
     Baytrail

   - bigger driver updates to the designware, meson, exynos5 drivers

   - new i2c_acpi_new_device() function to create devices from ACPI

   - struct i2c_driver has now a flag 'disable_i2c_core_irq_mapping' to
     allow custom IRQ mapping in case the default does not fit

   - mux subsystem centralized error messages in its core

   - new driver for ltc4306 i2c mux

   - usual set of small updates"

* 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (44 commits)
  i2c: thunderx: Enable HWMON class probing
  i2c: rcar: clarify PM handling with more comments
  i2c: rcar: fix resume by always initializing registers before transfer
  i2c: tegra: fix spelling mistake: "contoller" -> "controller"
  i2c: exynos5: use core helper to get driver data
  i2c: exynos5: de-duplicate error logs on clock setup
  i2c: exynos5: simplify clock frequency handling
  i2c: exynos5: simplify timings calculation
  i2c: designware-baytrail: fix potential null pointer dereference on dev
  i2c: designware: Get selected speed mode sda-hold-time via ACPI
  [media] cx231xx: stop double error reporting
  i2c: core: Allow drivers to disable i2c-core irq mapping
  i2c: core: Add new i2c_acpi_new_device helper function
  i2c: core: Allow getting ACPI info by index
  i2c: img-scb: use setup_timer
  i2c: i2c-scmi: add a MS HID
  i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
  dt-bindings: i2c: mux: ltc4306: Add dt-bindings for I2C multiplexer/switch
  i2c: mux: reg: stop double error reporting
  i2c: mux: pinctrl: stop double error reporting
  ...
This commit is contained in:
Linus Torvalds 2017-05-03 12:18:47 -07:00
commit 14b730723a
31 changed files with 674 additions and 259 deletions

View File

@ -8,6 +8,8 @@ Required properties:
- #address-cells: should be <1>
- #size-cells: should be <0>
For details regarding the following core I2C bindings see also i2c.txt.
Optional properties:
- clock-frequency: the desired I2C bus clock frequency in Hz; in
absence of this property the default value is used (100 kHz).

View File

@ -0,0 +1,61 @@
* Linear Technology / Analog Devices I2C bus switch
Required Properties:
- compatible: Must contain one of the following.
"lltc,ltc4305", "lltc,ltc4306"
- reg: The I2C address of the device.
The following required properties are defined externally:
- Standard I2C mux properties. See i2c-mux.txt in this directory.
- I2C child bus nodes. See i2c-mux.txt in this directory.
Optional Properties:
- enable-gpios: Reference to the GPIO connected to the enable input.
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
children in idle state. This is necessary for example, if there are several
multiplexers on the bus and the devices behind them use same I2C addresses.
- gpio-controller: Marks the device node as a GPIO Controller.
- #gpio-cells: Should be two. The first cell is the pin number and
the second cell is used to specify flags.
See ../gpio/gpio.txt for more information.
- ltc,downstream-accelerators-enable: Enables the rise time accelerators
on the downstream port.
- ltc,upstream-accelerators-enable: Enables the rise time accelerators
on the upstream port.
Example:
ltc4306: i2c-mux@4a {
compatible = "lltc,ltc4306";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x4a>;
gpio-controller;
#gpio-cells = <2>;
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
eeprom@50 {
compatible = "at,24c02";
reg = <0x50>;
};
};
i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
eeprom@50 {
compatible = "at,24c02";
reg = <0x50>;
};
};
};

View File

@ -11,6 +11,7 @@ Required properties :
- "rockchip,rk3188-i2c": for rk3188
- "rockchip,rk3228-i2c": for rk3228
- "rockchip,rk3288-i2c": for rk3288
- "rockchip,rk3328-i2c", "rockchip,rk3399-i2c": for rk3328
- "rockchip,rk3399-i2c": for rk3399
- interrupts : interrupt number
- clocks: See ../clock/clock-bindings.txt

View File

@ -7775,6 +7775,14 @@ S: Maintained
F: Documentation/hwmon/ltc4261
F: drivers/hwmon/ltc4261.c
LTC4306 I2C MULTIPLEXER DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
L: linux-i2c@vger.kernel.org
S: Supported
F: drivers/i2c/muxes/i2c-mux-ltc4306.c
F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
LTP (Linux Test Project)
M: Mike Frysinger <vapier@gentoo.org>
M: Cyril Hrubis <chrubis@suse.cz>

View File

@ -933,6 +933,7 @@ config I2C_TEGRA
config I2C_TEGRA_BPMP
tristate "NVIDIA Tegra BPMP I2C controller"
depends on TEGRA_BPMP
default y
help
If you say yes to this option, support will be included for the I2C
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
@ -1021,7 +1022,7 @@ config I2C_XLR
config I2C_XLP9XX
tristate "XLP9XX I2C support"
depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
help
This driver enables support for the on-chip I2C interface of
the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors.

View File

@ -22,7 +22,7 @@
#include "i2c-designware-core.h"
#define SEMAPHORE_TIMEOUT 100
#define SEMAPHORE_TIMEOUT 500
#define PUNIT_SEMAPHORE 0x7
#define PUNIT_SEMAPHORE_CHT 0x10e
#define PUNIT_SEMAPHORE_BIT BIT(0)
@ -70,7 +70,7 @@ static void reset_semaphore(struct dw_i2c_dev *dev)
static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
{
u32 addr = get_sem_addr(dev);
u32 addr;
u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
int ret;
unsigned long start, end;
@ -94,6 +94,8 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
*/
pm_qos_update_request(&dev->pm_qos, 0);
addr = get_sem_addr(dev);
/* host driver writes to side band semaphore register */
ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
if (ret) {
@ -170,7 +172,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
dev->acquire_lock = baytrail_i2c_acquire;
dev->release_lock = baytrail_i2c_release;
dev->pm_runtime_disabled = true;
dev->pm_disabled = true;
pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);

View File

@ -960,6 +960,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
unsigned long irq_flags;
int r;
init_completion(&dev->cmd_complete);
@ -975,9 +976,15 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) {
dev_pm_syscore_device(dev->dev, true);
irq_flags = IRQF_NO_SUSPEND;
} else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
}
i2c_dw_disable_int(dev);
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
IRQF_SHARED | IRQF_COND_SUSPEND,
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
dev_name(dev->dev), dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",

View File

@ -79,7 +79,7 @@
* @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @pm_runtime_disabled: true if pm runtime is disabled
* @pm_disabled: true if power-management should be disabled for this i2c-bus
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@ -128,7 +128,7 @@ struct dw_i2c_dev {
struct pm_qos_request pm_qos;
int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev);
bool pm_runtime_disabled;
bool pm_disabled;
};
#define ACCESS_SWAP 0x00000001

View File

@ -85,8 +85,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
*hcnt = (u16)objs[0].integer.value;
*lcnt = (u16)objs[1].integer.value;
if (sda_hold)
*sda_hold = (u32)objs[2].integer.value;
*sda_hold = (u32)objs[2].integer.value;
}
kfree(buf.pointer);
@ -95,26 +94,55 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
const struct acpi_device_id *id;
struct acpi_device *adev;
const char *uid;
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
dev->rx_fifo_depth = 32;
/*
* Try to get SDA hold time and *CNT values from an ACPI method if
* it exists for both supported speed modes.
* Try to get SDA hold time and *CNT values from an ACPI method for
* selected speed modes.
*/
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL);
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL);
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL);
switch (dev->clk_freq) {
case 100000:
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt,
&dev->sda_hold_time);
break;
case 1000000:
dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt,
&dev->sda_hold_time);
break;
case 3400000:
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt,
&dev->sda_hold_time);
break;
case 400000:
default:
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
break;
}
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
dev->flags |= (u32)id->driver_data;
if (acpi_bus_get_device(handle, &adev))
return -ENODEV;
/*
* Cherrytrail I2C7 gets used for the PMIC which gets accessed
* through ACPI opregions during late suspend / early resume
* disable pm for it.
*/
uid = adev->pnp.unique_id;
if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
dev->pm_disabled = true;
return 0;
}
@ -286,7 +314,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
if (dev->pm_runtime_disabled) {
if (dev->pm_disabled) {
pm_runtime_forbid(&pdev->dev);
} else {
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
@ -302,7 +330,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
return r;
exit_probe:
if (!dev->pm_runtime_disabled)
if (!dev->pm_disabled)
pm_runtime_disable(&pdev->dev);
exit_reset:
if (!IS_ERR_OR_NULL(dev->rst))
@ -322,7 +350,7 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
if (!dev->pm_runtime_disabled)
if (!dev->pm_disabled)
pm_runtime_disable(&pdev->dev);
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
@ -374,9 +402,7 @@ static int dw_i2c_plat_resume(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
i2c_dw_plat_prepare_clk(i_dev, true);
if (!i_dev->pm_runtime_disabled)
i2c_dw_init(i_dev);
i2c_dw_init(i_dev);
return 0;
}

View File

@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
@ -168,8 +169,6 @@
*/
#define HSI2C_HS_TX_CLOCK 1000000
#define HSI2C_FS_TX_CLOCK 100000
#define HSI2C_HIGH_SPD 1
#define HSI2C_FAST_SPD 0
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
@ -200,18 +199,10 @@ struct exynos5_i2c {
int trans_done;
/* Controller operating frequency */
unsigned int fs_clock;
unsigned int hs_clock;
/*
* HSI2C Controller can operate in
* 1. High speed upto 3.4Mbps
* 2. Fast speed upto 1Mbps
*/
int speed_mode;
unsigned int op_clock;
/* Version of HS-I2C Hardware */
struct exynos_hsi2c_variant *variant;
const struct exynos_hsi2c_variant *variant;
};
/**
@ -257,15 +248,6 @@ static const struct of_device_id exynos5_i2c_match[] = {
};
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant
(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos5_i2c_match, pdev->dev.of_node);
return (struct exynos_hsi2c_variant *)match->data;
}
static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
{
writel(readl(i2c->regs + HSI2C_INT_STATUS),
@ -279,7 +261,7 @@ static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
* Returns 0 on success, -EINVAL if the cycle length cannot
* be calculated.
*/
static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
{
u32 i2c_timing_s1;
u32 i2c_timing_s2;
@ -292,9 +274,10 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
unsigned int t_sr_release;
unsigned int t_ftl_cycle;
unsigned int clkin = clk_get_rate(i2c->clk);
unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle;
unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ?
i2c->hs_clock : i2c->fs_clock;
unsigned int op_clk = hs_timings ? i2c->op_clock :
(i2c->op_clock >= HSI2C_HS_TX_CLOCK) ? HSI2C_FS_TX_CLOCK :
i2c->op_clock;
int div, clk_cycle, temp;
/*
* In case of HSI2C controller in Exynos5 series
@ -305,33 +288,22 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE
*
* utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* utemp1 = (TSCLK_L + TSCLK_H + 2)
* clk_cycle := TSCLK_L + TSCLK_H
* temp := (CLK_DIV + 1) * (clk_cycle + 2)
*
* Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510
*
*/
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8;
if (i2c->variant->hw == HSI2C_EXYNOS7)
utemp0 -= t_ftl_cycle;
else
utemp0 -= 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (div = 0; div < 256; div++) {
utemp1 = utemp0 / (div + 1);
/*
* SCL_L and SCL_H each has max value of 255
* Hence, For the clk_cycle to the have right value
* utemp1 has to be less then 512 and more than 4.
*/
if ((utemp1 < 512) && (utemp1 > 4)) {
clk_cycle = utemp1 - 2;
break;
} else if (div == 255) {
dev_warn(i2c->dev, "Failed to calculate divisor");
return -EINVAL;
}
temp = clkin / op_clk - 8 - t_ftl_cycle;
if (i2c->variant->hw != HSI2C_EXYNOS7)
temp -= t_ftl_cycle;
div = temp / 512;
clk_cycle = temp / (div + 1) - 2;
if (temp < 4 || div >= 256 || clk_cycle < 2) {
dev_err(i2c->dev, "%s clock set-up failed\n",
hs_timings ? "HS" : "FS");
return -EINVAL;
}
t_scl_l = clk_cycle / 2;
@ -356,7 +328,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
div, t_sr_release);
dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd);
if (mode == HSI2C_HIGH_SPD) {
if (hs_timings) {
writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1);
writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2);
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3);
@ -372,24 +344,13 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c)
{
/*
* Configure the Fast speed timing values
* Even the High Speed mode initially starts with Fast mode
*/
if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) {
dev_err(i2c->dev, "HSI2C FS Clock set up failed\n");
return -EINVAL;
}
/* always set Fast Speed timings */
int ret = exynos5_i2c_set_timing(i2c, false);
/* configure the High speed timing values */
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) {
dev_err(i2c->dev, "HSI2C HS Clock set up failed\n");
return -EINVAL;
}
}
if (ret < 0 || i2c->op_clock < HSI2C_HS_TX_CLOCK)
return ret;
return 0;
return exynos5_i2c_set_timing(i2c, true);
}
/*
@ -409,7 +370,7 @@ static void exynos5_i2c_init(struct exynos5_i2c *i2c)
i2c->regs + HSI2C_CTL);
writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL);
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) {
writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)),
i2c->regs + HSI2C_ADDR);
i2c_conf |= HSI2C_HS_MODE;
@ -747,26 +708,14 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct exynos5_i2c *i2c;
struct resource *mem;
unsigned int op_clock;
int ret;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
if (of_property_read_u32(np, "clock-frequency", &op_clock)) {
i2c->speed_mode = HSI2C_FAST_SPD;
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
} else {
if (op_clock >= HSI2C_HS_TX_CLOCK) {
i2c->speed_mode = HSI2C_HIGH_SPD;
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
i2c->hs_clock = op_clock;
} else {
i2c->speed_mode = HSI2C_FAST_SPD;
i2c->fs_clock = op_clock;
}
}
if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock))
i2c->op_clock = HSI2C_FS_TX_CLOCK;
strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
@ -817,8 +766,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
goto err_clk;
}
/* Need to check the variant before setting up. */
i2c->variant = exynos5_i2c_get_variant(pdev);
i2c->variant = of_device_get_match_data(&pdev->dev);
ret = exynos5_hsi2c_clock_setup(i2c);
if (ret)

View File

@ -1362,9 +1362,8 @@ static int img_i2c_probe(struct platform_device *pdev)
}
/* Set up the exception check timer */
init_timer(&i2c->check_timer);
i2c->check_timer.function = img_i2c_check_timer;
i2c->check_timer.data = (unsigned long)i2c;
setup_timer(&i2c->check_timer, img_i2c_check_timer,
(unsigned long)i2c);
i2c->bitrate = timings[0].max_bitrate;
if (!of_property_read_u32(node, "clock-frequency", &val))

View File

@ -35,10 +35,11 @@
#define REG_CTRL_STATUS BIT(2)
#define REG_CTRL_ERROR BIT(3)
#define REG_CTRL_CLKDIV_SHIFT 12
#define REG_CTRL_CLKDIV_MASK ((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT)
#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT_SHIFT 28
#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
#define I2C_TIMEOUT_MS 500
#define DEFAULT_FREQ 100000
enum {
TOKEN_END = 0,
@ -54,7 +55,6 @@ enum {
STATE_IDLE,
STATE_READ,
STATE_WRITE,
STATE_STOP,
};
/**
@ -73,7 +73,6 @@ enum {
* @error: Flag set when an error is received
* @lock: To avoid race conditions between irq handler and xfer code
* @done: Completion used to wait for transfer termination
* @frequency: Operating frequency of I2C bus clock
* @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens
*/
@ -82,7 +81,6 @@ struct meson_i2c {
struct device *dev;
void __iomem *regs;
struct clk *clk;
int irq;
struct i2c_msg *msg;
int state;
@ -93,7 +91,6 @@ struct meson_i2c {
spinlock_t lock;
struct completion done;
unsigned int frequency;
u32 tokens[2];
int num_tokens;
};
@ -126,23 +123,27 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
i2c->num_tokens++;
}
static void meson_i2c_write_tokens(struct meson_i2c *i2c)
{
writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0);
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
}
static void meson_i2c_set_clk_div(struct meson_i2c *i2c)
static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
{
unsigned long clk_rate = clk_get_rate(i2c->clk);
unsigned int div;
div = DIV_ROUND_UP(clk_rate, i2c->frequency * 4);
div = DIV_ROUND_UP(clk_rate, freq * 4);
/* clock divider has 12 bits */
if (div >= (1 << 12)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div = (1 << 12) - 1;
}
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
div << REG_CTRL_CLKDIV_SHIFT);
(div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
clk_rate, i2c->frequency, div);
clk_rate, freq, div);
}
static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len)
@ -156,10 +157,10 @@ static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len)
dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__,
rdata0, rdata1, len);
for (i = 0; i < min_t(int, 4, len); i++)
for (i = 0; i < min(4, len); i++)
*buf++ = (rdata0 >> i * 8) & 0xff;
for (i = 4; i < min_t(int, 8, len); i++)
for (i = 4; i < min(8, len); i++)
*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
}
@ -168,10 +169,10 @@ static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len)
u32 wdata0 = 0, wdata1 = 0;
int i;
for (i = 0; i < min_t(int, 4, len); i++)
for (i = 0; i < min(4, len); i++)
wdata0 |= *buf++ << (i * 8);
for (i = 4; i < min_t(int, 8, len); i++)
for (i = 4; i < min(8, len); i++)
wdata1 |= *buf++ << ((i - 4) * 8);
writel(wdata0, i2c->regs + REG_TOK_WDATA0);
@ -186,7 +187,7 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
bool write = !(i2c->msg->flags & I2C_M_RD);
int i;
i2c->count = min_t(int, i2c->msg->len - i2c->pos, 8);
i2c->count = min(i2c->msg->len - i2c->pos, 8);
for (i = 0; i < i2c->count - 1; i++)
meson_i2c_add_token(i2c, TOKEN_DATA);
@ -200,19 +201,12 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
if (write)
meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
}
static void meson_i2c_stop(struct meson_i2c *i2c)
{
dev_dbg(i2c->dev, "%s: last %d\n", __func__, i2c->last);
if (i2c->last) {
i2c->state = STATE_STOP;
if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
meson_i2c_add_token(i2c, TOKEN_STOP);
} else {
i2c->state = STATE_IDLE;
complete(&i2c->done);
}
writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0);
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
}
static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
@ -223,12 +217,18 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
spin_lock(&i2c->lock);
meson_i2c_reset_tokens(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
ctrl = readl(i2c->regs + REG_CTRL);
dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n",
i2c->state, i2c->pos, i2c->count, ctrl);
if (ctrl & REG_CTRL_ERROR && i2c->state != STATE_IDLE) {
if (i2c->state == STATE_IDLE) {
spin_unlock(&i2c->lock);
return IRQ_NONE;
}
if (ctrl & REG_CTRL_ERROR) {
/*
* The bit is set when the IGNORE_NAK bit is cleared
* and the device didn't respond. In this case, the
@ -242,48 +242,21 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
goto out;
}
switch (i2c->state) {
case STATE_READ:
if (i2c->count > 0) {
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
i2c->count);
i2c->pos += i2c->count;
}
if (i2c->state == STATE_READ && i2c->count)
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
if (i2c->pos >= i2c->msg->len) {
meson_i2c_stop(i2c);
break;
}
i2c->pos += i2c->count;
meson_i2c_prepare_xfer(i2c);
break;
case STATE_WRITE:
i2c->pos += i2c->count;
if (i2c->pos >= i2c->msg->len) {
meson_i2c_stop(i2c);
break;
}
meson_i2c_prepare_xfer(i2c);
break;
case STATE_STOP:
if (i2c->pos >= i2c->msg->len) {
i2c->state = STATE_IDLE;
complete(&i2c->done);
break;
case STATE_IDLE:
break;
goto out;
}
/* Restart the processing */
meson_i2c_prepare_xfer(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
out:
if (i2c->state != STATE_IDLE) {
/* Restart the processing */
meson_i2c_write_tokens(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START,
REG_CTRL_START);
}
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
@ -323,7 +296,6 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
meson_i2c_prepare_xfer(i2c);
meson_i2c_write_tokens(i2c);
reinit_completion(&i2c->done);
/* Start the transfer */
@ -359,21 +331,19 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct meson_i2c *i2c = adap->algo_data;
int i, ret = 0, count = 0;
int i, ret = 0;
clk_enable(i2c->clk);
meson_i2c_set_clk_div(i2c);
for (i = 0; i < num; i++) {
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1);
if (ret)
break;
count++;
}
clk_disable(i2c->clk);
return ret ? ret : count;
return ret ?: i;
}
static u32 meson_i2c_func(struct i2c_adapter *adap)
@ -391,15 +361,14 @@ static int meson_i2c_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct meson_i2c *i2c;
struct resource *mem;
int ret = 0;
struct i2c_timings timings;
int irq, ret = 0;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&i2c->frequency))
i2c->frequency = DEFAULT_FREQ;
i2c_parse_fw_timings(&pdev->dev, &timings, true);
i2c->dev = &pdev->dev;
platform_set_drvdata(pdev, i2c);
@ -418,14 +387,13 @@ static int meson_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->regs))
return PTR_ERR(i2c->regs);
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0) {
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "can't find IRQ\n");
return i2c->irq;
return irq;
}
ret = devm_request_irq(&pdev->dev, i2c->irq, meson_i2c_irq,
0, dev_name(&pdev->dev), i2c);
ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c);
if (ret < 0) {
dev_err(&pdev->dev, "can't request IRQ\n");
return ret;
@ -457,6 +425,8 @@ static int meson_i2c_probe(struct platform_device *pdev)
return ret;
}
meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
return 0;
}

View File

@ -823,13 +823,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
if (IS_ERR(drv_data->rstc)) {
if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) {
rc = -EPROBE_DEFER;
goto out;
}
} else {
reset_control_deassert(drv_data->rstc);
rc = PTR_ERR(drv_data->rstc);
goto out;
}
reset_control_deassert(drv_data->rstc);
/* Its not yet defined how timeouts will be specified in device tree.
* So hard code the value to 1 second.
@ -951,8 +948,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_free_irq:
free_irq(drv_data->irq, drv_data);
exit_reset:
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
reset_control_assert(drv_data->rstc);
exit_clk:
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
@ -968,8 +964,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
reset_control_assert(drv_data->rstc);
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);

View File

@ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
pm_runtime_get_sync(dev);
rcar_i2c_init(priv);
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;
@ -751,6 +753,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
/* Keep device active for slave address detection logic */
pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
priv->slave = slave;
@ -854,15 +857,14 @@ static int rcar_i2c_probe(struct platform_device *pdev)
priv->dma_direction = DMA_NONE;
priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* Activate device for clock calculation */
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = rcar_i2c_clock_calculate(priv, &i2c_t);
if (ret < 0)
goto out_pm_put;
rcar_i2c_init(priv);
/* Don't suspend when multi-master to keep arbitration working */
/* Stay always active when multi-master to keep arbitration working */
if (of_property_read_bool(dev->of_node, "multi-master"))
priv->flags |= ID_P_PM_BLOCKED;
else

View File

@ -18,6 +18,9 @@
#define ACPI_SMBUS_HC_CLASS "smbus"
#define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
/* SMBUS HID definition as supported by Microsoft Windows */
#define ACPI_SMBUS_MS_HID "SMB0001"
ACPI_MODULE_NAME("smbus_cmi");
struct smbus_methods_t {
@ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = {
static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
{"SMBUS01", (kernel_ulong_t)&smbus_methods},
{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
{ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
{"", 0}
};
MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);

View File

@ -340,7 +340,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = {
};
module_platform_driver(tegra_bpmp_i2c_driver);
MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver");
MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus controller driver");
MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>");
MODULE_AUTHOR("Juha-Matti Tilli");
MODULE_LICENSE("GPL v2");

View File

@ -85,16 +85,22 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
{
int ret;
i2c->clk = clk_get(dev, NULL);
if (IS_ERR(i2c->clk)) {
i2c->clk = NULL;
goto skip;
}
if (acpi_disabled) {
/* DT */
i2c->clk = clk_get(dev, NULL);
if (IS_ERR(i2c->clk)) {
i2c->clk = NULL;
goto skip;
}
ret = clk_prepare_enable(i2c->clk);
if (ret)
goto skip;
i2c->sys_freq = clk_get_rate(i2c->clk);
ret = clk_prepare_enable(i2c->clk);
if (ret)
goto skip;
i2c->sys_freq = clk_get_rate(i2c->clk);
} else {
/* ACPI */
device_property_read_u32(dev, "sclk", &i2c->sys_freq);
}
skip:
if (!i2c->sys_freq)
@ -205,6 +211,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
i2c->adap = thunderx_i2c_ops;
i2c->adap.retries = 5;
i2c->adap.class = I2C_CLASS_HWMON;
i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
i2c->adap.dev.parent = dev;
i2c->adap.dev.of_node = pdev->dev.of_node;

View File

@ -432,6 +432,7 @@ MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
{"BRCM9007", 0},
{"CAV9007", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids);

View File

@ -112,6 +112,8 @@ struct i2c_acpi_lookup {
acpi_handle adapter_handle;
acpi_handle device_handle;
acpi_handle search_handle;
int n;
int index;
u32 speed;
u32 min_speed;
};
@ -130,6 +132,9 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
return 1;
if (lookup->index != -1 && lookup->n++ != lookup->index)
return 1;
status = acpi_get_handle(lookup->device_handle,
sb->resource_source.string_ptr,
&lookup->adapter_handle);
@ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
memset(&lookup, 0, sizeof(lookup));
lookup.info = info;
lookup.index = -1;
ret = i2c_acpi_do_lookup(adev, &lookup);
if (ret)
@ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
lookup.search_handle = ACPI_HANDLE(dev);
lookup.min_speed = UINT_MAX;
lookup.info = &dummy;
lookup.index = -1;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
I2C_ACPI_MAX_SCAN_DEPTH,
@ -414,6 +421,55 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
static struct notifier_block i2c_acpi_notifier = {
.notifier_call = i2c_acpi_notify,
};
/**
* i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource
* @dev: Device owning the ACPI resources to get the client from
* @index: Index of ACPI resource to get
* @info: describes the I2C device; note this is modified (addr gets set)
* Context: can sleep
*
* By default the i2c subsys creates an i2c-client for the first I2cSerialBus
* resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus
* resources, in that case this function can be used to create an i2c-client
* for other I2cSerialBus resources in the Current Resource Settings table.
*
* Also see i2c_new_device, which this function calls to create the i2c-client.
*
* Returns a pointer to the new i2c-client, or NULL if the adapter is not found.
*/
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
struct i2c_board_info *info)
{
struct i2c_acpi_lookup lookup;
struct i2c_adapter *adapter;
struct acpi_device *adev;
LIST_HEAD(resource_list);
int ret;
adev = ACPI_COMPANION(dev);
if (!adev)
return NULL;
memset(&lookup, 0, sizeof(lookup));
lookup.info = info;
lookup.device_handle = acpi_device_handle(adev);
lookup.index = index;
ret = acpi_dev_get_resources(adev, &resource_list,
i2c_acpi_fill_info, &lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info->addr)
return NULL;
adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
if (!adapter)
return NULL;
return i2c_new_device(adapter, info);
}
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
#else /* CONFIG_ACPI */
static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
extern struct notifier_block i2c_acpi_notifier;
@ -929,7 +985,9 @@ static int i2c_device_probe(struct device *dev)
if (!client)
return 0;
if (!client->irq) {
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) {
@ -951,8 +1009,6 @@ static int i2c_device_probe(struct device *dev)
client->irq = irq;
}
driver = to_i2c_driver(dev->driver);
/*
* An I2C ID table is not mandatory, if and only if, a suitable Device
* Tree match table entry is supplied for the probing device.

View File

@ -395,13 +395,16 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(&priv->adap);
dev_err(&parent->dev,
"failed to add mux-adapter %u as bus %u (error=%d)\n",
chan_id, force_nr, ret);
} else {
ret = i2c_add_adapter(&priv->adap);
dev_err(&parent->dev,
"failed to add mux-adapter %u (error=%d)\n",
chan_id, ret);
}
if (ret < 0) {
dev_err(&parent->dev,
"failed to add mux-adapter (error=%d)\n",
ret);
kfree(priv);
return ret;
}

View File

@ -30,6 +30,17 @@ config I2C_MUX_GPIO
This driver can also be built as a module. If so, the module
will be called i2c-mux-gpio.
config I2C_MUX_LTC4306
tristate "LTC LTC4306/5 I2C multiplexer"
select GPIOLIB
select REGMAP_I2C
help
If you say yes here you get support for the Analog Devices
LTC4306 or LTC4305 I2C mux/switch devices.
This driver can also be built as a module. If so, the module
will be called i2c-mux-ltc4306.
config I2C_MUX_PCA9541
tristate "NXP PCA9541 I2C Master Selector"
help

View File

@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o

View File

@ -202,10 +202,8 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
/* Actually add the mux adapter */
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
if (ret) {
dev_err(dev, "Failed to add adapter\n");
if (ret)
i2c_put_adapter(muxc->parent);
}
return ret;
}

View File

@ -245,10 +245,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
if (ret)
goto add_adapter_failed;
}
}
dev_info(&pdev->dev, "%d port mux on %s adapter\n",

View File

@ -0,0 +1,322 @@
/*
* Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch
*
* Copyright (C) 2017 Analog Devices Inc.
*
* Licensed under the GPL-2.
*
* Based on: i2c-mux-pca954x.c
*
* Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf
*/
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/i2c-mux.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define LTC4305_MAX_NCHANS 2
#define LTC4306_MAX_NCHANS 4
#define LTC_REG_STATUS 0x0
#define LTC_REG_CONFIG 0x1
#define LTC_REG_MODE 0x2
#define LTC_REG_SWITCH 0x3
#define LTC_DOWNSTREAM_ACCL_EN BIT(6)
#define LTC_UPSTREAM_ACCL_EN BIT(7)
#define LTC_GPIO_ALL_INPUT 0xC0
#define LTC_SWITCH_MASK 0xF0
enum ltc_type {
ltc_4305,
ltc_4306,
};
struct chip_desc {
u8 nchans;
u8 num_gpios;
};
struct ltc4306 {
struct regmap *regmap;
struct gpio_chip gpiochip;
const struct chip_desc *chip;
};
static const struct chip_desc chips[] = {
[ltc_4305] = {
.nchans = LTC4305_MAX_NCHANS,
},
[ltc_4306] = {
.nchans = LTC4306_MAX_NCHANS,
.num_gpios = 2,
},
};
static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg)
{
return (reg == LTC_REG_CONFIG) ? true : false;
}
static const struct regmap_config ltc4306_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LTC_REG_SWITCH,
.volatile_reg = ltc4306_is_volatile_reg,
.cache_type = REGCACHE_FLAT,
};
static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct ltc4306 *data = gpiochip_get_data(chip);
unsigned int val;
int ret;
ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val);
if (ret < 0)
return ret;
return !!(val & BIT(1 - offset));
}
static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct ltc4306 *data = gpiochip_get_data(chip);
regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset),
value ? BIT(5 - offset) : 0);
}
static int ltc4306_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct ltc4306 *data = gpiochip_get_data(chip);
unsigned int val;
int ret;
ret = regmap_read(data->regmap, LTC_REG_MODE, &val);
if (ret < 0)
return ret;
return !!(val & BIT(7 - offset));
}
static int ltc4306_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct ltc4306 *data = gpiochip_get_data(chip);
return regmap_update_bits(data->regmap, LTC_REG_MODE,
BIT(7 - offset), BIT(7 - offset));
}
static int ltc4306_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct ltc4306 *data = gpiochip_get_data(chip);
ltc4306_gpio_set(chip, offset, value);
return regmap_update_bits(data->regmap, LTC_REG_MODE,
BIT(7 - offset), 0);
}
static int ltc4306_gpio_set_config(struct gpio_chip *chip,
unsigned int offset, unsigned long config)
{
struct ltc4306 *data = gpiochip_get_data(chip);
unsigned int val;
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
val = 0;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
val = BIT(4 - offset);
break;
default:
return -ENOTSUPP;
}
return regmap_update_bits(data->regmap, LTC_REG_MODE,
BIT(4 - offset), val);
}
static int ltc4306_gpio_init(struct ltc4306 *data)
{
struct device *dev = regmap_get_device(data->regmap);
if (!data->chip->num_gpios)
return 0;
data->gpiochip.label = dev_name(dev);
data->gpiochip.base = -1;
data->gpiochip.ngpio = data->chip->num_gpios;
data->gpiochip.parent = dev;
data->gpiochip.can_sleep = true;
data->gpiochip.get_direction = ltc4306_gpio_get_direction;
data->gpiochip.direction_input = ltc4306_gpio_direction_input;
data->gpiochip.direction_output = ltc4306_gpio_direction_output;
data->gpiochip.get = ltc4306_gpio_get;
data->gpiochip.set = ltc4306_gpio_set;
data->gpiochip.set_config = ltc4306_gpio_set_config;
data->gpiochip.owner = THIS_MODULE;
/* gpiolib assumes all GPIOs default input */
regmap_write(data->regmap, LTC_REG_MODE, LTC_GPIO_ALL_INPUT);
return devm_gpiochip_add_data(dev, &data->gpiochip, data);
}
static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan)
{
struct ltc4306 *data = i2c_mux_priv(muxc);
return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
LTC_SWITCH_MASK, BIT(7 - chan));
}
static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
{
struct ltc4306 *data = i2c_mux_priv(muxc);
return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
LTC_SWITCH_MASK, 0);
}
static const struct i2c_device_id ltc4306_id[] = {
{ "ltc4305", ltc_4305 },
{ "ltc4306", ltc_4306 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4306_id);
static const struct of_device_id ltc4306_of_match[] = {
{ .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] },
{ .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] },
{ }
};
MODULE_DEVICE_TABLE(of, ltc4306_of_match);
static int ltc4306_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
const struct chip_desc *chip;
struct i2c_mux_core *muxc;
struct ltc4306 *data;
struct gpio_desc *gpio;
bool idle_disc;
unsigned int val = 0;
int num, ret;
chip = of_device_get_match_data(&client->dev);
if (!chip)
chip = &chips[id->driver_data];
idle_disc = device_property_read_bool(&client->dev,
"i2c-mux-idle-disconnect");
muxc = i2c_mux_alloc(adap, &client->dev,
chip->nchans, sizeof(*data),
I2C_MUX_LOCKED, ltc4306_select_mux,
idle_disc ? ltc4306_deselect_mux : NULL);
if (!muxc)
return -ENOMEM;
data = i2c_mux_priv(muxc);
data->chip = chip;
i2c_set_clientdata(client, muxc);
data->regmap = devm_regmap_init_i2c(client, &ltc4306_regmap_config);
if (IS_ERR(data->regmap)) {
ret = PTR_ERR(data->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
/* Reset and enable the mux if an enable GPIO is specified. */
gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
udelay(1);
gpiod_set_value(gpio, 1);
}
/*
* Write the mux register at addr to verify
* that the mux is in fact present. This also
* initializes the mux to disconnected state.
*/
if (regmap_write(data->regmap, LTC_REG_SWITCH, 0) < 0) {
dev_warn(&client->dev, "probe failed\n");
return -ENODEV;
}
if (device_property_read_bool(&client->dev,
"ltc,downstream-accelerators-enable"))
val |= LTC_DOWNSTREAM_ACCL_EN;
if (device_property_read_bool(&client->dev,
"ltc,upstream-accelerators-enable"))
val |= LTC_UPSTREAM_ACCL_EN;
if (regmap_write(data->regmap, LTC_REG_CONFIG, val) < 0)
return -ENODEV;
ret = ltc4306_gpio_init(data);
if (ret < 0)
return ret;
/* Now create an adapter for each channel */
for (num = 0; num < chip->nchans; num++) {
ret = i2c_mux_add_adapter(muxc, 0, num, 0);
if (ret) {
i2c_mux_del_adapters(muxc);
return ret;
}
}
dev_info(&client->dev,
"registered %d multiplexed busses for I2C switch %s\n",
num, client->name);
return 0;
}
static int ltc4306_remove(struct i2c_client *client)
{
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
i2c_mux_del_adapters(muxc);
return 0;
}
static struct i2c_driver ltc4306_driver = {
.driver = {
.name = "ltc4306",
.of_match_table = of_match_ptr(ltc4306_of_match),
},
.probe = ltc4306_probe,
.remove = ltc4306_remove,
.id_table = ltc4306_id,
};
module_i2c_driver(ltc4306_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver");
MODULE_LICENSE("GPL v2");

View File

@ -369,10 +369,8 @@ static int pca9541_probe(struct i2c_client *client,
i2c_set_clientdata(client, muxc);
ret = i2c_mux_add_adapter(muxc, force, 0, 0);
if (ret) {
dev_err(&client->dev, "failed to register master selector\n");
if (ret)
return ret;
}
dev_info(&client->dev, "registered master selector for I2C %s\n",
client->name);

View File

@ -84,7 +84,7 @@ struct pca954x {
struct irq_domain *irq;
unsigned int irq_mask;
spinlock_t lock;
raw_spinlock_t lock;
};
/* Provide specs for the PCA954x types we know about */
@ -252,13 +252,13 @@ static void pca954x_irq_mask(struct irq_data *idata)
unsigned int pos = idata->hwirq;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
raw_spin_lock_irqsave(&data->lock, flags);
data->irq_mask &= ~BIT(pos);
if (!data->irq_mask)
disable_irq(data->client->irq);
spin_unlock_irqrestore(&data->lock, flags);
raw_spin_unlock_irqrestore(&data->lock, flags);
}
static void pca954x_irq_unmask(struct irq_data *idata)
@ -267,13 +267,13 @@ static void pca954x_irq_unmask(struct irq_data *idata)
unsigned int pos = idata->hwirq;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
raw_spin_lock_irqsave(&data->lock, flags);
if (!data->irq_mask)
enable_irq(data->client->irq);
data->irq_mask |= BIT(pos);
spin_unlock_irqrestore(&data->lock, flags);
raw_spin_unlock_irqrestore(&data->lock, flags);
}
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
@ -299,7 +299,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
if (!data->chip->has_irq || client->irq <= 0)
return 0;
spin_lock_init(&data->lock);
raw_spin_lock_init(&data->lock);
data->irq = irq_domain_add_linear(client->dev.of_node,
data->chip->nchans,
@ -413,13 +413,8 @@ static int pca954x_probe(struct i2c_client *client,
idle_disconnect_dt) << num;
ret = i2c_mux_add_adapter(muxc, force, num, class);
if (ret) {
dev_err(&client->dev,
"failed to register multiplexed adapter"
" %d as bus %d\n", num, force);
if (ret)
goto fail_del_adapters;
}
}
dev_info(&client->dev,

View File

@ -245,10 +245,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
(mux->pdata->base_bus_num + i) : 0;
ret = i2c_mux_add_adapter(muxc, bus, i, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
if (ret)
goto err_del_adapter;
}
}
return 0;

View File

@ -222,10 +222,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
class = mux->data.classes ? mux->data.classes[i] : 0;
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
if (ret)
goto add_adapter_failed;
}
}
dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",

View File

@ -576,17 +576,10 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
{
int rc;
rc = i2c_mux_add_adapter(dev->muxc,
0,
mux_no /* chan_id */,
0 /* class */);
if (rc)
dev_warn(dev->dev,
"i2c mux %d register FAILED\n", mux_no);
return rc;
return i2c_mux_add_adapter(dev->muxc,
0,
mux_no /* chan_id */,
0 /* class */);
}
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)

View File

@ -149,6 +149,7 @@ enum i2c_alert_protocol {
* @detect: Callback for device detection
* @address_list: The I2C addresses to probe (for detect)
* @clients: List of detected clients we created (for i2c-core use only)
* @disable_i2c_core_irq_mapping: Tell the i2c-core to not do irq-mapping
*
* The driver.owner field should be set to the module owner of this driver.
* The driver.name field should be set to the name of this driver.
@ -212,6 +213,8 @@ struct i2c_driver {
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
bool disable_i2c_core_irq_mapping;
};
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
@ -824,11 +827,18 @@ static inline const struct of_device_id
#if IS_ENABLED(CONFIG_ACPI)
u32 i2c_acpi_find_bus_speed(struct device *dev);
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
struct i2c_board_info *info);
#else
static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
{
return 0;
}
static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
int index, struct i2c_board_info *info)
{
return NULL;
}
#endif /* CONFIG_ACPI */
#endif /* _LINUX_I2C_H */