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

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

   - new flag to mark DMA safe buffers in i2c_msg. Also, some
     infrastructure around it. And docs.

   - huge refactoring of the at24 driver led by the new maintainer
     Bartosz

   - update I2C bus recovery to send STOP after recovery

   - conversion from gpio to gpiod for I2C bus recovery

   - adding a fault-injector to the i2c-gpio driver

   - lots of small driver improvements, and bigger ones to
     i2c-sh_mobile"

* 'i2c/for-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (99 commits)
  i2c: mv64xxx: Add myself as maintainer for this driver
  i2c: mv64xxx: Fix clock resource by adding an optional bus clock
  i2c: mv64xxx: Remove useless test before clk_disable_unprepare
  i2c: mxs: use true and false for boolean values
  i2c: meson: update doc description to fix build warnings
  i2c: meson: add configurable divider factors
  dt-bindings: i2c: update documentation for the Meson-AXG
  i2c: imx-lpi2c: add runtime pm support
  i2c: rcar: fix some trivial typos in comments
  i2c: davinci: fix the cpufreq transition
  i2c: rk3x: add proper kerneldoc header
  i2c: rk3x: account for const type of of_device_id.data
  i2c: acorn: remove outdated path from file header
  i2c: acorn: add MODULE_LICENSE tag
  i2c: rcar: implement bus recovery
  i2c: send STOP after successful bus recovery
  i2c: ensure SDA is released in recovery if SDA is controllable
  i2c: add 'set_sda' to bus_recovery_info
  i2c: add identifier in declarations for i2c_bus_recovery
  i2c: make kerneldoc about bus recovery more precise
  ...
This commit is contained in:
Linus Torvalds 2018-02-04 10:57:43 -08:00
commit 4141cf676b
45 changed files with 1381 additions and 1012 deletions

View file

@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (bit_adap->getscl == NULL)
adap->quirks = &i2c_bit_quirk_no_clk_stretch;
/* Bring bus to a known state. Looks like STOP if bus is not free yet */
setscl(bit_adap, 1);
udelay(bit_adap->udelay);
setsda(bit_adap, 1);
ret = add_adapter(adap);
if (ret < 0)
return ret;

View file

@ -603,6 +603,14 @@ config I2C_GPIO
This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines.
config I2C_GPIO_FAULT_INJECTOR
bool "GPIO-based fault injector"
depends on I2C_GPIO
help
This adds some functionality to the i2c-gpio driver which can inject
faults to an I2C bus, so another bus master can be stress-tested.
This is for debugging. If unsure, say 'no'.
config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER

View file

@ -1,5 +1,5 @@
/*
* linux/drivers/acorn/char/i2c.c
* ARM IOC/IOMD i2c driver.
*
* Copyright (C) 2000 Russell King
*
@ -7,8 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ARM IOC/IOMD i2c driver.
*
* On Acorn machines, the following i2c devices are on the bus:
* - PCF8583 real time clock & static RAM
*/
@ -94,3 +92,7 @@ static int __init i2c_ioc_init(void)
}
module_init(i2c_ioc_init);
MODULE_AUTHOR("Russell King <[email protected]>");
MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver");
MODULE_LICENSE("GPL v2");

View file

@ -33,7 +33,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include <linux/platform_data/i2c-davinci.h>
#include <linux/pm_runtime.h>
@ -139,7 +139,6 @@ struct davinci_i2c_dev {
u8 terminate;
struct i2c_adapter adapter;
#ifdef CONFIG_CPU_FREQ
struct completion xfr_complete;
struct notifier_block freq_transition;
#endif
struct davinci_i2c_platform_data *pdata;
@ -294,7 +293,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
}
/*
* This routine does i2c bus recovery by using i2c_generic_gpio_recovery
* This routine does i2c bus recovery by using i2c_generic_scl_recovery
* which is provided by I2C Bus recovery infrastructure.
*/
static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
@ -316,7 +315,7 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
}
static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
.recover_bus = i2c_generic_gpio_recovery,
.recover_bus = i2c_generic_scl_recovery,
.prepare_recovery = davinci_i2c_prepare_recovery,
.unprepare_recovery = davinci_i2c_unprepare_recovery,
};
@ -567,9 +566,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
}
ret = num;
#ifdef CONFIG_CPU_FREQ
complete(&dev->xfr_complete);
#endif
out:
pm_runtime_mark_last_busy(dev->dev);
@ -717,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
struct davinci_i2c_dev *dev;
dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
i2c_lock_adapter(&dev->adapter);
if (val == CPUFREQ_PRECHANGE) {
wait_for_completion(&dev->xfr_complete);
davinci_i2c_reset_ctrl(dev, 0);
} else if (val == CPUFREQ_POSTCHANGE) {
i2c_davinci_calc_clk_dividers(dev);
davinci_i2c_reset_ctrl(dev, 1);
}
i2c_unlock_adapter(&dev->adapter);
return 0;
}
@ -769,6 +767,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
struct davinci_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem;
struct i2c_bus_recovery_info *rinfo;
int r, irq;
irq = platform_get_irq(pdev, 0);
@ -789,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
}
init_completion(&dev->cmd_complete);
#ifdef CONFIG_CPU_FREQ
init_completion(&dev->xfr_complete);
#endif
dev->dev = &pdev->dev;
dev->irq = irq;
dev->pdata = dev_get_platdata(&pdev->dev);
@ -868,10 +865,20 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (dev->pdata->has_pfunc)
adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
else if (dev->pdata->scl_pin) {
adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info;
adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin;
adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin;
else if (dev->pdata->gpio_recovery) {
rinfo = &davinci_i2c_gpio_recovery_info;
adap->bus_recovery_info = rinfo;
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl",
GPIOD_OUT_HIGH_OPEN_DRAIN);
if (IS_ERR(rinfo->scl_gpiod)) {
r = PTR_ERR(rinfo->scl_gpiod);
goto err_unuse_clocks;
}
rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
if (IS_ERR(rinfo->sda_gpiod)) {
r = PTR_ERR(rinfo->sda_gpiod);
goto err_unuse_clocks;
}
}
adap->nr = pdev->id;

View file

@ -21,6 +21,7 @@
* ----------------------------------------------------------------------------
*
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/errno.h>
@ -185,6 +186,19 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
return dev->get_clk_rate_khz(dev);
}
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare)
{
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
if (prepare)
return clk_prepare_enable(dev->clk);
clk_disable_unprepare(dev->clk);
return 0;
}
EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
{
int ret;
@ -217,7 +231,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
if (timeout <= 0) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
return -ETIMEDOUT;
i2c_recover_bus(&dev->adapter);
if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY)
return -ETIMEDOUT;
return 0;
}
timeout--;
usleep_range(1000, 1100);

View file

@ -284,6 +284,7 @@ struct dw_i2c_dev {
void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
int mode;
struct i2c_bus_recovery_info rinfo;
};
#define ACCESS_SWAP 0x00000001
@ -299,6 +300,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable);
void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable);
unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);

View file

@ -25,11 +25,13 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include "i2c-designware-core.h"
@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */
i2c_recover_bus(&dev->adapter);
i2c_dw_init_master(dev);
ret = -ETIMEDOUT;
goto done;
@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
return IRQ_HANDLED;
}
static void i2c_dw_prepare_recovery(struct i2c_adapter *adap)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
i2c_dw_disable(dev);
reset_control_assert(dev->rst);
i2c_dw_prepare_clk(dev, false);
}
static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
i2c_dw_prepare_clk(dev, true);
reset_control_deassert(dev->rst);
i2c_dw_init_master(dev);
}
static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
{
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
struct i2c_adapter *adap = &dev->adapter;
struct gpio_desc *gpio;
int r;
gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH);
if (IS_ERR(gpio)) {
r = PTR_ERR(gpio);
if (r == -ENOENT)
return 0;
return r;
}
rinfo->scl_gpiod = gpio;
gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
rinfo->sda_gpiod = gpio;
rinfo->recover_bus = i2c_generic_scl_recovery;
rinfo->prepare_recovery = i2c_dw_prepare_recovery;
rinfo->unprepare_recovery = i2c_dw_unprepare_recovery;
adap->bus_recovery_info = rinfo;
dev_info(dev->dev, "running with gpio recovery mode! scl%s",
rinfo->sda_gpiod ? ",sda" : "");
return 0;
}
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
return ret;
}
ret = i2c_dw_init_recovery_info(dev);
if (ret)
return ret;
/*
* Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is

View file

@ -202,29 +202,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
dev->mode = DW_IC_SLAVE;
switch (dev->clk_freq) {
case 100000:
dev->slave_cfg |= DW_IC_CON_SPEED_STD;
break;
case 3400000:
dev->slave_cfg |= DW_IC_CON_SPEED_HIGH;
break;
default:
dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
}
}
static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
if (IS_ERR(i_dev->clk))
return PTR_ERR(i_dev->clk);
if (prepare)
return clk_prepare_enable(i_dev->clk);
clk_disable_unprepare(i_dev->clk);
return 0;
}
static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
@ -356,7 +333,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
i2c_dw_configure_master(dev);
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
if (!i2c_dw_prepare_clk(dev, true)) {
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (!dev->sda_hold_time && ht)
@ -472,7 +449,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i_dev->disable(i_dev);
i2c_dw_plat_prepare_clk(i_dev, false);
i2c_dw_prepare_clk(i_dev, false);
return 0;
}
@ -481,7 +458,7 @@ static int dw_i2c_plat_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i2c_dw_plat_prepare_clk(i_dev, true);
i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
return 0;

View file

@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
*/
static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
{
u32 sda_falling_time, scl_falling_time;
u32 reg, comp_param1;
u32 hcnt, lcnt;
int ret;
ret = i2c_dw_acquire_lock(dev);
@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
/* Disable the adapter. */
__i2c_dw_enable_and_wait(dev, false);
/* Set standard and fast speed deviders for high/low periods. */
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
/* Set SCL timing parameters for standard-mode. */
if (dev->ss_hcnt && dev->ss_lcnt) {
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
} else {
hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
4700, /* tLOW = 4.7 us */
scl_falling_time,
0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
/* Set SCL timing parameters for fast-mode or fast-mode plus. */
if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
hcnt = dev->fp_hcnt;
lcnt = dev->fp_lcnt;
} else if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
} else {
hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
1300, /* tLOW = 1.3 us */
scl_falling_time,
0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) ==
DW_IC_CON_SPEED_HIGH) {
if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
!= DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
dev_err(dev->dev, "High Speed not supported!\n");
dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK;
dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
} else if (dev->hs_hcnt && dev->hs_lcnt) {
hcnt = dev->hs_hcnt;
lcnt = dev->hs_lcnt;
dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
hcnt, lcnt);
}
}
/* Configure SDA Hold Time if required. */
reg = dw_readl(dev, DW_IC_COMP_VERSION);
if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {

View file

@ -170,7 +170,7 @@
#define HSI2C_HS_TX_CLOCK 1000000
#define HSI2C_FS_TX_CLOCK 100000
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100))
#define HSI2C_EXYNOS7 BIT(0)

View file

@ -7,6 +7,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-gpio.h>
@ -23,6 +25,9 @@ struct i2c_gpio_private_data {
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
struct dentry *debug_dir;
#endif
};
/*
@ -34,7 +39,7 @@ static void i2c_gpio_setsda_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
gpiod_set_value(priv->sda, state);
gpiod_set_value_cansleep(priv->sda, state);
}
/*
@ -47,23 +52,125 @@ static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
gpiod_set_value(priv->scl, state);
gpiod_set_value_cansleep(priv->scl, state);
}
static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_private_data *priv = data;
return gpiod_get_value(priv->sda);
return gpiod_get_value_cansleep(priv->sda);
}
static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_private_data *priv = data;
return gpiod_get_value(priv->scl);
return gpiod_get_value_cansleep(priv->scl);
}
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
static struct dentry *i2c_gpio_debug_dir;
#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
#define setscl(bd, val) ((bd)->setscl((bd)->data, val))
#define getsda(bd) ((bd)->getsda((bd)->data))
#define getscl(bd) ((bd)->getscl((bd)->data))
#define WIRE_ATTRIBUTE(wire) \
static int fops_##wire##_get(void *data, u64 *val) \
{ \
struct i2c_gpio_private_data *priv = data; \
\
i2c_lock_adapter(&priv->adap); \
*val = get##wire(&priv->bit_data); \
i2c_unlock_adapter(&priv->adap); \
return 0; \
} \
static int fops_##wire##_set(void *data, u64 val) \
{ \
struct i2c_gpio_private_data *priv = data; \
\
i2c_lock_adapter(&priv->adap); \
set##wire(&priv->bit_data, val); \
i2c_unlock_adapter(&priv->adap); \
return 0; \
} \
DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n")
WIRE_ATTRIBUTE(scl);
WIRE_ATTRIBUTE(sda);
static int fops_incomplete_transfer_set(void *data, u64 addr)
{
struct i2c_gpio_private_data *priv = data;
struct i2c_algo_bit_data *bit_data = &priv->bit_data;
int i, pattern;
if (addr > 0x7f)
return -EINVAL;
/* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */
pattern = (addr << 2) | 3;
i2c_lock_adapter(&priv->adap);
/* START condition */
setsda(bit_data, 0);
udelay(bit_data->udelay);
/* Send ADDR+RD, request ACK, don't send STOP */
for (i = 8; i >= 0; i--) {
setscl(bit_data, 0);
udelay(bit_data->udelay / 2);
setsda(bit_data, (pattern >> i) & 1);
udelay((bit_data->udelay + 1) / 2);
setscl(bit_data, 1);
udelay(bit_data->udelay);
}
i2c_unlock_adapter(&priv->adap);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n");
static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
/*
* If there will be a debugfs-dir per i2c adapter somewhen, put the
* 'fault-injector' dir there. Until then, we have a global dir with
* all adapters as subdirs.
*/
if (!i2c_gpio_debug_dir) {
i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL);
if (!i2c_gpio_debug_dir)
return;
}
priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir);
if (!priv->debug_dir)
return;
debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);
debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda);
debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir,
priv, &fops_incomplete_transfer);
}
static void i2c_gpio_fault_injector_exit(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
debugfs_remove_recursive(priv->debug_dir);
}
#else
static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
static void of_i2c_gpio_get_props(struct device_node *np,
struct i2c_gpio_platform_data *pdata)
{
@ -179,6 +286,9 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->scl))
return PTR_ERR(priv->scl);
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
bit_data->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val;
@ -228,6 +338,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
pdata->scl_is_output_only
? ", no clock stretching" : "");
i2c_gpio_fault_injector_init(pdev);
return 0;
}
@ -236,6 +348,8 @@ static int i2c_gpio_remove(struct platform_device *pdev)
struct i2c_gpio_private_data *priv;
struct i2c_adapter *adap;
i2c_gpio_fault_injector_exit(pdev);
priv = platform_get_drvdata(pdev);
adap = &priv->adap;

View file

@ -30,6 +30,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/slab.h>
@ -90,6 +91,8 @@
#define FAST_PLUS_MAX_BITRATE 3400000
#define HIGHSPEED_MAX_BITRATE 5000000
#define I2C_PM_TIMEOUT 10 /* ms */
enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */
FAST, /* 400+Kbps */
@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
unsigned int temp;
int ret;
ret = clk_enable(lpi2c_imx->clk);
if (ret)
ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
if (ret < 0)
return ret;
temp = MCR_RST;
@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
ret = lpi2c_imx_config(lpi2c_imx);
if (ret)
goto clk_disable;
goto rpm_put;
temp = readl(lpi2c_imx->base + LPI2C_MCR);
temp |= MCR_MEN;
@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
return 0;
clk_disable:
clk_disable(lpi2c_imx->clk);
rpm_put:
pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
return ret;
}
@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
temp &= ~MCR_MEN;
writel(temp, lpi2c_imx->base + LPI2C_MCR);
clk_disable(lpi2c_imx->clk);
pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
return 0;
}
@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
return ret;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
clk_disable(lpi2c_imx->clk);
ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret)
goto clk_unprepare;
goto rpm_disable;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
return 0;
clk_unprepare:
clk_unprepare(lpi2c_imx->clk);
rpm_disable:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
return ret;
}
@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev)
i2c_del_adapter(&lpi2c_imx->adapter);
clk_unprepare(lpi2c_imx->clk);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int lpi2c_imx_suspend(struct device *dev)
static int lpi2c_runtime_suspend(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
clk_disable_unprepare(lpi2c_imx->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int lpi2c_imx_resume(struct device *dev)
static int lpi2c_runtime_resume(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(lpi2c_imx->clk);
if (ret) {
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
return ret;
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume);
static const struct dev_pm_ops lpi2c_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
lpi2c_runtime_resume, NULL)
};
#define IMX_LPI2C_PM (&lpi2c_pm_ops)
#else
#define IMX_LPI2C_PM NULL
#endif
static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe,
@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match,
.pm = &imx_lpi2c_pm,
.pm = IMX_LPI2C_PM,
},
};

View file

@ -37,6 +37,7 @@
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@ -46,7 +47,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio");
rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH);
if (rinfo->sda_gpio == -EPROBE_DEFER ||
rinfo->scl_gpio == -EPROBE_DEFER) {
if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (!gpio_is_valid(rinfo->sda_gpio) ||
!gpio_is_valid(rinfo->scl_gpio) ||
} else if (IS_ERR(rinfo->sda_gpiod) ||
IS_ERR(rinfo->scl_gpiod) ||
IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n");
return 0;
}
dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
rinfo->scl_gpio, rinfo->sda_gpio);
dev_dbg(&pdev->dev, "using scl%s for recovery\n",
rinfo->sda_gpiod ? ",sda" : "");
rinfo->prepare_recovery = i2c_imx_prepare_recovery;
rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
rinfo->recover_bus = i2c_generic_gpio_recovery;
rinfo->recover_bus = i2c_generic_scl_recovery;
i2c_imx->adapter.bus_recovery_info = rinfo;
return 0;

View file

@ -172,7 +172,7 @@ struct ismt_priv {
dma_addr_t io_rng_dma; /* descriptor HW base addr */
u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */
u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */
u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */
};
/**
@ -320,10 +320,12 @@ static int ismt_process_desc(const struct ismt_desc *desc,
struct ismt_priv *priv, int size,
char read_write)
{
u8 *dma_buffer = priv->dma_buffer;
u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n");
__ismt_desc_dump(&priv->pci_dev->dev, desc);
ismt_gen_reg_dump(priv);
ismt_mstr_reg_dump(priv);
if (desc->status & ISMT_DESC_SCS) {
if (read_write == I2C_SMBUS_WRITE &&
@ -393,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
struct ismt_desc *desc;
struct ismt_priv *priv = i2c_get_adapdata(adap);
struct device *dev = &priv->pci_dev->dev;
u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);
desc = &priv->hw[priv->head];
/* Initialize the DMA buffer */
memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer));
memset(priv->buffer, 0, sizeof(priv->buffer));
/* Initialize the descriptor */
memset(desc, 0, sizeof(struct ismt_desc));
@ -446,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 2;
dma_size = 2;
dma_direction = DMA_TO_DEVICE;
priv->dma_buffer[0] = command;
priv->dma_buffer[1] = data->byte;
dma_buffer[0] = command;
dma_buffer[1] = data->byte;
} else {
/* Read Byte */
dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n");
@ -466,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->wr_len_cmd = 3;
dma_size = 3;
dma_direction = DMA_TO_DEVICE;
priv->dma_buffer[0] = command;
priv->dma_buffer[1] = data->word & 0xff;
priv->dma_buffer[2] = data->word >> 8;
dma_buffer[0] = command;
dma_buffer[1] = data->word & 0xff;
dma_buffer[2] = data->word >> 8;
} else {
/* Read Word */
dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n");
@ -486,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->rd_len = 2;
dma_size = 3;
dma_direction = DMA_BIDIRECTIONAL;
priv->dma_buffer[0] = command;
priv->dma_buffer[1] = data->word & 0xff;
priv->dma_buffer[2] = data->word >> 8;
dma_buffer[0] = command;
dma_buffer[1] = data->word & 0xff;
dma_buffer[2] = data->word >> 8;
break;
case I2C_SMBUS_BLOCK_DATA:
@ -499,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_BLK;
priv->dma_buffer[0] = command;
memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
dma_buffer[0] = command;
memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else {
/* Block Read */
dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n");
@ -527,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_direction = DMA_TO_DEVICE;
desc->wr_len_cmd = dma_size;
desc->control |= ISMT_DESC_I2C;
priv->dma_buffer[0] = command;
memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
dma_buffer[0] = command;
memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
} else {
/* i2c Block Read */
dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n");
@ -557,23 +560,22 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
if (dma_size != 0) {
dev_dbg(dev, " dev=%p\n", dev);
dev_dbg(dev, " data=%p\n", data);
dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer);
dev_dbg(dev, " dma_buffer=%p\n", dma_buffer);
dev_dbg(dev, " dma_size=%d\n", dma_size);
dev_dbg(dev, " dma_direction=%d\n", dma_direction);
dma_addr = dma_map_single(dev,
priv->dma_buffer,
dma_buffer,
dma_size,
dma_direction);
if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "Error in mapping dma buffer %p\n",
priv->dma_buffer);
dma_buffer);
return -EIO;
}
dev_dbg(dev, " dma_addr = 0x%016llX\n",
(unsigned long long)dma_addr);
dev_dbg(dev, " dma_addr = %pad\n", &dma_addr);
desc->dptr_low = lower_32_bits(dma_addr);
desc->dptr_high = upper_32_bits(dma_addr);

View file

@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/types.h>
@ -57,6 +58,10 @@ enum {
STATE_WRITE,
};
struct meson_i2c_data {
unsigned char div_factor;
};
/**
* struct meson_i2c - Meson I2C device private data
*
@ -64,7 +69,6 @@ enum {
* @dev: Pointer to device structure
* @regs: Base address of the device memory mapped registers
* @clk: Pointer to clock structure
* @irq: IRQ number
* @msg: Pointer to the current I2C message
* @state: Current state in the driver state machine
* @last: Flag set for the last message in the transfer
@ -75,6 +79,7 @@ enum {
* @done: Completion used to wait for transfer termination
* @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens
* @data: Pointer to the controlller's platform data
*/
struct meson_i2c {
struct i2c_adapter adap;
@ -93,6 +98,8 @@ struct meson_i2c {
struct completion done;
u32 tokens[2];
int num_tokens;
const struct meson_i2c_data *data;
};
static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
@ -128,7 +135,7 @@ 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, freq * 4);
div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor);
/* clock divider has 12 bits */
if (div >= (1 << 12)) {
@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev)
spin_lock_init(&i2c->lock);
init_completion(&i2c->done);
i2c->data = (const struct meson_i2c_data *)
of_device_get_match_data(&pdev->dev);
i2c->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "can't get device clock\n");
@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c" },
{ .compatible = "amlogic,meson-gxbb-i2c" },
{ },
static const struct meson_i2c_data i2c_meson6_data = {
.div_factor = 4,
};
static const struct meson_i2c_data i2c_gxbb_data = {
.div_factor = 4,
};
static const struct meson_i2c_data i2c_axg_data = {
.div_factor = 3,
};
static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data },
{ .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data },
{ .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data },
{},
};
MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = {

View file

@ -78,9 +78,7 @@ struct mpc_i2c_divider {
};
struct mpc_i2c_data {
void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
u32 clock, u32 prescaler);
u32 prescaler;
void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock);
};
static inline void writeccr(struct mpc_i2c *i2c, u32 x)
@ -201,7 +199,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
};
static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
int prescaler, u32 *real_clk)
u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
unsigned int pvr = mfspr(SPRN_PVR);
@ -236,7 +234,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
int ret, fdr;
@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
return;
}
ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
static void mpc_i2c_setup_52xx(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
}
#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node,
#ifdef CONFIG_PPC_MPC512x
static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
struct device_node *node_ctrl;
void __iomem *ctrl;
@ -289,12 +287,12 @@ static void mpc_i2c_setup_512x(struct device_node *node,
}
/* The clock setup for the 52xx works also fine for the 512x */
mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
mpc_i2c_setup_52xx(node, i2c, clock);
}
#else /* CONFIG_PPC_MPC512x */
static void mpc_i2c_setup_512x(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
}
#endif /* CONFIG_PPC_MPC512x */
@ -332,14 +330,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
if (prop) {
/*
* Map and check POR Device Status Register 2
* (PORDEVSR2) at 0xE0014
* (PORDEVSR2) at 0xE0014. Note than while MPC8533
* and MPC8544 indicate SEC frequency ratio
* configuration as bit 26 in PORDEVSR2, other MPC8xxx
* parts may store it differently or may not have it
* at all.
*/
reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
if (!reg)
printk(KERN_ERR
"Error: couldn't map PORDEVSR2\n");
else
val = in_be32(reg) & 0x00000080; /* sec-cfg */
val = in_be32(reg) & 0x00000020; /* sec-cfg */
iounmap(reg);
}
}
@ -350,7 +352,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
static u32 mpc_i2c_get_prescaler_8xxx(void)
{
/* mpc83xx and mpc82xx all have prescaler 1 */
/*
* According to the AN2919 all MPC824x have prescaler 1, while MPC83xx
* may have prescaler 1, 2, or 3, depending on the power-on
* configuration.
*/
u32 prescaler = 1;
/* mpc85xx */
@ -367,6 +373,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void)
|| (SVR_SOC_VER(svr) == SVR_8610))
/* the above 85xx SoCs have prescaler 1 */
prescaler = 1;
else if ((SVR_SOC_VER(svr) == SVR_8533)
|| (SVR_SOC_VER(svr) == SVR_8544))
/* the above 85xx SoCs have prescaler 3 or 2 */
prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
else
/* all the other 85xx have prescaler 2 */
prescaler = 2;
@ -376,9 +386,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void)
}
static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
u32 prescaler, u32 *real_clk)
u32 *real_clk)
{
const struct mpc_i2c_divider *div = NULL;
u32 prescaler = mpc_i2c_get_prescaler_8xxx();
u32 divider;
int i;
@ -388,12 +399,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
return -EINVAL;
}
/* Determine proper divider value */
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
if (!prescaler)
prescaler = mpc_i2c_get_prescaler_8xxx();
divider = fsl_get_sys_freq() / clock / prescaler;
pr_debug("I2C: src_clock=%d clock=%d divider=%d\n",
@ -415,7 +420,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
int ret, fdr;
@ -426,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
return;
}
ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk);
ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk);
fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
@ -440,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
#else /* !CONFIG_FSL_SOC */
static void mpc_i2c_setup_8xxx(struct device_node *node,
struct mpc_i2c *i2c,
u32 clock, u32 prescaler)
u32 clock)
{
}
#endif /* CONFIG_FSL_SOC */
@ -711,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op)
if (match->data) {
const struct mpc_i2c_data *data = match->data;
data->setup(op->dev.of_node, i2c, clock, data->prescaler);
data->setup(op->dev.of_node, i2c, clock);
} else {
/* Backwards compatibility */
if (of_get_property(op->dev.of_node, "dfsrr", NULL))
mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
}
prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
@ -813,12 +818,10 @@ static const struct mpc_i2c_data mpc_i2c_data_8313 = {
static const struct mpc_i2c_data mpc_i2c_data_8543 = {
.setup = mpc_i2c_setup_8xxx,
.prescaler = 2,
};
static const struct mpc_i2c_data mpc_i2c_data_8544 = {
.setup = mpc_i2c_setup_8xxx,
.prescaler = 3,
};
static const struct of_device_id mpc_i2c_of_match[] = {

View file

@ -61,6 +61,7 @@
#define I2C_DMA_HARD_RST 0x0002
#define I2C_DMA_4G_MODE 0x0001
#define I2C_DEFAULT_CLK_DIV 5
#define I2C_DEFAULT_SPEED 100000 /* hz */
#define MAX_FS_MODE_SPEED 400000
#define MAX_HS_MODE_SPEED 3400000
@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET {
OFFSET_DEBUGSTAT = 0x64,
OFFSET_DEBUGCTRL = 0x68,
OFFSET_TRANSFER_LEN_AUX = 0x6c,
OFFSET_CLOCK_DIV = 0x70,
};
struct mtk_i2c_compatible {
@ -136,6 +138,7 @@ struct mtk_i2c_compatible {
unsigned char auto_restart: 1;
unsigned char aux_len_reg: 1;
unsigned char support_33bits: 1;
unsigned char timing_adjust: 1;
};
struct mtk_i2c {
@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
.max_num_msgs = 255,
};
static const struct mtk_i2c_compatible mt2712_compat = {
.pmic_i2c = 0,
.dcm = 1,
.auto_restart = 1,
.aux_len_reg = 1,
.support_33bits = 1,
.timing_adjust = 1,
};
static const struct mtk_i2c_compatible mt6577_compat = {
.quirks = &mt6577_i2c_quirks,
.pmic_i2c = 0,
@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.auto_restart = 0,
.aux_len_reg = 0,
.support_33bits = 0,
.timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt6589_compat = {
@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.auto_restart = 0,
.aux_len_reg = 0,
.support_33bits = 0,
.timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt7622_compat = {
@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = {
.auto_restart = 1,
.aux_len_reg = 1,
.support_33bits = 0,
.timing_adjust = 0,
};
static const struct mtk_i2c_compatible mt8173_compat = {
@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.auto_restart = 1,
.aux_len_reg = 1,
.support_33bits = 1,
.timing_adjust = 0,
};
static const struct of_device_id mtk_i2c_of_match[] = {
{ .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat },
{ .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
if (i2c->dev_comp->dcm)
writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN);
if (i2c->dev_comp->timing_adjust)
writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV);
writew(i2c->timing_reg, i2c->base + OFFSET_TIMING);
writew(i2c->high_speed_reg, i2c->base + OFFSET_HS);
@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
if (ret)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev)
i2c->adap.timeout = 2 * HZ;
i2c->adap.retries = 1;
ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c);
if (ret)
return -EINVAL;
if (i2c->dev_comp->timing_adjust)
i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV;
if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c)
return -EINVAL;
@ -838,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int mtk_i2c_resume(struct device *dev)
{
int ret;
struct mtk_i2c *i2c = dev_get_drvdata(dev);
ret = mtk_i2c_clock_enable(i2c);
if (ret) {
dev_err(dev, "clock enable failed!\n");
return ret;
}
mtk_i2c_init_hw(i2c);
mtk_i2c_clock_disable(i2c);
return 0;
}
#endif

View file

@ -135,6 +135,7 @@ struct mv64xxx_i2c_data {
u32 freq_m;
u32 freq_n;
struct clk *clk;
struct clk *reg_clk;
wait_queue_head_t waitq;
spinlock_t lock;
struct i2c_msg *msg;
@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd)
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
/* Not all platforms have a clk */
/* Not all platforms have clocks */
drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->clk))
clk_prepare_enable(drv_data->clk);
drv_data->reg_clk = devm_clk_get(&pd->dev, "reg");
if (IS_ERR(drv_data->reg_clk) &&
PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->reg_clk))
clk_prepare_enable(drv_data->reg_clk);
drv_data->irq = platform_get_irq(pd, 0);
if (pdata) {
@ -950,9 +958,8 @@ exit_free_irq:
exit_reset:
reset_control_assert(drv_data->rstc);
exit_clk:
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);
clk_disable_unprepare(drv_data->reg_clk);
clk_disable_unprepare(drv_data->clk);
return rc;
}
@ -965,9 +972,8 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
reset_control_assert(drv_data->rstc);
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);
clk_disable_unprepare(drv_data->reg_clk);
clk_disable_unprepare(drv_data->clk);
return 0;
}

View file

@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
if (msg->flags & I2C_M_RD) {
i2c->dma_read = 1;
i2c->dma_read = true;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
/*
@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
goto read_init_dma_fail;
}
} else {
i2c->dma_read = 0;
i2c->dma_read = false;
i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
/*

View file

@ -62,7 +62,7 @@
#define MIE (1 << 3) /* master if enable */
#define TSBE (1 << 2)
#define FSB (1 << 1) /* force stop bit */
#define ESG (1 << 0) /* en startbit gen */
#define ESG (1 << 0) /* enable start bit gen */
/* ICSSR (also for ICSIER) */
#define GCAR (1 << 6) /* general call received */
@ -132,6 +132,7 @@ struct rcar_i2c_priv {
int pos;
u32 icccr;
u32 flags;
u8 recovery_icmcr; /* protected by adapter lock */
enum rcar_i2c_type devtype;
struct i2c_client *slave;
@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
return readl(priv->io + reg);
}
static int rcar_i2c_get_scl(struct i2c_adapter *adap)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
return !!(rcar_i2c_read(priv, ICMCR) & FSCL);
};
static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
if (val)
priv->recovery_icmcr |= FSCL;
else
priv->recovery_icmcr &= ~FSCL;
rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
};
/* No get_sda, because the HW only reports its bus free logic, not SDA itself */
static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
if (val)
priv->recovery_icmcr |= FSDA;
else
priv->recovery_icmcr &= ~FSDA;
rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr);
};
static struct i2c_bus_recovery_info rcar_i2c_bri = {
.get_scl = rcar_i2c_get_scl,
.set_scl = rcar_i2c_set_scl,
.set_sda = rcar_i2c_set_sda,
.recover_bus = i2c_generic_scl_recovery,
};
static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{
/* reset master mode */
@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{
int i;
int i, ret;
for (i = 0; i < LOOP_TIMEOUT; i++) {
/* make sure that bus is not busy */
@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
udelay(1);
}
return -EBUSY;
/* Waiting did not help, try to recover */
priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
ret = i2c_recover_bus(&priv->adap);
/* No failure when recovering, so check bus busy bit again */
if (ret == 0)
ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0;
return ret;
}
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
@ -282,7 +331,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
/*
* We don't have a testcase but the HW engineers say that the write order
* We don't have a test case but the HW engineers say that the write order
* of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
* it didn't cause a drawback for me, let's rather be safe than sorry.
*/
@ -359,7 +408,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
int len;
/* Do not use DMA if it's not available or for messages < 8 bytes */
if (IS_ERR(chan) || msg->len < 8)
if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE))
return;
if (read) {
@ -440,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
/*
* Try to use DMA to transmit the rest of the data if
* address transfer pashe just finished.
* address transfer phase just finished.
*/
if (msr & MAT)
rcar_i2c_dma(priv);
@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
adap->retries = 3;
adap->dev.parent = dev;
adap->dev.of_node = dev->of_node;
adap->bus_recovery_info = &rcar_i2c_bri;
i2c_set_adapdata(adap, priv);
strlcpy(adap->name, pdev->name, sizeof(adap->name));

View file

@ -161,6 +161,7 @@ enum rk3x_i2c_state {
};
/**
* struct rk3x_i2c_soc_data:
* @grf_offset: offset inside the grf regmap for setting the i2c type
* @calc_timings: Callback function for i2c timing information calculated
*/
@ -194,7 +195,7 @@ struct rk3x_i2c_soc_data {
struct rk3x_i2c {
struct i2c_adapter adap;
struct device *dev;
struct rk3x_i2c_soc_data *soc_data;
const struct rk3x_i2c_soc_data *soc_data;
/* Hardware resources */
void __iomem *regs;
@ -1164,27 +1165,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = {
static const struct of_device_id rk3x_i2c_match[] = {
{
.compatible = "rockchip,rv1108-i2c",
.data = (void *)&rv1108_soc_data
.data = &rv1108_soc_data
},
{
.compatible = "rockchip,rk3066-i2c",
.data = (void *)&rk3066_soc_data
.data = &rk3066_soc_data
},
{
.compatible = "rockchip,rk3188-i2c",
.data = (void *)&rk3188_soc_data
.data = &rk3188_soc_data
},
{
.compatible = "rockchip,rk3228-i2c",
.data = (void *)&rk3228_soc_data
.data = &rk3228_soc_data
},
{
.compatible = "rockchip,rk3288-i2c",
.data = (void *)&rk3288_soc_data
.data = &rk3288_soc_data
},
{
.compatible = "rockchip,rk3399-i2c",
.data = (void *)&rk3399_soc_data
.data = &rk3399_soc_data
},
{},
};
@ -1207,7 +1208,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
match = of_match_node(rk3x_i2c_match, np);
i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
i2c->soc_data = match->data;
/* use common interface to get I2C timing properties */
i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);

View file

@ -40,21 +40,21 @@
/* BUS: S A8 ACK P(*) */
/* IRQ: DTE WAIT */
/* ICIC: */
/* ICCR: 0x94 0x90 */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 */
/* */
/* 1 byte transmit */
/* BUS: S A8 ACK D8(1) ACK P(*) */
/* IRQ: DTE WAIT WAIT */
/* ICIC: -DTE */
/* ICCR: 0x94 0x90 */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) */
/* */
/* 2 byte transmit */
/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */
/* IRQ: DTE WAIT WAIT WAIT */
/* ICIC: -DTE */
/* ICCR: 0x94 0x90 */
/* ICCR: 0x94 0x90 */
/* ICDR: A8 D8(1) D8(2) */
/* */
/* 3 bytes or more, +---------+ gets repeated */
@ -113,7 +113,6 @@ enum sh_mobile_i2c_op {
OP_TX_FIRST,
OP_TX,
OP_TX_STOP,
OP_TX_STOP_DATA,
OP_TX_TO_RX,
OP_RX,
OP_RX_STOP,
@ -145,11 +144,12 @@ struct sh_mobile_i2c_data {
struct dma_chan *dma_rx;
struct scatterlist sg;
enum dma_data_direction dma_direction;
u8 *dma_buf;
};
struct sh_mobile_dt_config {
int clks_per_count;
void (*setup)(struct sh_mobile_i2c_data *pd);
int (*setup)(struct sh_mobile_i2c_data *pd);
};
#define IIC_FLAG_HAS_ICIC67 (1 << 0)
@ -246,36 +246,10 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf)
return (((count_khz * (tHIGH + tf)) + 5000) / 10000);
}
static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
static int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd)
{
unsigned long i2c_clk_khz;
u32 tHIGH, tLOW, tf;
uint16_t max_val;
u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
/* Get clock rate after clock is enabled */
clk_prepare_enable(pd->clk);
i2c_clk_khz = clk_get_rate(pd->clk) / 1000;
clk_disable_unprepare(pd->clk);
i2c_clk_khz /= pd->clks_per_count;
if (pd->bus_speed == STANDARD_MODE) {
tLOW = 47; /* tLOW = 4.7 us */
tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
tf = 3; /* tf = 0.3 us */
} else if (pd->bus_speed == FAST_MODE) {
tLOW = 13; /* tLOW = 1.3 us */
tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
tf = 3; /* tf = 0.3 us */
} else {
dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
pd->bus_speed);
return -EINVAL;
}
pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
if (pd->iccl > max_val || pd->icch > max_val) {
dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
pd->iccl, pd->icch);
@ -298,35 +272,43 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
return 0;
}
static void activate_ch(struct sh_mobile_i2c_data *pd)
static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
{
/* Wake up device and enable clock */
pm_runtime_get_sync(pd->dev);
clk_prepare_enable(pd->clk);
unsigned long i2c_clk_khz;
u32 tHIGH, tLOW, tf;
/* Enable channel and configure rx ack */
iic_set_clr(pd, ICCR, ICCR_ICE, 0);
i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count;
/* Mask all interrupts */
iic_wr(pd, ICIC, 0);
if (pd->bus_speed == STANDARD_MODE) {
tLOW = 47; /* tLOW = 4.7 us */
tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */
tf = 3; /* tf = 0.3 us */
} else if (pd->bus_speed == FAST_MODE) {
tLOW = 13; /* tLOW = 1.3 us */
tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */
tf = 3; /* tf = 0.3 us */
} else {
dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
pd->bus_speed);
return -EINVAL;
}
/* Set the clock */
iic_wr(pd, ICCL, pd->iccl & 0xff);
iic_wr(pd, ICCH, pd->icch & 0xff);
pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
return sh_mobile_i2c_check_timing(pd);
}
static void deactivate_ch(struct sh_mobile_i2c_data *pd)
static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd)
{
/* Clear/disable interrupts */
iic_wr(pd, ICSR, 0);
iic_wr(pd, ICIC, 0);
unsigned long clks_per_cycle;
/* Disable channel */
iic_set_clr(pd, ICCR, 0, ICCR_ICE);
/* L = 5, H = 4, L + H = 9 */
clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed;
pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count);
pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count);
/* Disable clock and mark device as idle */
clk_disable_unprepare(pd->clk);
pm_runtime_put_sync(pd->dev);
return sh_mobile_i2c_check_timing(pd);
}
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
@ -350,10 +332,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
case OP_TX: /* write data */
iic_wr(pd, ICDR, data);
break;
case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */
iic_wr(pd, ICDR, data);
/* fallthrough */
case OP_TX_STOP: /* issue a stop */
case OP_TX_STOP: /* issue a stop (or rep_start) */
iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
: ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break;
@ -387,11 +366,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
return pd->pos == -1;
}
static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
{
return pd->pos == pd->msg->len - 1;
}
static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
unsigned char *buf)
{
@ -409,20 +383,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
unsigned char data;
if (pd->pos == pd->msg->len) {
/* Send stop if we haven't yet (DMA case) */
if (pd->send_stop && pd->stop_after_dma)
i2c_op(pd, OP_TX_STOP, 0);
i2c_op(pd, OP_TX_STOP, 0);
return 1;
}
sh_mobile_i2c_get_data(pd, &data);
if (sh_mobile_i2c_is_last_byte(pd))
i2c_op(pd, OP_TX_STOP_DATA, data);
else if (sh_mobile_i2c_is_first_byte(pd))
i2c_op(pd, OP_TX_FIRST, data);
else
i2c_op(pd, OP_TX, data);
i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data);
pd->pos++;
return 0;
@ -464,8 +430,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
break;
}
data = i2c_op(pd, OP_RX_STOP_DATA, 0);
} else
} else if (real_pos >= 0) {
data = i2c_op(pd, OP_RX, 0);
}
if (real_pos >= 0)
pd->msg->buf[real_pos] = data;
@ -548,6 +515,8 @@ static void sh_mobile_i2c_dma_callback(void *data)
pd->pos = pd->msg->len;
pd->stop_after_dma = true;
i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf);
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
@ -608,7 +577,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
if (IS_ERR(chan))
return;
dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir);
dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir);
if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(pd->dev, "dma map failed, using PIO\n");
return;
@ -651,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
if (do_init) {
/* Initialize channel registers */
iic_set_clr(pd, ICCR, 0, ICCR_ICE);
iic_wr(pd, ICCR, ICCR_SCP);
/* Enable channel and configure rx ack */
iic_set_clr(pd, ICCR, ICCR_ICE, 0);
iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
/* Set the clock */
iic_wr(pd, ICCL, pd->iccl & 0xff);
@ -665,7 +634,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
pd->pos = -1;
pd->sr = 0;
if (pd->msg->len > 8)
pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
if (pd->dma_buf)
sh_mobile_i2c_xfer_dma(pd);
/* Enable all interrupts to begin with */
@ -731,7 +701,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
int i;
long timeout;
activate_ch(pd);
/* Wake up device and enable clock */
pm_runtime_get_sync(pd->dev);
/* Process all messages */
for (i = 0; i < num; i++) {
@ -768,11 +739,13 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
break;
}
deactivate_ch(pd);
/* Disable channel */
iic_wr(pd, ICCR, ICCR_SCP);
if (!err)
err = num;
return err;
/* Disable clock and mark device as idle */
pm_runtime_put_sync(pd->dev);
return err ?: num;
}
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
@ -789,7 +762,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
* r8a7740 chip has lasting errata on I2C I/O pad reset.
* this is work-around for it.
*/
static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
iic_set_clr(pd, ICCR, ICCR_ICE, 0);
iic_rd(pd, ICCR); /* dummy read */
@ -810,14 +783,23 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
udelay(10);
iic_wr(pd, ICCR, ICCR_TRS);
udelay(10);
return sh_mobile_i2c_init(pd);
}
static const struct sh_mobile_dt_config default_dt_config = {
.clks_per_count = 1,
.setup = sh_mobile_i2c_init,
};
static const struct sh_mobile_dt_config fast_clock_dt_config = {
.clks_per_count = 2,
.setup = sh_mobile_i2c_init,
};
static const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
.clks_per_count = 2,
.setup = sh_mobile_i2c_v2_init,
};
static const struct sh_mobile_dt_config r8a7740_dt_config = {
@ -828,7 +810,7 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = {
static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
{ .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
@ -910,32 +892,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return PTR_ERR(pd->reg);
ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
pd->bus_speed = ret ? STANDARD_MODE : bus_speed;
pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed;
pd->clks_per_count = 1;
config = of_device_get_match_data(&dev->dev);
if (config) {
pd->clks_per_count = config->clks_per_count;
if (config->setup)
config->setup(pd);
}
/* The IIC blocks on SH-Mobile ARM processors
* come with two new bits in ICIC.
*/
/* Newer variants come with two new bits in ICIC */
if (resource_size(res) > 0x17)
pd->flags |= IIC_FLAG_HAS_ICIC67;
ret = sh_mobile_i2c_init(pd);
if (ret)
return ret;
/* Init DMA */
sg_init_table(&pd->sg, 1);
pd->dma_direction = DMA_NONE;
pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* Enable Runtime PM for this device.
*
* Also tell the Runtime PM core to ignore children
@ -948,6 +911,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
*/
pm_suspend_ignore_children(&dev->dev, true);
pm_runtime_enable(&dev->dev);
pm_runtime_get_sync(&dev->dev);
config = of_device_get_match_data(&dev->dev);
if (config) {
pd->clks_per_count = config->clks_per_count;
ret = config->setup(pd);
} else {
ret = sh_mobile_i2c_init(pd);
}
pm_runtime_put_sync(&dev->dev);
if (ret)
return ret;
/* Init DMA */
sg_init_table(&pd->sg, 1);
pd->dma_direction = DMA_NONE;
pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* setup the private data */
adap = &pd->adap;

View file

@ -27,7 +27,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/idr.h>
@ -134,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
/* i2c bus recovery routines */
static int get_scl_gpio_value(struct i2c_adapter *adap)
{
return gpio_get_value(adap->bus_recovery_info->scl_gpio);
return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod);
}
static void set_scl_gpio_value(struct i2c_adapter *adap, int val)
{
gpio_set_value(adap->bus_recovery_info->scl_gpio, val);
gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val);
}
static int get_sda_gpio_value(struct i2c_adapter *adap)
{
return gpio_get_value(adap->bus_recovery_info->sda_gpio);
return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod);
}
static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap)
static void set_sda_gpio_value(struct i2c_adapter *adap, int val)
{
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;
}
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);
gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val);
}
/*
@ -190,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap)
#define RECOVERY_NDELAY 5000
#define RECOVERY_CLK_CNT 9
static int i2c_generic_recovery(struct i2c_adapter *adap)
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
int i = 0, val = 1, ret = 0;
@ -199,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
bri->prepare_recovery(adap);
bri->set_scl(adap, val);
if (bri->set_sda)
bri->set_sda(adap, 1);
ndelay(RECOVERY_NDELAY);
/*
@ -227,33 +199,25 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
if (bri->get_sda && !bri->get_sda(adap))
ret = -EBUSY;
/* If all went well, send STOP for a sane bus state. */
if (ret == 0 && bri->set_sda) {
bri->set_scl(adap, 0);
ndelay(RECOVERY_NDELAY / 2);
bri->set_sda(adap, 0);
ndelay(RECOVERY_NDELAY / 2);
bri->set_scl(adap, 1);
ndelay(RECOVERY_NDELAY / 2);
bri->set_sda(adap, 1);
ndelay(RECOVERY_NDELAY / 2);
}
if (bri->unprepare_recovery)
bri->unprepare_recovery(adap);
return ret;
}
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
return i2c_generic_recovery(adap);
}
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;
}
EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery);
int i2c_recover_bus(struct i2c_adapter *adap)
{
if (!adap->bus_recovery_info)
@ -277,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
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;
if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) {
bri->get_scl = get_scl_gpio_value;
bri->set_scl = set_scl_gpio_value;
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
if (bri->sda_gpiod) {
bri->get_sda = get_sda_gpio_value;
/* FIXME: add proper flag instead of '0' once available */
if (gpiod_get_direction(bri->sda_gpiod) == 0)
bri->set_sda = set_sda_gpio_value;
}
return;
}
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";
@ -1976,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
EXPORT_SYMBOL(i2c_transfer);
/**
* i2c_master_send - issue a single I2C message in master transmit mode
* i2c_transfer_buffer_flags - issue a single I2C message transferring data
* to/from a buffer
* @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
* @buf: Where the data is stored
* @count: How many bytes to transfer, must be less than 64k since msg.len is u16
* @flags: The flags to be used for the message, e.g. I2C_M_RD for reads
*
* Returns negative errno, or else the number of bytes written.
* Returns negative errno, or else the number of bytes transferred.
*/
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,
int count, u16 flags)
{
int ret;
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
struct i2c_msg msg = {
.addr = client->addr,
.flags = flags | (client->flags & I2C_M_TEN),
.len = count,
.buf = buf,
};
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
ret = i2c_transfer(client->adapter, &msg, 1);
/*
* If everything went ok (i.e. 1 msg transmitted), return #bytes
* transmitted, else error code.
* If everything went ok (i.e. 1 msg transferred), return #bytes
* transferred, else error code.
*/
return (ret == 1) ? count : ret;
}
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;
}
EXPORT_SYMBOL(i2c_master_recv);
EXPORT_SYMBOL(i2c_transfer_buffer_flags);
/* ----------------------------------------------------
* the i2c address scanning function
@ -2265,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap)
}
EXPORT_SYMBOL(i2c_put_adapter);
/**
* i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg
* @msg: the message to be checked
* @threshold: the minimum number of bytes for which using DMA makes sense
*
* Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO.
* Or a valid pointer to be used with DMA. After use, release it by
* calling i2c_release_dma_safe_msg_buf().
*
* This function must only be called from process context!
*/
u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold)
{
if (msg->len < threshold)
return NULL;
if (msg->flags & I2C_M_DMA_SAFE)
return msg->buf;
pr_debug("using bounce buffer for addr=0x%02x, len=%d\n",
msg->addr, msg->len);
if (msg->flags & I2C_M_RD)
return kzalloc(msg->len, GFP_KERNEL);
else
return kmemdup(msg->buf, msg->len, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
/**
* i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
* @msg: the message to be synced with
* @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL.
*/
void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf)
{
if (!buf || buf == msg->buf)
return;
if (msg->flags & I2C_M_RD)
memcpy(msg->buf, buf, msg->len);
kfree(buf);
}
EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf);
MODULE_AUTHOR("Simon G. Vogl <[email protected]>");
MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL");

View file

@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/slab.h>
#define CREATE_TRACE_POINTS
#include <trace/events/smbus.h>
@ -291,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
}
EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val)
{
bool is_read = msg->flags & I2C_M_RD;
unsigned char *dma_buf;
dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL);
if (!dma_buf)
return;
msg->buf = dma_buf;
msg->flags |= I2C_M_DMA_SAFE;
if (init_val)
msg->buf[0] = init_val;
}
/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
@ -368,6 +385,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else {
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
@ -376,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]);
return -EINVAL;
}
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[0].buf[i] = data->block[i - 1];
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
@ -389,12 +409,16 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->block[0]);
return -EINVAL;
}
msg[0].len = data->block[0] + 2;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[0].buf[i] = data->block[i - 1];
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
the underlying bus driver */
i2c_smbus_try_get_dmabuf(&msg[1], 0);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
@ -406,10 +430,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
i2c_smbus_try_get_dmabuf(&msg[1], 0);
} else {
msg[0].len = data->block[0] + 1;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i];
msg[0].buf[i] = data->block[i];
}
break;
default:
@ -457,14 +484,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
data->block[i + 1] = msg[1].buf[i];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i < msgbuf1[0] + 1; i++)
data->block[i] = msgbuf1[i];
for (i = 0; i < msg[1].buf[0] + 1; i++)
data->block[i] = msg[1].buf[i];
break;
}
if (msg[0].flags & I2C_M_DMA_SAFE)
kfree(msg[0].buf);
if (msg[1].flags & I2C_M_DMA_SAFE)
kfree(msg[1].buf);
return 0;
}

View file

@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
res = PTR_ERR(msgs[i].buf);
break;
}
/* memdup_user allocates with GFP_KERNEL, so DMA is ok */
msgs[i].flags |= I2C_M_DMA_SAFE;
/*
* If the message length is received from the slave (similar

View file

@ -64,11 +64,11 @@ config I2C_MUX_PCA9541
will be called i2c-mux-pca9541.
config I2C_MUX_PCA954x
tristate "Philips PCA954x I2C Mux/switches"
tristate "NXP PCA954x and PCA984x I2C Mux/switches"
depends on GPIOLIB || COMPILE_TEST
help
If you say yes here you get support for the Philips PCA954x
I2C mux/switch devices.
If you say yes here you get support for the NXP PCA954x
and PCA984x I2C mux/switch devices.
This driver can also be built as a module. If so, the module
will be called i2c-mux-pca954x.

View file

@ -4,11 +4,11 @@
* 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 module supports the PCA954x and PCA954x series of I2C multiplexer/switch
* chips made by NXP Semiconductors.
* This includes the:
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
* and PCA9548.
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
* PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849.
*
* 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,
@ -63,6 +63,10 @@ enum pca_type {
pca_9546,
pca_9547,
pca_9548,
pca_9846,
pca_9847,
pca_9848,
pca_9849,
};
struct chip_desc {
@ -129,6 +133,24 @@ static const struct chip_desc chips[] = {
.nchans = 8,
.muxtype = pca954x_isswi,
},
[pca_9846] = {
.nchans = 4,
.muxtype = pca954x_isswi,
},
[pca_9847] = {
.nchans = 8,
.enable = 0x8,
.muxtype = pca954x_ismux,
},
[pca_9848] = {
.nchans = 8,
.muxtype = pca954x_isswi,
},
[pca_9849] = {
.nchans = 4,
.enable = 0x4,
.muxtype = pca954x_ismux,
},
};
static const struct i2c_device_id pca954x_id[] = {
@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = {
{ "pca9546", pca_9546 },
{ "pca9547", pca_9547 },
{ "pca9548", pca_9548 },
{ "pca9846", pca_9846 },
{ "pca9847", pca_9847 },
{ "pca9848", pca_9848 },
{ "pca9849", pca_9849 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
{ .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
{ .compatible = "nxp,pca9846", .data = &chips[pca_9846] },
{ .compatible = "nxp,pca9847", .data = &chips[pca_9847] },
{ .compatible = "nxp,pca9848", .data = &chips[pca_9848] },
{ .compatible = "nxp,pca9849", .data = &chips[pca_9849] },
{}
};
MODULE_DEVICE_TABLE(of, pca954x_of_match);

View file

@ -177,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
sizeof(mux->data));
} else {
ret = i2c_mux_reg_probe_dt(mux, pdev);
if (ret == -EPROBE_DEFER)
return ret;
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing device tree");
return ret;