aboutsummaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c5
-rw-r--r--drivers/i2c/busses/Kconfig15
-rw-r--r--drivers/i2c/busses/i2c-acorn.c8
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c12
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c21
-rw-r--r--drivers/i2c/busses/i2c-cht-wc.c53
-rw-r--r--drivers/i2c/busses/i2c-davinci.c106
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c20
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c59
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c105
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c64
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c2
-rw-r--r--drivers/i2c/busses/i2c-gpio.c310
-rw-r--r--drivers/i2c/busses/i2c-i801.c4
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c104
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c68
-rw-r--r--drivers/i2c/busses/i2c-imx.c20
-rw-r--r--drivers/i2c/busses/i2c-ismt.c42
-rw-r--r--drivers/i2c/busses/i2c-meson.c34
-rw-r--r--drivers/i2c/busses/i2c-mpc.c61
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c40
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c20
-rw-r--r--drivers/i2c/busses/i2c-mxs.c4
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.c1
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.h2
-rw-r--r--drivers/i2c/busses/i2c-omap.c25
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c1
-rw-r--r--drivers/i2c/busses/i2c-parport.c1
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-pnx.c8
-rw-r--r--drivers/i2c/busses/i2c-pxa-pci.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c2
-rw-r--r--drivers/i2c/busses/i2c-rcar.c62
-rw-r--r--drivers/i2c/busses/i2c-riic.c115
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c17
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c195
-rw-r--r--drivers/i2c/busses/i2c-sirf.c4
-rw-r--r--drivers/i2c/busses/i2c-stm32.h3
-rw-r--r--drivers/i2c/busses/i2c-stm32f4.c3
-rw-r--r--drivers/i2c/busses/i2c-stm32f7.c3
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c3
-rw-r--r--drivers/i2c/busses/i2c-thunderx-pcidrv.c9
-rw-r--r--drivers/i2c/busses/i2c-xgene-slimpro.c30
-rw-r--r--drivers/i2c/busses/i2c-xlp9xx.c44
-rw-r--r--drivers/i2c/i2c-boardinfo.c2
-rw-r--r--drivers/i2c/i2c-core-base.c252
-rw-r--r--drivers/i2c/i2c-core-smbus.c113
-rw-r--r--drivers/i2c/i2c-dev.c270
-rw-r--r--drivers/i2c/i2c-smbus.c81
-rw-r--r--drivers/i2c/muxes/Kconfig6
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c133
-rw-r--r--drivers/i2c/muxes/i2c-mux-reg.c12
53 files changed, 1654 insertions, 926 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 1147bddb8b2c..3df0efd69ae3 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -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;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 45a3f3ca29b3..e2954fb86d65 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -123,8 +123,10 @@ config I2C_I801
Wildcat Point (PCH)
Wildcat Point-LP (PCH)
BayTrail (SOC)
+ Braswell (SOC)
Sunrise Point-H (PCH)
Sunrise Point-LP (PCH)
+ Kaby Lake-H (PCH)
DNV (SOC)
Broxton (SOC)
Lewisburg (PCH)
@@ -198,6 +200,11 @@ config I2C_CHT_WC
SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC
found on some Intel Cherry Trail systems.
+ Note this controller is hooked up to a TI bq24292i charger-IC,
+ combined with a FUSB302 Type-C port-controller as such it is advised
+ to also select CONFIG_CHARGER_BQ24190=m and CONFIG_TYPEC_FUSB302=m
+ (the fusb302 driver currently is in drivers/staging).
+
config I2C_NFORCE2
tristate "Nvidia nForce2, nForce3 and nForce4"
depends on PCI
@@ -598,6 +605,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
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 9d7be5af2bf2..f4a5ae69bf6a 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -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");
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index 284f8670dbeb..7d4aeb4465b3 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -27,6 +27,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/slab.h>
/* I2C Register */
@@ -132,6 +133,7 @@ struct aspeed_i2c_bus {
struct i2c_adapter adap;
struct device *dev;
void __iomem *base;
+ struct reset_control *rst;
/* Synchronizes I/O mem access to base. */
spinlock_t lock;
struct completion cmd_complete;
@@ -847,6 +849,14 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
/* We just need the clock rate, we don't actually use the clk object. */
devm_clk_put(&pdev->dev, parent_clk);
+ bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
+ if (IS_ERR(bus->rst)) {
+ dev_err(&pdev->dev,
+ "missing or invalid reset controller device tree entry");
+ return PTR_ERR(bus->rst);
+ }
+ reset_control_deassert(bus->rst);
+
ret = of_property_read_u32(pdev->dev.of_node,
"bus-frequency", &bus->bus_frequency);
if (ret < 0) {
@@ -917,6 +927,8 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev)
spin_unlock_irqrestore(&bus->lock, flags);
+ reset_control_assert(bus->rst);
+
i2c_del_adapter(&bus->adap);
return 0;
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index cd07a69e2e93..44deae78913e 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -50,6 +50,9 @@
#define BCM2835_I2C_S_CLKT BIT(9)
#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */
+#define BCM2835_I2C_FEDL_SHIFT 16
+#define BCM2835_I2C_REDL_SHIFT 0
+
#define BCM2835_I2C_CDIV_MIN 0x0002
#define BCM2835_I2C_CDIV_MAX 0xFFFE
@@ -81,7 +84,7 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
{
- u32 divider;
+ u32 divider, redl, fedl;
divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
i2c_dev->bus_clk_rate);
@@ -100,6 +103,22 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
+ /*
+ * Number of core clocks to wait after falling edge before
+ * outputting the next data bit. Note that both FEDL and REDL
+ * can't be greater than CDIV/2.
+ */
+ fedl = max(divider / 16, 1u);
+
+ /*
+ * Number of core clocks to wait after rising edge before
+ * sampling the next incoming data bit.
+ */
+ redl = max(divider / 4, 1u);
+
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+ (fedl << BCM2835_I2C_FEDL_SHIFT) |
+ (redl << BCM2835_I2C_REDL_SHIFT));
return 0;
}
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
index 190bbbc7bfee..44cffad43701 100644
--- a/drivers/i2c/busses/i2c-cht-wc.c
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
+#include <linux/acpi.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -25,6 +26,7 @@
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/power/bq24190_charger.h>
#include <linux/slab.h>
#define CHT_WC_I2C_CTRL 0x5e24
@@ -232,13 +234,35 @@ static const struct irq_chip cht_wc_i2c_irq_chip = {
.name = "cht_wc_ext_chrg_irq_chip",
};
+static const char * const bq24190_suppliers[] = { "fusb302-typec-source" };
+
static const struct property_entry bq24190_props[] = {
- PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"),
+ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers),
PROPERTY_ENTRY_BOOL("omit-battery-class"),
PROPERTY_ENTRY_BOOL("disable-reset"),
{ }
};
+static struct regulator_consumer_supply fusb302_consumer = {
+ .supply = "vbus",
+ /* Must match fusb302 dev_name in intel_cht_int33fe.c */
+ .dev_name = "i2c-fusb302",
+};
+
+static const struct regulator_init_data bq24190_vbus_init_data = {
+ .constraints = {
+ /* The name is used in intel_cht_int33fe.c do not change. */
+ .name = "cht_wc_usb_typec_vbus",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = &fusb302_consumer,
+ .num_consumer_supplies = 1,
+};
+
+static struct bq24190_platform_data bq24190_pdata = {
+ .regulator_init_data = &bq24190_vbus_init_data,
+};
+
static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
@@ -246,7 +270,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
struct i2c_board_info board_info = {
.type = "bq24190",
.addr = 0x6b,
+ .dev_name = "bq24190",
.properties = bq24190_props,
+ .platform_data = &bq24190_pdata,
};
int ret, reg, irq;
@@ -314,11 +340,21 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
if (ret)
goto remove_irq_domain;
- board_info.irq = adap->client_irq;
- adap->client = i2c_new_device(&adap->adapter, &board_info);
- if (!adap->client) {
- ret = -ENOMEM;
- goto del_adapter;
+ /*
+ * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger,
+ * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302
+ * USB Type-C controller connected to another i2c bus. In this setup
+ * the max17047 and fusb302 devices are enumerated through an INT33FE
+ * ACPI device. If this device is present register an i2c-client for
+ * the TI bq24292i charger.
+ */
+ if (acpi_dev_present("INT33FE", NULL, -1)) {
+ board_info.irq = adap->client_irq;
+ adap->client = i2c_new_device(&adap->adapter, &board_info);
+ if (!adap->client) {
+ ret = -ENOMEM;
+ goto del_adapter;
+ }
}
platform_set_drvdata(pdev, adap);
@@ -335,14 +371,15 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
{
struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
- i2c_unregister_device(adap->client);
+ if (adap->client)
+ i2c_unregister_device(adap->client);
i2c_del_adapter(&adap->adapter);
irq_domain_remove(adap->irq_domain);
return 0;
}
-static struct platform_device_id cht_wc_i2c_adap_id_table[] = {
+static const struct platform_device_id cht_wc_i2c_adap_id_table[] = {
{ .name = "cht_wcove_ext_chgr" },
{},
};
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index b8c43535f16c..75d6ab177055 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -33,9 +33,10 @@
#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>
/* ----- global defines ----------------------------------------------- */
@@ -122,6 +123,9 @@
/* set the SDA GPIO low */
#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1)
+/* timeout for pm runtime autosuspend */
+#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
+
struct davinci_i2c_dev {
struct device *dev;
void __iomem *base;
@@ -135,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;
@@ -290,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)
@@ -312,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,
};
@@ -500,7 +503,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
/* This should be 0 if all bytes were transferred
* or dev->cmd_err denotes an error.
*/
- dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+ dev_err(dev->dev, "abnormal termination buf_len=%zu\n",
dev->buf_len);
dev->terminate = 1;
wmb();
@@ -541,10 +544,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+ ret = pm_runtime_get_sync(dev->dev);
+ if (ret < 0) {
+ dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret);
+ pm_runtime_put_noidle(dev->dev);
+ return ret;
+ }
+
ret = i2c_davinci_wait_bus_not_busy(dev);
if (ret < 0) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
- return ret;
+ goto out;
}
for (i = 0; i < num; i++) {
@@ -552,14 +562,16 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,
ret);
if (ret < 0)
- return ret;
+ goto out;
}
-#ifdef CONFIG_CPU_FREQ
- complete(&dev->xfr_complete);
-#endif
+ ret = num;
+
+out:
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
- return num;
+ return ret;
}
static u32 i2c_davinci_func(struct i2c_adapter *adap)
@@ -599,6 +611,9 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
int count = 0;
u16 w;
+ if (pm_runtime_suspended(dev->dev))
+ return IRQ_NONE;
+
while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
if (count++ == 100) {
@@ -698,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;
}
@@ -750,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);
@@ -770,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);
@@ -802,13 +818,24 @@ static int davinci_i2c_probe(struct platform_device *pdev)
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
- clk_prepare_enable(dev->clk);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base)) {
- r = PTR_ERR(dev->base);
- goto err_unuse_clocks;
+ return PTR_ERR(dev->base);
+ }
+
+ pm_runtime_set_autosuspend_delay(dev->dev,
+ DAVINCI_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev->dev);
+
+ pm_runtime_enable(dev->dev);
+
+ r = pm_runtime_get_sync(dev->dev);
+ if (r < 0) {
+ dev_err(dev->dev, "failed to runtime_get device: %d\n", r);
+ pm_runtime_put_noidle(dev->dev);
+ return r;
}
i2c_davinci_init(dev);
@@ -838,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;
@@ -849,27 +886,40 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (r)
goto err_unuse_clocks;
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+
return 0;
err_unuse_clocks:
- clk_disable_unprepare(dev->clk);
- dev->clk = NULL;
+ pm_runtime_dont_use_autosuspend(dev->dev);
+ pm_runtime_put_sync(dev->dev);
+ pm_runtime_disable(dev->dev);
+
return r;
}
static int davinci_i2c_remove(struct platform_device *pdev)
{
struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ int ret;
i2c_davinci_cpufreq_deregister(dev);
i2c_del_adapter(&dev->adapter);
- clk_disable_unprepare(dev->clk);
- dev->clk = NULL;
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&pdev->dev);
+ return ret;
+ }
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+ pm_runtime_dont_use_autosuspend(dev->dev);
+ pm_runtime_put_sync(dev->dev);
+ pm_runtime_disable(dev->dev);
+
return 0;
}
@@ -880,7 +930,6 @@ static int davinci_i2c_suspend(struct device *dev)
/* put I2C into reset */
davinci_i2c_reset_ctrl(i2c_dev, 0);
- clk_disable_unprepare(i2c_dev->clk);
return 0;
}
@@ -889,7 +938,6 @@ static int davinci_i2c_resume(struct device *dev)
{
struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev);
- clk_prepare_enable(i2c_dev->clk);
/* take I2C out of reset */
davinci_i2c_reset_ctrl(i2c_dev, 1);
@@ -899,6 +947,8 @@ static int davinci_i2c_resume(struct device *dev)
static const struct dev_pm_ops davinci_i2c_pm = {
.suspend = davinci_i2c_suspend,
.resume = davinci_i2c_resume,
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
#define davinci_i2c_pm_ops (&davinci_i2c_pm)
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index d1a69372432f..27ebd90de43b 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -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);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9fee4c054d3d..8707c76b2fee 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -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);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 418c233075d3..05732531829f 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -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"
@@ -207,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
i2c_dw_disable_int(dev);
/* Enable the adapter */
- __i2c_dw_enable(dev, true);
+ __i2c_dw_enable_and_wait(dev, true);
/* Clear and enable interrupts */
dw_readl(dev, DW_IC_CLR_INTR);
@@ -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 || r == -ENOSYS)
+ 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
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0e65b97842b4..5660daf6c92e 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -42,6 +42,7 @@
#include <linux/reset.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/suspend.h>
#include "i2c-designware-core.h"
@@ -201,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)
@@ -249,6 +227,14 @@ static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id)
}
}
+static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
+{
+ pm_runtime_disable(dev->dev);
+
+ if (dev->pm_disabled)
+ pm_runtime_put_noidle(dev->dev);
+}
+
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -257,7 +243,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
u32 acpi_speed, ht = 0;
struct resource *mem;
int i, irq, ret;
- const int supported_speeds[] = { 0, 100000, 400000, 1000000, 3400000 };
+ static const int supported_speeds[] = {
+ 0, 100000, 400000, 1000000, 3400000
+ };
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -345,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)
@@ -362,14 +350,22 @@ 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_disabled) {
- pm_runtime_forbid(&pdev->dev);
- } else {
- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- }
+ dev_pm_set_driver_flags(&pdev->dev,
+ DPM_FLAG_SMART_PREPARE |
+ DPM_FLAG_SMART_SUSPEND |
+ DPM_FLAG_LEAVE_SUSPENDED);
+
+ /* The code below assumes runtime PM to be disabled. */
+ WARN_ON(pm_runtime_enabled(&pdev->dev));
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+
+ if (dev->pm_disabled)
+ pm_runtime_get_noresume(&pdev->dev);
+
+ pm_runtime_enable(&pdev->dev);
if (dev->mode == DW_IC_SLAVE)
ret = i2c_dw_probe_slave(dev);
@@ -382,8 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
return ret;
exit_probe:
- if (!dev->pm_disabled)
- pm_runtime_disable(&pdev->dev);
+ dw_i2c_plat_pm_cleanup(dev);
exit_reset:
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
@@ -402,8 +397,8 @@ 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_disabled)
- pm_runtime_disable(&pdev->dev);
+ dw_i2c_plat_pm_cleanup(dev);
+
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
@@ -423,12 +418,24 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#ifdef CONFIG_PM_SLEEP
static int dw_i2c_plat_prepare(struct device *dev)
{
- return pm_runtime_suspended(dev);
+ /*
+ * If the ACPI companion device object is present for this device, it
+ * may be accessed during suspend and resume of other devices via I2C
+ * operation regions, so tell the PM core and middle layers to avoid
+ * skipping system suspend/resume callbacks for it in that case.
+ */
+ return !has_acpi_companion(dev);
}
static void dw_i2c_plat_complete(struct device *dev)
{
- if (dev->power.direct_complete)
+ /*
+ * The device can only be in runtime suspend at this point if it has not
+ * been resumed throughout the ending system suspend/resume cycle, so if
+ * the platform firmware might mess up with it, request the runtime PM
+ * framework to resume it.
+ */
+ if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
pm_request_resume(dev);
}
#else
@@ -437,12 +444,12 @@ static void dw_i2c_plat_complete(struct device *dev)
#endif
#ifdef CONFIG_PM
-static int dw_i2c_plat_runtime_suspend(struct device *dev)
+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;
}
@@ -451,27 +458,17 @@ 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;
}
-#ifdef CONFIG_PM_SLEEP
-static int dw_i2c_plat_suspend(struct device *dev)
-{
- pm_runtime_resume(dev);
- return dw_i2c_plat_runtime_suspend(dev);
-}
-#endif
-
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = dw_i2c_plat_prepare,
.complete = dw_i2c_plat_complete,
- SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
- SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
- dw_i2c_plat_resume,
- NULL)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
+ SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
};
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index ea9578ab19a1..d42558d1b002 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -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) {
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 3855e0b11877..b02428498f6d 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -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)
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 0ef8fcc6ac3a..58abb3eced58 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -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>
@@ -14,27 +16,20 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
struct i2c_gpio_private_data {
+ struct gpio_desc *sda;
+ struct gpio_desc *scl;
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
};
-/* Toggle SDA by changing the direction of the pin */
-static void i2c_gpio_setsda_dir(void *data, int state)
-{
- struct i2c_gpio_platform_data *pdata = data;
-
- if (state)
- gpio_direction_input(pdata->sda_pin);
- else
- gpio_direction_output(pdata->sda_pin, 0);
-}
-
/*
* Toggle SDA by changing the output value of the pin. This is only
* valid for pins configured as open drain (i.e. setting the value
@@ -42,20 +37,9 @@ static void i2c_gpio_setsda_dir(void *data, int state)
*/
static void i2c_gpio_setsda_val(void *data, int state)
{
- struct i2c_gpio_platform_data *pdata = data;
+ struct i2c_gpio_private_data *priv = data;
- gpio_set_value(pdata->sda_pin, state);
-}
-
-/* Toggle SCL by changing the direction of the pin. */
-static void i2c_gpio_setscl_dir(void *data, int state)
-{
- struct i2c_gpio_platform_data *pdata = data;
-
- if (state)
- gpio_direction_input(pdata->scl_pin);
- else
- gpio_direction_output(pdata->scl_pin, 0);
+ gpiod_set_value_cansleep(priv->sda, state);
}
/*
@@ -66,46 +50,127 @@ static void i2c_gpio_setscl_dir(void *data, int state)
*/
static void i2c_gpio_setscl_val(void *data, int state)
{
- struct i2c_gpio_platform_data *pdata = data;
+ struct i2c_gpio_private_data *priv = data;
- gpio_set_value(pdata->scl_pin, state);
+ gpiod_set_value_cansleep(priv->scl, state);
}
static int i2c_gpio_getsda(void *data)
{
- struct i2c_gpio_platform_data *pdata = data;
+ struct i2c_gpio_private_data *priv = data;
- return gpio_get_value(pdata->sda_pin);
+ return gpiod_get_value_cansleep(priv->sda);
}
static int i2c_gpio_getscl(void *data)
{
- struct i2c_gpio_platform_data *pdata = data;
+ struct i2c_gpio_private_data *priv = data;
- return gpio_get_value(pdata->scl_pin);
+ return gpiod_get_value_cansleep(priv->scl);
}
-static int of_i2c_gpio_get_pins(struct device_node *np,
- unsigned int *sda_pin, unsigned int *scl_pin)
+#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)
{
- if (of_gpio_count(np) < 2)
- return -ENODEV;
+ 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);
+ }
- *sda_pin = of_get_gpio(np, 0);
- *scl_pin = of_get_gpio(np, 1);
+ i2c_unlock_adapter(&priv->adap);
- if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n");
- if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) {
- pr_err("%pOF: invalid GPIO pins, sda=%d/scl=%d\n",
- np, *sda_pin, *scl_pin);
- return -ENODEV;
+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;
}
- return 0;
+ 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)
{
@@ -124,72 +189,108 @@ static void of_i2c_gpio_get_props(struct device_node *np,
of_property_read_bool(np, "i2c-gpio,scl-output-only");
}
+static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags gflags)
+{
+ struct gpio_desc *retdesc;
+ int ret;
+
+ retdesc = devm_gpiod_get(dev, con_id, gflags);
+ if (!IS_ERR(retdesc)) {
+ dev_dbg(dev, "got GPIO from name %s\n", con_id);
+ return retdesc;
+ }
+
+ retdesc = devm_gpiod_get_index(dev, NULL, index, gflags);
+ if (!IS_ERR(retdesc)) {
+ dev_dbg(dev, "got GPIO from index %u\n", index);
+ return retdesc;
+ }
+
+ ret = PTR_ERR(retdesc);
+
+ /* FIXME: hack in the old code, is this really necessary? */
+ if (ret == -EINVAL)
+ retdesc = ERR_PTR(-EPROBE_DEFER);
+
+ /* This happens if the GPIO driver is not yet probed, let's defer */
+ if (ret == -ENOENT)
+ retdesc = ERR_PTR(-EPROBE_DEFER);
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "error trying to get descriptor: %d\n", ret);
+
+ return retdesc;
+}
+
static int i2c_gpio_probe(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
- unsigned int sda_pin, scl_pin;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ enum gpiod_flags gflags;
int ret;
- /* First get the GPIO pins; if it fails, we'll defer the probe. */
- if (pdev->dev.of_node) {
- ret = of_i2c_gpio_get_pins(pdev->dev.of_node,
- &sda_pin, &scl_pin);
- if (ret)
- return ret;
- } else {
- if (!dev_get_platdata(&pdev->dev))
- return -ENXIO;
- pdata = dev_get_platdata(&pdev->dev);
- sda_pin = pdata->sda_pin;
- scl_pin = pdata->scl_pin;
- }
-
- ret = devm_gpio_request(&pdev->dev, sda_pin, "sda");
- if (ret) {
- if (ret == -EINVAL)
- ret = -EPROBE_DEFER; /* Try again later */
- return ret;
- }
- ret = devm_gpio_request(&pdev->dev, scl_pin, "scl");
- if (ret) {
- if (ret == -EINVAL)
- ret = -EPROBE_DEFER; /* Try again later */
- return ret;
- }
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
- if (pdev->dev.of_node) {
- pdata->sda_pin = sda_pin;
- pdata->scl_pin = scl_pin;
- of_i2c_gpio_get_props(pdev->dev.of_node, pdata);
+ if (np) {
+ of_i2c_gpio_get_props(np, pdata);
} else {
- memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata));
+ /*
+ * If all platform data settings are zero it is OK
+ * to not provide any platform data from the board.
+ */
+ if (dev_get_platdata(dev))
+ memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata));
}
- if (pdata->sda_is_open_drain) {
- gpio_direction_output(pdata->sda_pin, 1);
- bit_data->setsda = i2c_gpio_setsda_val;
- } else {
- gpio_direction_input(pdata->sda_pin);
- bit_data->setsda = i2c_gpio_setsda_dir;
- }
+ /*
+ * First get the GPIO pins; if it fails, we'll defer the probe.
+ * If the SDA line is marked from platform data or device tree as
+ * "open drain" it means something outside of our control is making
+ * this line being handled as open drain, and we should just handle
+ * it as any other output. Else we enforce open drain as this is
+ * required for an I2C bus.
+ */
+ if (pdata->sda_is_open_drain)
+ gflags = GPIOD_OUT_HIGH;
+ else
+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+ priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags);
+ if (IS_ERR(priv->sda))
+ return PTR_ERR(priv->sda);
+
+ /*
+ * If the SCL line is marked from platform data or device tree as
+ * "open drain" it means something outside of our control is making
+ * this line being handled as open drain, and we should just handle
+ * it as any other output. Else we enforce open drain as this is
+ * required for an I2C bus.
+ */
+ if (pdata->scl_is_open_drain)
+ gflags = GPIOD_OUT_LOW;
+ else
+ gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+ priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags);
+ if (IS_ERR(priv->scl))
+ return PTR_ERR(priv->scl);
- if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
- gpio_direction_output(pdata->scl_pin, 1);
- bit_data->setscl = i2c_gpio_setscl_val;
- } else {
- gpio_direction_input(pdata->scl_pin);
- bit_data->setscl = i2c_gpio_setscl_dir;
- }
+ 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;
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
@@ -207,18 +308,18 @@ static int i2c_gpio_probe(struct platform_device *pdev)
else
bit_data->timeout = HZ / 10; /* 100 ms */
- bit_data->data = pdata;
+ bit_data->data = priv;
adap->owner = THIS_MODULE;
- if (pdev->dev.of_node)
- strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+ if (np)
+ strlcpy(adap->name, dev_name(dev), sizeof(adap->name));
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- adap->dev.parent = &pdev->dev;
- adap->dev.of_node = pdev->dev.of_node;
+ adap->dev.parent = dev;
+ adap->dev.of_node = np;
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
@@ -227,11 +328,18 @@ static int i2c_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
- pdata->sda_pin, pdata->scl_pin,
+ /*
+ * FIXME: using global GPIO numbers is not helpful. If/when we
+ * get accessors to get the actual name of the GPIO line,
+ * from the descriptor, then provide that instead.
+ */
+ dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n",
+ desc_to_gpio(priv->sda), desc_to_gpio(priv->scl),
pdata->scl_is_output_only
? ", no clock stretching" : "");
+ i2c_gpio_fault_injector_init(pdev);
+
return 0;
}
@@ -240,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;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 9e12a53ef7b8..692b34125866 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -58,6 +58,7 @@
* Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes
* Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
* BayTrail (SOC) 0x0f12 32 hard yes yes yes
+ * Braswell (SOC) 0x2292 32 hard yes yes yes
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
* DNV (SOC) 0x19df 32 hard yes yes yes
@@ -1617,6 +1618,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Default timeout in interrupt mode: 200 ms */
priv->adapter.timeout = HZ / 5;
+ if (dev->irq == IRQ_NOTCONNECTED)
+ priv->features &= ~FEATURE_IRQ;
+
if (priv->features & FEATURE_IRQ) {
u16 pcictl, pcists;
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index eb1d91b986fd..f038858b6c54 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -82,6 +82,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/timer.h>
@@ -280,6 +281,8 @@
#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M)
+#define IMG_I2C_PM_TIMEOUT 1000 /* ms */
+
enum img_i2c_mode {
MODE_INACTIVE,
MODE_RAW,
@@ -408,6 +411,9 @@ struct img_i2c {
unsigned int raw_timeout;
};
+static int img_i2c_runtime_suspend(struct device *dev);
+static int img_i2c_runtime_resume(struct device *dev);
+
static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value)
{
writel(value, i2c->base + offset);
@@ -826,9 +832,9 @@ next_atomic_cmd:
* Timer function to check if something has gone wrong in automatic mode (so we
* don't have to handle so many interrupts just to catch an exception).
*/
-static void img_i2c_check_timer(unsigned long arg)
+static void img_i2c_check_timer(struct timer_list *t)
{
- struct img_i2c *i2c = (struct img_i2c *)arg;
+ struct img_i2c *i2c = from_timer(i2c, t, check_timer);
unsigned long flags;
unsigned int line_status;
@@ -1054,8 +1060,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
atomic = true;
}
- ret = clk_prepare_enable(i2c->scb_clk);
- if (ret)
+ ret = pm_runtime_get_sync(adap->dev.parent);
+ if (ret < 0)
return ret;
for (i = 0; i < num; i++) {
@@ -1131,7 +1137,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
break;
}
- clk_disable_unprepare(i2c->scb_clk);
+ pm_runtime_mark_last_busy(adap->dev.parent);
+ pm_runtime_put_autosuspend(adap->dev.parent);
return i2c->msg_status ? i2c->msg_status : num;
}
@@ -1149,12 +1156,13 @@ static const struct i2c_algorithm img_i2c_algo = {
static int img_i2c_init(struct img_i2c *i2c)
{
unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh;
- unsigned int i, ret, data, prescale, inc, int_bitrate, filt;
+ unsigned int i, data, prescale, inc, int_bitrate, filt;
struct img_i2c_timings timing;
u32 rev;
+ int ret;
- ret = clk_prepare_enable(i2c->scb_clk);
- if (ret)
+ ret = pm_runtime_get_sync(i2c->adap.dev.parent);
+ if (ret < 0)
return ret;
rev = img_i2c_readl(i2c, SCB_CORE_REV_REG);
@@ -1163,7 +1171,8 @@ static int img_i2c_init(struct img_i2c *i2c)
"Unknown hardware revision (%d.%d.%d.%d)\n",
(rev >> 24) & 0xff, (rev >> 16) & 0xff,
(rev >> 8) & 0xff, rev & 0xff);
- clk_disable_unprepare(i2c->scb_clk);
+ pm_runtime_mark_last_busy(i2c->adap.dev.parent);
+ pm_runtime_put_autosuspend(i2c->adap.dev.parent);
return -EINVAL;
}
@@ -1314,7 +1323,8 @@ static int img_i2c_init(struct img_i2c *i2c)
/* Perform a synchronous sequence to reset the bus */
ret = img_i2c_reset_bus(i2c);
- clk_disable_unprepare(i2c->scb_clk);
+ pm_runtime_mark_last_busy(i2c->adap.dev.parent);
+ pm_runtime_put_autosuspend(i2c->adap.dev.parent);
return ret;
}
@@ -1362,8 +1372,7 @@ static int img_i2c_probe(struct platform_device *pdev)
}
/* Set up the exception check timer */
- setup_timer(&i2c->check_timer, img_i2c_check_timer,
- (unsigned long)i2c);
+ timer_setup(&i2c->check_timer, img_i2c_check_timer, 0);
i2c->bitrate = timings[0].max_bitrate;
if (!of_property_read_u32(node, "clock-frequency", &val))
@@ -1384,22 +1393,30 @@ static int img_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c);
- ret = clk_prepare_enable(i2c->sys_clk);
- if (ret)
- return ret;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = img_i2c_runtime_resume(&pdev->dev);
+ if (ret)
+ return ret;
+ }
ret = img_i2c_init(i2c);
if (ret)
- goto disable_clk;
+ goto rpm_disable;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0)
- goto disable_clk;
+ goto rpm_disable;
return 0;
-disable_clk:
- clk_disable_unprepare(i2c->sys_clk);
+rpm_disable:
+ if (!pm_runtime_enabled(&pdev->dev))
+ img_i2c_runtime_suspend(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
return ret;
}
@@ -1408,19 +1425,55 @@ static int img_i2c_remove(struct platform_device *dev)
struct img_i2c *i2c = platform_get_drvdata(dev);
i2c_del_adapter(&i2c->adap);
+ pm_runtime_disable(&dev->dev);
+ if (!pm_runtime_status_suspended(&dev->dev))
+ img_i2c_runtime_suspend(&dev->dev);
+
+ return 0;
+}
+
+static int img_i2c_runtime_suspend(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(i2c->scb_clk);
clk_disable_unprepare(i2c->sys_clk);
return 0;
}
+static int img_i2c_runtime_resume(struct device *dev)
+{
+ struct img_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(i2c->sys_clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable sys clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(i2c->scb_clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable scb clock\n");
+ clk_disable_unprepare(i2c->sys_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int img_i2c_suspend(struct device *dev)
{
struct img_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
- img_i2c_switch_mode(i2c, MODE_SUSPEND);
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
- clk_disable_unprepare(i2c->sys_clk);
+ img_i2c_switch_mode(i2c, MODE_SUSPEND);
return 0;
}
@@ -1430,7 +1483,7 @@ static int img_i2c_resume(struct device *dev)
struct img_i2c *i2c = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(i2c->sys_clk);
+ ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
@@ -1440,7 +1493,12 @@ static int img_i2c_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(img_i2c_pm, img_i2c_suspend, img_i2c_resume);
+static const struct dev_pm_ops img_i2c_pm = {
+ SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend,
+ img_i2c_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume)
+};
static const struct of_device_id img_scb_i2c_match[] = {
{ .compatible = "img,scb-i2c" },
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index e86801a63120..e6da2c7a9a3e 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -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,
},
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index f96830ffd9f1..999557729ad2 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -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;
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index b51adffa4841..0d1c3ec8cb40 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -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);
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 88d15b92ec35..90f5d0407d73 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -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 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" },
- { .compatible = "amlogic,meson-gxbb-i2c" },
- { },
+ { .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 = {
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 96caf378b1dc..d94f05c8b8b7 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -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 */
@@ -322,7 +320,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
static u32 mpc_i2c_get_sec_cfg_8xxx(void)
{
- struct device_node *node = NULL;
+ struct device_node *node;
u32 __iomem *reg;
u32 val = 0;
@@ -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 */
@@ -700,7 +705,7 @@ static int fsl_i2c_probe(struct platform_device *op)
}
}
- if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
+ if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
prop = of_get_property(op->dev.of_node, "clock-frequency",
@@ -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[] = {
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 09d288ce0ddb..cf23a746cc17 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -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
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a832c45276a4..440fe4a96e68 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -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;
}
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index d4e8f1954f23..e617bd600794 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -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;
/*
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index 1d8775799056..d9607905dc2f 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -233,6 +233,7 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
return -EOPNOTSUPP;
case STAT_TXDATA_NAK:
+ case STAT_BUS_ERROR:
return -EIO;
case STAT_TXADDR_NAK:
case STAT_RXADDR_NAK:
diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h
index a7ef19855bb8..9bb9f64fdda0 100644
--- a/drivers/i2c/busses/i2c-octeon-core.h
+++ b/drivers/i2c/busses/i2c-octeon-core.h
@@ -43,7 +43,7 @@
#define TWSI_CTL_AAK 0x04 /* Assert ACK */
/* Status values */
-#define STAT_ERROR 0x00
+#define STAT_BUS_ERROR 0x00
#define STAT_START 0x08
#define STAT_REP_START 0x10
#define STAT_TXADDR_ACK 0x18
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 23c2ea2baedc..b9172f08fd05 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -487,6 +487,22 @@ static int omap_i2c_init(struct omap_i2c_dev *omap)
}
/*
+ * Try bus recovery, but only if SDA is actually low.
+ */
+static int omap_i2c_recover_bus(struct omap_i2c_dev *omap)
+{
+ u16 systest;
+
+ systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
+ if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
+ (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC))
+ return 0; /* bus seems to already be fine */
+ if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC))
+ return -EBUSY; /* recovery would not fix SCL */
+ return i2c_recover_bus(&omap->adapter);
+}
+
+/*
* Waiting on Bus Busy
*/
static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
@@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
timeout = jiffies + OMAP_I2C_TIMEOUT;
while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
if (time_after(jiffies, timeout))
- return i2c_recover_bus(&omap->adapter);
+ return omap_i2c_recover_bus(omap);
msleep(1);
}
@@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap)
}
if (time_after(jiffies, timeout)) {
+ /*
+ * SDA or SCL were low for the entire timeout without
+ * any activity detected. Most likely, a slave is
+ * locking up the bus with no master driving the clock.
+ */
dev_warn(omap->dev, "timeout waiting for bus ready\n");
- return -ETIMEDOUT;
+ return omap_i2c_recover_bus(omap);
}
msleep(1);
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index faa8fb8f2b8f..fa41ff799533 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = {
/* SMBus alert support */
static struct i2c_smbus_alert_setup alert_data = {
- .alert_edge_triggered = 1,
};
static struct i2c_client *ara;
static struct lineop parport_ctrl_irq = {
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index a8e54df4aed6..319209a07353 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port)
/* Setup SMBus alert if supported */
if (adapter_parm[type].smbus_alert) {
- adapter->alert_data.alert_edge_triggered = 1;
adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
&adapter->alert_data);
if (adapter->ara)
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 174579d32e5f..462948e2c535 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -983,7 +983,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
if (adapdata->smba) {
i2c_del_adapter(adap);
- if (adapdata->port == (0 << 1)) {
+ if (adapdata->port == (0 << piix4_port_shift_sb800)) {
release_region(adapdata->smba, SMBIOSIZE);
if (adapdata->sb800_main)
release_region(SB800_PIIX4_SMB_IDX, 2);
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 42d6b3a226f8..a542041df0cd 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -112,7 +112,6 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
jiffies, expires);
timer->expires = jiffies + expires;
- timer->data = (unsigned long)alg_data;
add_timer(timer);
}
@@ -435,9 +434,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void i2c_pnx_timeout(unsigned long data)
+static void i2c_pnx_timeout(struct timer_list *t)
{
- struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
+ struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer);
u32 ctl;
dev_err(&alg_data->adapter.dev,
@@ -659,8 +658,7 @@ static int i2c_pnx_probe(struct platform_device *pdev)
if (IS_ERR(alg_data->clk))
return PTR_ERR(alg_data->clk);
- setup_timer(&alg_data->mif.timer, i2c_pnx_timeout,
- (unsigned long)alg_data);
+ timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0);
snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
"%s", pdev->name);
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 004deb96afe3..72ea8f4c61aa 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
-#include <linux/i2c/pxa-i2c.h>
+#include <linux/platform_data/i2c-pxa.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 600d264e080c..fbf91d383b40 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -36,7 +36,7 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/i2c/pxa-i2c.h>
+#include <linux/platform_data/i2c-pxa.h>
#include <asm/irq.h>
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 15d764afec3b..4159ebcec2bb 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -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));
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index c811af4c8d81..95c2f1ce3cad 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -84,12 +84,7 @@
#define ICSR2_NACKF 0x10
-/* ICBRx (@ PCLK 33MHz) */
#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */
-#define ICBRL_SP100K (19 | ICBR_RESERVED)
-#define ICBRH_SP100K (16 | ICBR_RESERVED)
-#define ICBRL_SP400K (21 | ICBR_RESERVED)
-#define ICBRH_SP400K (9 | ICBR_RESERVED)
#define RIIC_INIT_MSG -1
@@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = {
.functionality = riic_func,
};
-static int riic_init_hw(struct riic_dev *riic, u32 spd)
+static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
{
int ret;
unsigned long rate;
+ int total_ticks, cks, brl, brh;
ret = clk_prepare_enable(riic->clk);
if (ret)
return ret;
+ if (t->bus_freq_hz > 400000) {
+ dev_err(&riic->adapter.dev,
+ "unsupported bus speed (%dHz). 400000 max\n",
+ t->bus_freq_hz);
+ clk_disable_unprepare(riic->clk);
+ return -EINVAL;
+ }
+
+ rate = clk_get_rate(riic->clk);
+
/*
- * TODO: Implement formula to calculate the timing values depending on
- * variable parent clock rate and arbitrary bus speed
+ * Assume the default register settings:
+ * FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles)
+ * FER.NFE = 1 (noise circuit enabled)
+ * MR3.NF = 0 (1 cycle of noise filtered out)
+ *
+ * Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1)
+ * Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1)
*/
- rate = clk_get_rate(riic->clk);
- if (rate != 33325000) {
- dev_err(&riic->adapter.dev,
- "invalid parent clk (%lu). Must be 33325000Hz\n", rate);
+
+ /*
+ * Determine reference clock rate. We must be able to get the desired
+ * frequency with only 62 clock ticks max (31 high, 31 low).
+ * Aim for a duty of 60% LOW, 40% HIGH.
+ */
+ total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz);
+
+ for (cks = 0; cks < 7; cks++) {
+ /*
+ * 60% low time must be less than BRL + 2 + 1
+ * BRL max register value is 0x1F.
+ */
+ brl = ((total_ticks * 6) / 10);
+ if (brl <= (0x1F + 3))
+ break;
+
+ total_ticks /= 2;
+ rate /= 2;
+ }
+
+ if (brl > (0x1F + 3)) {
+ dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n",
+ (unsigned long)t->bus_freq_hz);
clk_disable_unprepare(riic->clk);
return -EINVAL;
}
+ brh = total_ticks - brl;
+
+ /* Remove automatic clock ticks for sync circuit and NF */
+ if (cks == 0) {
+ brl -= 4;
+ brh -= 4;
+ } else {
+ brl -= 3;
+ brh -= 3;
+ }
+
+ /*
+ * Remove clock ticks for rise and fall times. Convert ns to clock
+ * ticks.
+ */
+ brl -= t->scl_fall_ns / (1000000000 / rate);
+ brh -= t->scl_rise_ns / (1000000000 / rate);
+
+ /* Adjust for min register values for when SCLE=1 and NFE=1 */
+ if (brl < 1)
+ brl = 1;
+ if (brh < 1)
+ brh = 1;
+
+ pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n",
+ rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6),
+ t->scl_fall_ns / (1000000000 / rate),
+ t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
+
/* Changing the order of accessing IICRST and ICE may break things! */
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
- switch (spd) {
- case 100000:
- writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1);
- writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH);
- writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL);
- break;
- case 400000:
- writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1);
- writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH);
- writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL);
- break;
- default:
- dev_err(&riic->adapter.dev,
- "unsupported bus speed (%dHz). Use 100000 or 400000\n", spd);
- clk_disable_unprepare(riic->clk);
- return -EINVAL;
- }
+ writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
+ writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
+ writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
writeb(0, riic->base + RIIC_ICSER);
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
@@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = {
static int riic_i2c_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct riic_dev *riic;
struct i2c_adapter *adap;
struct resource *res;
- u32 bus_rate = 0;
+ struct i2c_timings i2c_t;
int i, ret;
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
@@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev)
init_completion(&riic->msg_done);
- of_property_read_u32(np, "clock-frequency", &bus_rate);
- ret = riic_init_hw(riic, bus_rate);
+ i2c_parse_fw_timings(&pdev->dev, &i2c_t, true);
+
+ ret = riic_init_hw(riic, &i2c_t);
if (ret)
return ret;
@@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, riic);
- dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate);
+ dev_info(&pdev->dev, "registered with %dHz bus speed\n",
+ i2c_t.bus_freq_hz);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index fe234578380a..e1a18d989f83 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -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);
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 6f2aaeb7c4fa..d856bc211715 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -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;
-
- /* 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);
+ u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
- 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;
+
+ 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;
+ }
- /* Mask all interrupts */
- iic_wr(pd, ICIC, 0);
+ pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
+ pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
- /* Set the clock */
- iic_wr(pd, ICCL, pd->iccl & 0xff);
- iic_wr(pd, ICCH, pd->icch & 0xff);
+ 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);
+
+ /* Disable clock and mark device as idle */
+ pm_runtime_put_sync(pd->dev);
- if (!err)
- err = num;
- return err;
+ 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 },
@@ -881,7 +863,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
struct sh_mobile_i2c_data *pd;
struct i2c_adapter *adap;
struct resource *res;
- const struct of_device_id *match;
+ const struct sh_mobile_dt_config *config;
int ret;
u32 bus_speed;
@@ -910,34 +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;
- match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev);
- if (match) {
- const struct sh_mobile_dt_config *config = match->data;
-
- 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
@@ -950,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;
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 2fd8b6d00391..87197ece0f90 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -341,7 +341,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, adap);
init_completion(&siic->done);
- /* Controller Initalisation */
+ /* Controller initialisation */
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
@@ -369,7 +369,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
* but they start to affect the speed when clock is set to faster
* frequencies.
* Through the actual tests, use the different user_div value(which
- * in the divider formular 'Fio / (Fi2c * user_div)') to adapt
+ * in the divider formula 'Fio / (Fi2c * user_div)') to adapt
* the different ranges of i2c bus clock frequency, to make the SCL
* more accurate.
*/
diff --git a/drivers/i2c/busses/i2c-stm32.h b/drivers/i2c/busses/i2c-stm32.h
index dab51761f8c5..d4f9cef251ac 100644
--- a/drivers/i2c/busses/i2c-stm32.h
+++ b/drivers/i2c/busses/i2c-stm32.h
@@ -1,10 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* i2c-stm32.h
*
* Copyright (C) M'boumba Cedric Madianga 2017
+ * Copyright (C) STMicroelectronics 2017
* Author: M'boumba Cedric Madianga <[email protected]>
*
- * License terms: GNU General Public License (GPL), version 2
*/
#ifndef _I2C_STM32_H
diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
index 4ec108496f15..47c8d00de53f 100644
--- a/drivers/i2c/busses/i2c-stm32f4.c
+++ b/drivers/i2c/busses/i2c-stm32f4.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for STMicroelectronics STM32 I2C controller
*
@@ -6,11 +7,11 @@
* http://www.st.com/resource/en/reference_manual/DM00031020.pdf
*
* Copyright (C) M'boumba Cedric Madianga 2016
+ * Copyright (C) STMicroelectronics 2017
* Author: M'boumba Cedric Madianga <[email protected]>
*
* This driver is based on i2c-st.c
*
- * License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index d4a6e9c2e9aa..b445b3bb0bb1 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Driver for STMicroelectronics STM32F7 I2C controller
*
@@ -7,11 +8,11 @@
* http://www.st.com/resource/en/reference_manual/dm00124865.pdf
*
* Copyright (C) M'boumba Cedric Madianga 2017
+ * Copyright (C) STMicroelectronics 2017
* Author: M'boumba Cedric Madianga <[email protected]>
*
* This driver is based on i2c-stm32f4.c
*
- * License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
#include <linux/delay.h>
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
index addd90a8cb59..7c7fc01116a1 100644
--- a/drivers/i2c/busses/i2c-taos-evm.c
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -282,8 +282,7 @@ static void taos_disconnect(struct serio *serio)
{
struct taos_data *taos = serio_get_drvdata(serio);
- if (taos->client)
- i2c_unregister_device(taos->client);
+ i2c_unregister_device(taos->client);
i2c_del_adapter(&taos->adapter);
serio_close(serio);
kfree(taos);
diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
index df0976f4432a..19f8eec38717 100644
--- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c
+++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c
@@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
struct device_node *node)
{
- u32 type;
-
if (!node)
return -EINVAL;
@@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
if (!i2c->alert_data.irq)
return -EINVAL;
- type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq));
- i2c->alert_data.alert_edge_triggered =
- (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0;
-
i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
if (!i2c->ara)
return -ENODEV;
@@ -149,8 +143,7 @@ static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
{
- if (i2c->ara)
- i2c_unregister_device(i2c->ara);
+ i2c_unregister_device(i2c->ara);
}
static int thunder_i2c_probe_pci(struct pci_dev *pdev,
diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
index 7e89ba6fcf6f..a7ac746018ad 100644
--- a/drivers/i2c/busses/i2c-xgene-slimpro.c
+++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
@@ -129,6 +129,11 @@ struct slimpro_i2c_dev {
#define to_slimpro_i2c_dev(cl) \
container_of(cl, struct slimpro_i2c_dev, mbox_client)
+enum slimpro_i2c_version {
+ XGENE_SLIMPRO_I2C_V1 = 0,
+ XGENE_SLIMPRO_I2C_V2 = 1,
+};
+
/*
* This function tests and clears a bitmask then returns its old value
*/
@@ -476,6 +481,15 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
}
} else {
struct acpi_pcct_hw_reduced *cppc_ss;
+ const struct acpi_device_id *acpi_id;
+ int version = XGENE_SLIMPRO_I2C_V1;
+
+ acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+ &pdev->dev);
+ if (!acpi_id)
+ return -EINVAL;
+
+ version = (int)acpi_id->driver_data;
if (device_property_read_u32(&pdev->dev, "pcc-channel",
&ctx->mbox_idx))
@@ -514,9 +528,16 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
*/
ctx->comm_base_addr = cppc_ss->base_address;
if (ctx->comm_base_addr) {
- ctx->pcc_comm_addr = memremap(ctx->comm_base_addr,
- cppc_ss->length,
- MEMREMAP_WB);
+ if (version == XGENE_SLIMPRO_I2C_V2)
+ ctx->pcc_comm_addr = memremap(
+ ctx->comm_base_addr,
+ cppc_ss->length,
+ MEMREMAP_WT);
+ else
+ ctx->pcc_comm_addr = memremap(
+ ctx->comm_base_addr,
+ cppc_ss->length,
+ MEMREMAP_WB);
} else {
dev_err(&pdev->dev, "Failed to get PCC comm region\n");
rc = -ENOENT;
@@ -581,7 +602,8 @@ MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids);
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = {
- {"APMC0D40", 0},
+ {"APMC0D40", XGENE_SLIMPRO_I2C_V1},
+ {"APMC0D8B", XGENE_SLIMPRO_I2C_V2},
{}
};
MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids);
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index 6b106e94bc09..b970bf8f38e5 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -7,6 +7,7 @@
*/
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -81,9 +82,12 @@ struct xlp9xx_i2c_dev {
struct completion msg_complete;
int irq;
bool msg_read;
+ bool len_recv;
+ bool client_pec;
u32 __iomem *base;
u32 msg_buf_remaining;
u32 msg_len;
+ u32 ip_clk_hz;
u32 clk_hz;
u32 msg_err;
u8 *msg_buf;
@@ -141,10 +145,25 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
{
u32 len, i;
- u8 *buf = priv->msg_buf;
+ u8 rlen, *buf = priv->msg_buf;
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
XLP9XX_I2C_FIFO_WCNT_MASK;
+ if (!len)
+ return;
+ if (priv->len_recv) {
+ /* read length byte */
+ rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
+ *buf++ = rlen;
+ len--;
+ if (priv->client_pec)
+ ++rlen;
+ /* update remaining bytes and message length */
+ priv->msg_buf_remaining = rlen;
+ priv->msg_len = rlen + 1;
+ priv->len_recv = false;
+ }
+
len = min(priv->msg_buf_remaining, len);
for (i = 0; i < len; i++, buf++)
*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
@@ -213,7 +232,7 @@ static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
* The controller uses 5 * SCL clock internally.
* So prescale value should be divided by 5.
*/
- prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz);
+ prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz);
prescale = ((prescale - 8) / 5) - 1;
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
@@ -228,7 +247,7 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
int last_msg)
{
unsigned long timeleft;
- u32 intr_mask, cmd, val;
+ u32 intr_mask, cmd, val, len;
priv->msg_buf = msg->buf;
priv->msg_buf_remaining = priv->msg_len = msg->len;
@@ -261,9 +280,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
else
val &= ~XLP9XX_I2C_CTRL_ADDMODE;
+ priv->len_recv = msg->flags & I2C_M_RECV_LEN;
+ len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len;
+ priv->client_pec = msg->flags & I2C_CLIENT_PEC;
+
/* set data length to be transferred */
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
- (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+ (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
/* fill fifo during tx */
@@ -310,6 +333,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
return -ETIMEDOUT;
}
+ /* update msg->len with actual received length */
+ if (msg->flags & I2C_M_RECV_LEN)
+ msg->len = priv->msg_len;
return 0;
}
@@ -342,9 +368,19 @@ static const struct i2c_algorithm xlp9xx_i2c_algo = {
static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
struct xlp9xx_i2c_dev *priv)
{
+ struct clk *clk;
u32 freq;
int err;
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ;
+ dev_dbg(&pdev->dev, "using default input frequency %u\n",
+ priv->ip_clk_hz);
+ } else {
+ priv->ip_clk_hz = clk_get_rate(clk);
+ }
+
err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq);
if (err) {
freq = XLP9XX_I2C_DEFAULT_FREQ;
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index 31186ead5a40..509a6007cdf6 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -86,6 +86,7 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig
property_entries_dup(info->properties);
if (IS_ERR(devinfo->board_info.properties)) {
status = PTR_ERR(devinfo->board_info.properties);
+ kfree(devinfo);
break;
}
}
@@ -98,6 +99,7 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig
GFP_KERNEL);
if (!devinfo->board_info.resources) {
status = -ENOMEM;
+ kfree(devinfo);
break;
}
}
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 56e46581b84b..5a00bf443d06 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -27,8 +27,9 @@
#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>
#include <linux/init.h>
#include <linux/irqflags.h>
@@ -133,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);
}
/*
@@ -189,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;
@@ -198,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);
/*
@@ -205,9 +178,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
*/
while (i++ < RECOVERY_CLK_CNT * 2) {
if (val) {
- /* Break if SDA is high */
- if (bri->get_sda && bri->get_sda(adap))
- break;
/* SCL shouldn't be low here */
if (!bri->get_scl(adap)) {
dev_err(&adap->dev,
@@ -215,6 +185,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
ret = -EBUSY;
break;
}
+ /* Break if SDA is high */
+ if (bri->get_sda && bri->get_sda(adap))
+ break;
}
val = !val;
@@ -222,33 +195,29 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
ndelay(RECOVERY_NDELAY);
}
+ /* check if recovery actually succeeded */
+ 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)
@@ -272,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";
@@ -666,10 +633,16 @@ static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter,
}
static void i2c_dev_set_name(struct i2c_adapter *adap,
- struct i2c_client *client)
+ struct i2c_client *client,
+ struct i2c_board_info const *info)
{
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ if (info && info->dev_name) {
+ dev_set_name(&client->dev, "i2c-%s", info->dev_name);
+ return;
+ }
+
if (adev) {
dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev));
return;
@@ -766,7 +739,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->dev.of_node = info->of_node;
client->dev.fwnode = info->fwnode;
- i2c_dev_set_name(adap, client);
+ i2c_dev_set_name(adap, client, info);
if (info->properties) {
status = device_add_properties(&client->dev, info->properties);
@@ -808,8 +781,14 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
*/
void i2c_unregister_device(struct i2c_client *client)
{
- if (client->dev.of_node)
+ if (!client)
+ return;
+
+ if (client->dev.of_node) {
of_node_clear_flag(client->dev.of_node, OF_POPULATED);
+ of_node_put(client->dev.of_node);
+ }
+
if (ACPI_COMPANION(&client->dev))
acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev));
device_unregister(&client->dev);
@@ -1259,6 +1238,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
+ res = of_i2c_setup_smbus_alert(adap);
+ if (res)
+ goto out_reg;
+
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev);
@@ -1290,6 +1273,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return 0;
+out_reg:
+ init_completion(&adap->dev_released);
+ device_unregister(&adap->dev);
+ wait_for_completion(&adap->dev_released);
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
@@ -1417,8 +1404,7 @@ static int __unregister_client(struct device *dev, void *dummy)
static int __unregister_dummy(struct device *dev, void *dummy)
{
struct i2c_client *client = i2c_verify_client(dev);
- if (client)
- i2c_unregister_device(client);
+ i2c_unregister_device(client);
return 0;
}
@@ -1952,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
- * @client: Handle to slave device
- * @buf: Data that will be written to the slave
- * @count: How many bytes to write, must be less than 64k since msg.len is u16
- *
- * Returns negative errno, or else the number of bytes written.
- */
-int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
-{
- int ret;
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg;
-
- msg.addr = client->addr;
- msg.flags = client->flags & I2C_M_TEN;
- msg.len = count;
- msg.buf = (char *)buf;
-
- ret = i2c_transfer(adap, &msg, 1);
-
- /*
- * If everything went ok (i.e. 1 msg transmitted), return #bytes
- * transmitted, else error code.
- */
- return (ret == 1) ? count : ret;
-}
-EXPORT_SYMBOL(i2c_master_send);
-
-/**
- * i2c_master_recv - issue a single I2C message in master receive mode
+ * i2c_transfer_buffer_flags - issue a single I2C message transferring data
+ * to/from a buffer
* @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
+ * @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 read.
+ * Returns negative errno, or else the number of bytes transferred.
*/
-int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
+int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,
+ int count, u16 flags)
{
- struct i2c_adapter *adap = client->adapter;
- struct i2c_msg msg;
int ret;
+ 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.flags |= I2C_M_RD;
- msg.len = count;
- msg.buf = buf;
-
- ret = i2c_transfer(adap, &msg, 1);
+ ret = i2c_transfer(client->adapter, &msg, 1);
/*
- * If everything went ok (i.e. 1 msg received), return #bytes received,
- * 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_recv);
+EXPORT_SYMBOL(i2c_transfer_buffer_flags);
/* ----------------------------------------------------
* the i2c address scanning function
@@ -2241,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");
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
index 10f00a82ec9d..59d5cf376f6a 100644
--- a/drivers/i2c/i2c-core-smbus.c
+++ b/drivers/i2c/i2c-core-smbus.c
@@ -17,6 +17,8 @@
#include <linux/device.h>
#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>
@@ -290,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,
@@ -367,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) {
@@ -375,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:
@@ -388,26 +409,34 @@ 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) {
+ dev_err(&adapter->dev, "Invalid block %s size %d\n",
+ read_write == I2C_SMBUS_READ ? "read" : "write",
+ data->block[0]);
+ return -EINVAL;
+ }
+
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;
- if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
- dev_err(&adapter->dev,
- "Invalid block write size %d\n",
- data->block[0]);
- return -EINVAL;
- }
+
+ 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:
@@ -455,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;
}
@@ -592,3 +627,57 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
return i;
}
EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated);
+
+/**
+ * i2c_setup_smbus_alert - Setup SMBus alert support
+ * @adapter: the target adapter
+ * @setup: setup data for the SMBus alert handler
+ * Context: can sleep
+ *
+ * Setup handling of the SMBus alert protocol on a given I2C bus segment.
+ *
+ * Handling can be done either through our IRQ handler, or by the
+ * adapter (from its handler, periodic polling, or whatever).
+ *
+ * NOTE that if we manage the IRQ, we *MUST* know if it's level or
+ * edge triggered in order to hand it to the workqueue correctly.
+ * If triggering the alert seems to wedge the system, you probably
+ * should have said it's level triggered.
+ *
+ * This returns the ara client, which should be saved for later use with
+ * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
+ * to indicate an error.
+ */
+struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
+ struct i2c_smbus_alert_setup *setup)
+{
+ struct i2c_board_info ara_board_info = {
+ I2C_BOARD_INFO("smbus_alert", 0x0c),
+ .platform_data = setup,
+ };
+
+ return i2c_new_device(adapter, &ara_board_info);
+}
+EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
+
+#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF)
+int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter)
+{
+ struct i2c_client *client;
+ int irq;
+
+ irq = of_property_match_string(adapter->dev.of_node, "interrupt-names",
+ "smbus_alert");
+ if (irq == -EINVAL || irq == -ENODATA)
+ return 0;
+ else if (irq < 0)
+ return irq;
+
+ client = i2c_setup_smbus_alert(adapter, NULL);
+ if (!client)
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert);
+#endif
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 6f638bbc922d..036a03f0d0a6 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -35,6 +35,7 @@
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/compat.h>
/*
* An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
@@ -238,48 +239,33 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
}
static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
- unsigned long arg)
+ unsigned nmsgs, struct i2c_msg *msgs)
{
- struct i2c_rdwr_ioctl_data rdwr_arg;
- struct i2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i, res;
- if (copy_from_user(&rdwr_arg,
- (struct i2c_rdwr_ioctl_data __user *)arg,
- sizeof(rdwr_arg)))
- return -EFAULT;
-
- /* Put an arbitrary limit on the number of messages that can
- * be sent at once */
- if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
- return -EINVAL;
-
- rdwr_pa = memdup_user(rdwr_arg.msgs,
- rdwr_arg.nmsgs * sizeof(struct i2c_msg));
- if (IS_ERR(rdwr_pa))
- return PTR_ERR(rdwr_pa);
-
- data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+ data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL);
if (data_ptrs == NULL) {
- kfree(rdwr_pa);
+ kfree(msgs);
return -ENOMEM;
}
res = 0;
- for (i = 0; i < rdwr_arg.nmsgs; i++) {
+ for (i = 0; i < nmsgs; i++) {
/* Limit the size of the message to a sane amount */
- if (rdwr_pa[i].len > 8192) {
+ if (msgs[i].len > 8192) {
res = -EINVAL;
break;
}
- data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
- rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
- if (IS_ERR(rdwr_pa[i].buf)) {
- res = PTR_ERR(rdwr_pa[i].buf);
+ data_ptrs[i] = (u8 __user *)msgs[i].buf;
+ msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len);
+ if (IS_ERR(msgs[i].buf)) {
+ 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
@@ -292,121 +278,117 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
* greater (for example to account for a checksum byte at
* the end of the message.)
*/
- if (rdwr_pa[i].flags & I2C_M_RECV_LEN) {
- if (!(rdwr_pa[i].flags & I2C_M_RD) ||
- rdwr_pa[i].buf[0] < 1 ||
- rdwr_pa[i].len < rdwr_pa[i].buf[0] +
+ if (msgs[i].flags & I2C_M_RECV_LEN) {
+ if (!(msgs[i].flags & I2C_M_RD) ||
+ msgs[i].buf[0] < 1 ||
+ msgs[i].len < msgs[i].buf[0] +
I2C_SMBUS_BLOCK_MAX) {
res = -EINVAL;
break;
}
- rdwr_pa[i].len = rdwr_pa[i].buf[0];
+ msgs[i].len = msgs[i].buf[0];
}
}
if (res < 0) {
int j;
for (j = 0; j < i; ++j)
- kfree(rdwr_pa[j].buf);
+ kfree(msgs[j].buf);
kfree(data_ptrs);
- kfree(rdwr_pa);
+ kfree(msgs);
return res;
}
- res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+ res = i2c_transfer(client->adapter, msgs, nmsgs);
while (i-- > 0) {
- if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
- if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
- rdwr_pa[i].len))
+ if (res >= 0 && (msgs[i].flags & I2C_M_RD)) {
+ if (copy_to_user(data_ptrs[i], msgs[i].buf,
+ msgs[i].len))
res = -EFAULT;
}
- kfree(rdwr_pa[i].buf);
+ kfree(msgs[i].buf);
}
kfree(data_ptrs);
- kfree(rdwr_pa);
+ kfree(msgs);
return res;
}
static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
- unsigned long arg)
+ u8 read_write, u8 command, u32 size,
+ union i2c_smbus_data __user *data)
{
- struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp = {};
int datasize, res;
- if (copy_from_user(&data_arg,
- (struct i2c_smbus_ioctl_data __user *) arg,
- sizeof(struct i2c_smbus_ioctl_data)))
- return -EFAULT;
- if ((data_arg.size != I2C_SMBUS_BYTE) &&
- (data_arg.size != I2C_SMBUS_QUICK) &&
- (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
- (data_arg.size != I2C_SMBUS_WORD_DATA) &&
- (data_arg.size != I2C_SMBUS_PROC_CALL) &&
- (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
- (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
- (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
- (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
+ if ((size != I2C_SMBUS_BYTE) &&
+ (size != I2C_SMBUS_QUICK) &&
+ (size != I2C_SMBUS_BYTE_DATA) &&
+ (size != I2C_SMBUS_WORD_DATA) &&
+ (size != I2C_SMBUS_PROC_CALL) &&
+ (size != I2C_SMBUS_BLOCK_DATA) &&
+ (size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
+ (size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+ (size != I2C_SMBUS_BLOCK_PROC_CALL)) {
dev_dbg(&client->adapter->dev,
"size out of range (%x) in ioctl I2C_SMBUS.\n",
- data_arg.size);
+ size);
return -EINVAL;
}
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size==I2C_SMBUS_QUICK too. */
- if ((data_arg.read_write != I2C_SMBUS_READ) &&
- (data_arg.read_write != I2C_SMBUS_WRITE)) {
+ if ((read_write != I2C_SMBUS_READ) &&
+ (read_write != I2C_SMBUS_WRITE)) {
dev_dbg(&client->adapter->dev,
"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
- data_arg.read_write);
+ read_write);
return -EINVAL;
}
/* Note that command values are always valid! */
- if ((data_arg.size == I2C_SMBUS_QUICK) ||
- ((data_arg.size == I2C_SMBUS_BYTE) &&
- (data_arg.read_write == I2C_SMBUS_WRITE)))
+ if ((size == I2C_SMBUS_QUICK) ||
+ ((size == I2C_SMBUS_BYTE) &&
+ (read_write == I2C_SMBUS_WRITE)))
/* These are special: we do not use data */
return i2c_smbus_xfer(client->adapter, client->addr,
- client->flags, data_arg.read_write,
- data_arg.command, data_arg.size, NULL);
+ client->flags, read_write,
+ command, size, NULL);
- if (data_arg.data == NULL) {
+ if (data == NULL) {
dev_dbg(&client->adapter->dev,
"data is NULL pointer in ioctl I2C_SMBUS.\n");
return -EINVAL;
}
- if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
- (data_arg.size == I2C_SMBUS_BYTE))
- datasize = sizeof(data_arg.data->byte);
- else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
- (data_arg.size == I2C_SMBUS_PROC_CALL))
- datasize = sizeof(data_arg.data->word);
+ if ((size == I2C_SMBUS_BYTE_DATA) ||
+ (size == I2C_SMBUS_BYTE))
+ datasize = sizeof(data->byte);
+ else if ((size == I2C_SMBUS_WORD_DATA) ||
+ (size == I2C_SMBUS_PROC_CALL))
+ datasize = sizeof(data->word);
else /* size == smbus block, i2c block, or block proc. call */
- datasize = sizeof(data_arg.data->block);
+ datasize = sizeof(data->block);
- if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
- (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
- (data_arg.read_write == I2C_SMBUS_WRITE)) {
- if (copy_from_user(&temp, data_arg.data, datasize))
+ if ((size == I2C_SMBUS_PROC_CALL) ||
+ (size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ (size == I2C_SMBUS_I2C_BLOCK_DATA) ||
+ (read_write == I2C_SMBUS_WRITE)) {
+ if (copy_from_user(&temp, data, datasize))
return -EFAULT;
}
- if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
+ if (size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
/* Convert old I2C block commands to the new
convention. This preserves binary compatibility. */
- data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
- if (data_arg.read_write == I2C_SMBUS_READ)
+ size = I2C_SMBUS_I2C_BLOCK_DATA;
+ if (read_write == I2C_SMBUS_READ)
temp.block[0] = I2C_SMBUS_BLOCK_MAX;
}
res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
- data_arg.read_write, data_arg.command, data_arg.size, &temp);
- if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
- (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
- (data_arg.read_write == I2C_SMBUS_READ))) {
- if (copy_to_user(data_arg.data, &temp, datasize))
+ read_write, command, size, &temp);
+ if (!res && ((size == I2C_SMBUS_PROC_CALL) ||
+ (size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ (read_write == I2C_SMBUS_READ))) {
+ if (copy_to_user(data, &temp, datasize))
return -EFAULT;
}
return res;
@@ -454,12 +436,39 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
- case I2C_RDWR:
- return i2cdev_ioctl_rdwr(client, arg);
+ case I2C_RDWR: {
+ struct i2c_rdwr_ioctl_data rdwr_arg;
+ struct i2c_msg *rdwr_pa;
+
+ if (copy_from_user(&rdwr_arg,
+ (struct i2c_rdwr_ioctl_data __user *)arg,
+ sizeof(rdwr_arg)))
+ return -EFAULT;
+
+ /* Put an arbitrary limit on the number of messages that can
+ * be sent at once */
+ if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
+ return -EINVAL;
- case I2C_SMBUS:
- return i2cdev_ioctl_smbus(client, arg);
+ rdwr_pa = memdup_user(rdwr_arg.msgs,
+ rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+ if (IS_ERR(rdwr_pa))
+ return PTR_ERR(rdwr_pa);
+
+ return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
+ }
+ case I2C_SMBUS: {
+ struct i2c_smbus_ioctl_data data_arg;
+ if (copy_from_user(&data_arg,
+ (struct i2c_smbus_ioctl_data __user *) arg,
+ sizeof(struct i2c_smbus_ioctl_data)))
+ return -EFAULT;
+ return i2cdev_ioctl_smbus(client, data_arg.read_write,
+ data_arg.command,
+ data_arg.size,
+ data_arg.data);
+ }
case I2C_RETRIES:
client->adapter->retries = arg;
break;
@@ -480,6 +489,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0;
}
+#ifdef CONFIG_COMPAT
+
+struct i2c_smbus_ioctl_data32 {
+ u8 read_write;
+ u8 command;
+ u32 size;
+ compat_caddr_t data; /* union i2c_smbus_data *data */
+};
+
+struct i2c_msg32 {
+ u16 addr;
+ u16 flags;
+ u16 len;
+ compat_caddr_t buf;
+};
+
+struct i2c_rdwr_ioctl_data32 {
+ compat_caddr_t msgs; /* struct i2c_msg __user *msgs */
+ u32 nmsgs;
+};
+
+static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = file->private_data;
+ unsigned long funcs;
+ switch (cmd) {
+ case I2C_FUNCS:
+ funcs = i2c_get_functionality(client->adapter);
+ return put_user(funcs, (compat_ulong_t __user *)arg);
+ case I2C_RDWR: {
+ struct i2c_rdwr_ioctl_data32 rdwr_arg;
+ struct i2c_msg32 *p;
+ struct i2c_msg *rdwr_pa;
+ int i;
+
+ if (copy_from_user(&rdwr_arg,
+ (struct i2c_rdwr_ioctl_data32 __user *)arg,
+ sizeof(rdwr_arg)))
+ return -EFAULT;
+
+ if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
+ return -EINVAL;
+
+ rdwr_pa = kmalloc_array(rdwr_arg.nmsgs, sizeof(struct i2c_msg),
+ GFP_KERNEL);
+ if (!rdwr_pa)
+ return -ENOMEM;
+
+ p = compat_ptr(rdwr_arg.msgs);
+ for (i = 0; i < rdwr_arg.nmsgs; i++) {
+ struct i2c_msg32 umsg;
+ if (copy_from_user(&umsg, p + i, sizeof(umsg))) {
+ kfree(rdwr_pa);
+ return -EFAULT;
+ }
+ rdwr_pa[i] = (struct i2c_msg) {
+ .addr = umsg.addr,
+ .flags = umsg.flags,
+ .len = umsg.len,
+ .buf = compat_ptr(umsg.buf)
+ };
+ }
+
+ return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
+ }
+ case I2C_SMBUS: {
+ struct i2c_smbus_ioctl_data32 data32;
+ if (copy_from_user(&data32,
+ (void __user *) arg,
+ sizeof(data32)))
+ return -EFAULT;
+ return i2cdev_ioctl_smbus(client, data32.read_write,
+ data32.command,
+ data32.size,
+ compat_ptr(data32.data));
+ }
+ default:
+ return i2cdev_ioctl(file, cmd, arg);
+ }
+}
+#else
+#define compat_i2cdev_ioctl NULL
+#endif
+
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
@@ -527,6 +620,7 @@ static const struct file_operations i2cdev_fops = {
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
+ .compat_ioctl = compat_i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index f9271c713d20..5a1dd7f13bac 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -21,12 +21,11 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct i2c_smbus_alert {
- unsigned int alert_edge_triggered:1;
- int irq;
struct work_struct alert;
struct i2c_client *ara; /* Alert response address */
};
@@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
* The alert IRQ handler needs to hand work off to a task which can issue
* SMBus calls, because those sleeping calls can't be made in IRQ context.
*/
-static void smbus_alert(struct work_struct *work)
+static irqreturn_t smbus_alert(int irq, void *d)
{
- struct i2c_smbus_alert *alert;
+ struct i2c_smbus_alert *alert = d;
struct i2c_client *ara;
unsigned short prev_addr = 0; /* Not a valid address */
- alert = container_of(work, struct i2c_smbus_alert, alert);
ara = alert->ara;
for (;;) {
@@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work)
prev_addr = data.addr;
}
- /* We handled all alerts; re-enable level-triggered IRQs */
- if (!alert->alert_edge_triggered)
- enable_irq(alert->irq);
+ return IRQ_HANDLED;
}
-static irqreturn_t smbalert_irq(int irq, void *d)
+static void smbalert_work(struct work_struct *work)
{
- struct i2c_smbus_alert *alert = d;
+ struct i2c_smbus_alert *alert;
- /* Disable level-triggered IRQs until we handle them */
- if (!alert->alert_edge_triggered)
- disable_irq_nosync(irq);
+ alert = container_of(work, struct i2c_smbus_alert, alert);
+
+ smbus_alert(0, alert);
- schedule_work(&alert->alert);
- return IRQ_HANDLED;
}
/* Setup SMBALERT# infrastructure */
@@ -139,28 +133,35 @@ static int smbalert_probe(struct i2c_client *ara,
struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev);
struct i2c_smbus_alert *alert;
struct i2c_adapter *adapter = ara->adapter;
- int res;
+ int res, irq;
alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
GFP_KERNEL);
if (!alert)
return -ENOMEM;
- alert->alert_edge_triggered = setup->alert_edge_triggered;
- alert->irq = setup->irq;
- INIT_WORK(&alert->alert, smbus_alert);
+ if (setup) {
+ irq = setup->irq;
+ } else {
+ irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert");
+ if (irq <= 0)
+ return irq;
+ }
+
+ INIT_WORK(&alert->alert, smbalert_work);
alert->ara = ara;
- if (setup->irq > 0) {
- res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
- 0, "smbus_alert", alert);
+ if (irq > 0) {
+ res = devm_request_threaded_irq(&ara->dev, irq,
+ NULL, smbus_alert,
+ IRQF_SHARED | IRQF_ONESHOT,
+ "smbus_alert", alert);
if (res)
return res;
}
i2c_set_clientdata(ara, alert);
- dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
- setup->alert_edge_triggered ? "edge" : "level");
+ dev_info(&adapter->dev, "supports SMBALERT#\n");
return 0;
}
@@ -190,38 +191,6 @@ static struct i2c_driver smbalert_driver = {
};
/**
- * i2c_setup_smbus_alert - Setup SMBus alert support
- * @adapter: the target adapter
- * @setup: setup data for the SMBus alert handler
- * Context: can sleep
- *
- * Setup handling of the SMBus alert protocol on a given I2C bus segment.
- *
- * Handling can be done either through our IRQ handler, or by the
- * adapter (from its handler, periodic polling, or whatever).
- *
- * NOTE that if we manage the IRQ, we *MUST* know if it's level or
- * edge triggered in order to hand it to the workqueue correctly.
- * If triggering the alert seems to wedge the system, you probably
- * should have said it's level triggered.
- *
- * This returns the ara client, which should be saved for later use with
- * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
- * to indicate an error.
- */
-struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
- struct i2c_smbus_alert_setup *setup)
-{
- struct i2c_board_info ara_board_info = {
- I2C_BOARD_INFO("smbus_alert", 0x0c),
- .platform_data = setup,
- };
-
- return i2c_new_device(adapter, &ara_board_info);
-}
-EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
-
-/**
* i2c_handle_smbus_alert - Handle an SMBus alert
* @ara: the ARA client on the relevant adapter
* Context: can't sleep
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 0f5c8fc36625..52a4a922e7e6 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -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.
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 7b992db38021..fbb84c7ef282 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -4,11 +4,11 @@
* Copyright (c) 2008-2009 Rodolfo Giometti <[email protected]>
* Copyright (c) 2008-2009 Eurotech S.p.A. <[email protected]>
*
- * 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);
@@ -246,36 +276,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
return handled ? IRQ_HANDLED : IRQ_NONE;
}
-static void pca954x_irq_mask(struct irq_data *idata)
-{
- struct pca954x *data = irq_data_get_irq_chip_data(idata);
- unsigned int pos = idata->hwirq;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&data->lock, flags);
-
- data->irq_mask &= ~BIT(pos);
- if (!data->irq_mask)
- disable_irq(data->client->irq);
-
- raw_spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static void pca954x_irq_unmask(struct irq_data *idata)
-{
- struct pca954x *data = irq_data_get_irq_chip_data(idata);
- unsigned int pos = idata->hwirq;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&data->lock, flags);
-
- if (!data->irq_mask)
- enable_irq(data->client->irq);
- data->irq_mask |= BIT(pos);
-
- raw_spin_unlock_irqrestore(&data->lock, flags);
-}
-
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
{
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
@@ -285,8 +285,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
static struct irq_chip pca954x_irq_chip = {
.name = "i2c-mux-pca954x",
- .irq_mask = pca954x_irq_mask,
- .irq_unmask = pca954x_irq_unmask,
.irq_set_type = pca954x_irq_set_type,
};
@@ -294,7 +292,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
- int c, err, irq;
+ int c, irq;
if (!data->chip->has_irq || client->irq <= 0)
return 0;
@@ -309,29 +307,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
for (c = 0; c < data->chip->nchans; c++) {
irq = irq_create_mapping(data->irq, c);
+ if (!irq) {
+ dev_err(&client->dev, "failed irq create map\n");
+ return -EINVAL;
+ }
irq_set_chip_data(irq, data);
irq_set_chip_and_handler(irq, &pca954x_irq_chip,
handle_simple_irq);
}
- err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL,
- pca954x_irq_handler,
- IRQF_ONESHOT | IRQF_SHARED,
- "pca954x", data);
- if (err)
- goto err_req_irq;
+ return 0;
+}
- disable_irq(data->client->irq);
+static void pca954x_cleanup(struct i2c_mux_core *muxc)
+{
+ struct pca954x *data = i2c_mux_priv(muxc);
+ int c, irq;
- return 0;
-err_req_irq:
- for (c = 0; c < data->chip->nchans; c++) {
- irq = irq_find_mapping(data->irq, c);
- irq_dispose_mapping(irq);
+ if (data->irq) {
+ for (c = 0; c < data->chip->nchans; c++) {
+ irq = irq_find_mapping(data->irq, c);
+ irq_dispose_mapping(irq);
+ }
+ irq_domain_remove(data->irq);
}
- irq_domain_remove(data->irq);
-
- return err;
+ i2c_mux_del_adapters(muxc);
}
/*
@@ -391,7 +391,7 @@ static int pca954x_probe(struct i2c_client *client,
ret = pca954x_irq_setup(muxc);
if (ret)
- goto fail_del_adapters;
+ goto fail_cleanup;
/* Now create an adapter for each channel */
for (num = 0; num < data->chip->nchans; num++) {
@@ -414,7 +414,16 @@ static int pca954x_probe(struct i2c_client *client,
ret = i2c_mux_add_adapter(muxc, force, num, class);
if (ret)
- goto fail_del_adapters;
+ goto fail_cleanup;
+ }
+
+ if (data->irq) {
+ ret = devm_request_threaded_irq(&client->dev, data->client->irq,
+ NULL, pca954x_irq_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "pca954x", data);
+ if (ret)
+ goto fail_cleanup;
}
dev_info(&client->dev,
@@ -424,26 +433,16 @@ static int pca954x_probe(struct i2c_client *client,
return 0;
-fail_del_adapters:
- i2c_mux_del_adapters(muxc);
+fail_cleanup:
+ pca954x_cleanup(muxc);
return ret;
}
static int pca954x_remove(struct i2c_client *client)
{
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
- struct pca954x *data = i2c_mux_priv(muxc);
- int c, irq;
-
- if (data->irq) {
- for (c = 0; c < data->chip->nchans; c++) {
- irq = irq_find_mapping(data->irq, c);
- irq_dispose_mapping(irq);
- }
- irq_domain_remove(data->irq);
- }
- i2c_mux_del_adapters(muxc);
+ pca954x_cleanup(muxc);
return 0;
}
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index d97031804de8..c948e5a4cb04 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -107,9 +107,9 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
put_device(&adapter->dev);
mux->data.n_values = of_get_child_count(np);
- if (of_find_property(np, "little-endian", NULL)) {
+ if (of_property_read_bool(np, "little-endian")) {
mux->data.little_endian = true;
- } else if (of_find_property(np, "big-endian", NULL)) {
+ } else if (of_property_read_bool(np, "big-endian")) {
mux->data.little_endian = false;
} else {
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \
@@ -122,10 +122,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
#error Endianness not defined?
#endif
}
- if (of_find_property(np, "write-only", NULL))
- mux->data.write_only = true;
- else
- mux->data.write_only = false;
+ mux->data.write_only = of_property_read_bool(np, "write-only");
values = devm_kzalloc(&pdev->dev,
sizeof(*mux->data.values) * mux->data.n_values,
@@ -180,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;