summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c2
-rw-r--r--drivers/i2c/busses/Kconfig7
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-at91.c23
-rw-r--r--drivers/i2c/busses/i2c-bcm283x.c36
-rw-r--r--drivers/i2c/busses/i2c-cadence.c11
-rw-r--r--drivers/i2c/busses/i2c-designware.c9
-rw-r--r--drivers/i2c/busses/i2c-gpio.c11
-rw-r--r--drivers/i2c/busses/i2c-imx-early.c57
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c555
-rw-r--r--drivers/i2c/busses/i2c-imx.c42
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c13
-rw-r--r--drivers/i2c/busses/i2c-omap.c15
-rw-r--r--drivers/i2c/busses/i2c-rockchip.c25
-rw-r--r--drivers/i2c/busses/i2c-stm32.c455
-rw-r--r--drivers/i2c/busses/i2c-tegra.c13
-rw-r--r--drivers/i2c/busses/i2c-versatile.c7
-rw-r--r--drivers/i2c/i2c-mux.c10
-rw-r--r--drivers/i2c/i2c.c115
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c8
20 files changed, 1107 insertions, 308 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 2d6010869d..9b7e5d96f0 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -245,7 +245,7 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
static int test_bus(struct i2c_adapter *i2c_adap)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
- struct device_d *dev = &i2c_adap->dev;
+ struct device *dev = &i2c_adap->dev;
int scl, sda, ret;
if (adap->pre_xfer) {
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 766aa5edfa..a274baf4b6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -30,6 +30,13 @@ config I2C_IMX
for many i.MX ARM based SoCs, for MPC85xx and MPC5200 PowerPC based
SoCs.
+config I2C_IMX_LPI2C
+ tristate "IMX Low Power I2C interface"
+ depends on ARCH_IMX || COMPILE_TEST
+ help
+ Say Y here if you want to use the Low Power IIC bus controller
+ on the Freescale i.MX processors.
+
config I2C_DESIGNWARE
bool "Synopsys DesignWare I2C Master driver"
help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a1ab46fb28..b4225995c0 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_I2C_BCM283X) += i2c-bcm283x.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
lwl-$(CONFIG_I2C_IMX_EARLY) += i2c-imx-early.o
+obj-pbl-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index b100dc6c17..5b1f456187 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -78,11 +78,10 @@ struct at91_twi_pdata {
bool has_dig_filtr;
bool has_adv_dig_filtr;
bool has_ana_filtr;
- bool has_clear_cmd;
};
struct at91_twi_dev {
- struct device_d *dev;
+ struct device *dev;
void __iomem *base;
struct clk *clk;
u8 *buf;
@@ -438,6 +437,13 @@ static struct at91_twi_pdata at91sam9x5_config = {
.has_unre_flag = false,
};
+static struct at91_twi_pdata sama5d4_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_hold_field = true,
+ .has_dig_filtr = true,
+};
+
static struct at91_twi_pdata sama5d2_config = {
.clk_max_div = 7,
.clk_offset = 3,
@@ -493,14 +499,21 @@ static struct of_device_id at91_twi_dt_ids[] = {
.compatible = "atmel,at91sam9x5-i2c",
.data = &at91sam9x5_config,
}, {
+ .compatible = "atmel,sama5d4-i2c",
+ .data = &sama5d4_config,
+ }, {
.compatible = "atmel,sama5d2-i2c",
.data = &sama5d2_config,
}, {
+ .compatible = "microchip,sam9x60-i2c",
+ .data = &sama5d2_config,
+ }, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, at91_twi_dt_ids);
-static int at91_twi_probe(struct device_d *dev)
+static int at91_twi_probe(struct device *dev)
{
struct resource *iores;
struct at91_twi_dev *i2c_at91;
@@ -546,7 +559,7 @@ static int at91_twi_probe(struct device_d *dev)
i2c_at91->adapter.master_xfer = at91_twi_xfer;
i2c_at91->adapter.dev.parent = dev;
i2c_at91->adapter.nr = dev->id;
- i2c_at91->adapter.dev.device_node = dev->device_node;
+ i2c_at91->adapter.dev.of_node = dev->of_node;
rc = i2c_add_numbered_adapter(&i2c_at91->adapter);
if (rc) {
@@ -565,7 +578,7 @@ out_free:
return rc;
}
-static struct driver_d at91_twi_driver = {
+static struct driver at91_twi_driver = {
.name = "at91-twi",
.probe = at91_twi_probe,
.id_table = at91_twi_devtypes,
diff --git a/drivers/i2c/busses/i2c-bcm283x.c b/drivers/i2c/busses/i2c-bcm283x.c
index 097f73d983..b40918932f 100644
--- a/drivers/i2c/busses/i2c-bcm283x.c
+++ b/drivers/i2c/busses/i2c-bcm283x.c
@@ -74,7 +74,7 @@ static inline struct bcm283x_i2c *to_bcm283x_i2c(struct i2c_adapter *adapter)
static inline int bcm283x_i2c_init(struct bcm283x_i2c *bcm_i2c)
{
- struct device_d *dev = &bcm_i2c->adapter.dev;
+ struct device *dev = bcm_i2c->adapter.dev.parent;
u32 mclk_rate, cdiv, redl, fedl;
/*
@@ -130,7 +130,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c,
{
int ret;
u32 reg_c, reg_s, reg_dlen, timeout;
- struct device_d *dev = &bcm_i2c->adapter.dev;
+ struct device *dev = &bcm_i2c->adapter.dev;
bool msg_read = (msg->flags & I2C_M_RD) > 0;
bool msg_10bit = (msg->flags & I2C_M_TEN) > 0;
u16 buf_pos = 0;
@@ -147,7 +147,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c,
if (ret) {
dev_err(dev, "timeout: 10bit read initilization\n");
- return ret;
+ goto out;
}
if (reg_s & BSC_S_ERR)
goto nack;
@@ -178,7 +178,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c,
if (ret) {
dev_err(dev, "timeout: waiting for data in FIFO\n");
- return ret;
+ goto out;
}
if (reg_s & BSC_S_ERR)
goto nack;
@@ -197,7 +197,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c,
if (ret) {
dev_err(dev, "timeout: waiting for space in FIFO\n");
- return ret;
+ goto out;
}
if (reg_s & BSC_S_ERR)
goto nack;
@@ -216,16 +216,23 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c,
if (ret) {
dev_err(dev, "timeout: waiting for transfer to end\n");
- return ret;
+ goto out;
}
if (reg_s & BSC_S_ERR)
goto nack;
- writel(BSC_S_DONE | BSC_S_ERR | BSC_S_CLKT, &bcm_i2c->regs->s);
- writel(BSC_C_CLEAR1 | BSC_C_I2CEN, &bcm_i2c->regs->c);
- return 0;
+ goto out;
nack:
dev_dbg(dev, "device with addr %x didn't ACK\n", msg->addr);
- return -EREMOTEIO;
+ writel(BSC_S_ERR, &bcm_i2c->regs->s);
+ timeout = calc_byte_timeout_us(bcm_i2c->bitrate);
+ // Wait for end of transfer so BSC has time to send STOP condition
+ readl_poll_timeout(&bcm_i2c->regs->s, reg_s, ~reg_s & BSC_S_TA, timeout);
+ ret = -EREMOTEIO;
+out:
+ // Return to default state for next xfer
+ writel(BSC_S_DONE | BSC_S_ERR | BSC_S_CLKT, &bcm_i2c->regs->s);
+ writel(BSC_C_CLEAR1 | BSC_C_I2CEN, &bcm_i2c->regs->c);
+ return ret;
}
static int bcm283x_i2c_xfer(struct i2c_adapter *adapter,
@@ -259,12 +266,12 @@ out:
return ret;
}
-static int bcm283x_i2c_probe(struct device_d *dev)
+static int bcm283x_i2c_probe(struct device *dev)
{
int ret;
struct resource *iores;
struct bcm283x_i2c *bcm_i2c;
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
bcm_i2c = xzalloc(sizeof(*bcm_i2c));
@@ -301,7 +308,7 @@ static int bcm283x_i2c_probe(struct device_d *dev)
bcm_i2c->adapter.master_xfer = bcm283x_i2c_xfer;
bcm_i2c->adapter.nr = dev->id;
bcm_i2c->adapter.dev.parent = dev;
- bcm_i2c->adapter.dev.device_node = np;
+ bcm_i2c->adapter.dev.of_node = np;
ret = bcm283x_i2c_init(bcm_i2c);
if (ret)
@@ -318,8 +325,9 @@ static struct of_device_id bcm283x_i2c_dt_ids[] = {
{ .compatible = "brcm,bcm2711-i2c", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, bcm283x_i2c_dt_ids);
-static struct driver_d bcm283x_i2c_driver = {
+static struct driver bcm283x_i2c_driver = {
.name = "i2c-bcm283x",
.probe = bcm283x_i2c_probe,
.of_compatible = DRV_OF_COMPAT(bcm283x_i2c_dt_ids),
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 5537efff23..bf9ec30994 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -16,7 +16,7 @@
#include <driver.h>
#include <io.h>
#include <linux/clk.h>
-#include <regmap.h>
+#include <linux/regmap.h>
struct __packed i2c_regs {
u32 control;
@@ -396,9 +396,9 @@ static int cdns_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg,
return nmsgs;
}
-static int cdns_i2c_probe(struct device_d *dev)
+static int cdns_i2c_probe(struct device *dev)
{
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct resource *iores;
struct cdns_i2c *i2c;
u32 bitrate;
@@ -424,7 +424,7 @@ static int cdns_i2c_probe(struct device_d *dev)
i2c->adapter.master_xfer = cdns_i2c_xfer;
i2c->adapter.nr = dev->id;
i2c->adapter.dev.parent = dev;
- i2c->adapter.dev.device_node = np;
+ i2c->adapter.dev.of_node = np;
cdns_i2c_reset_hardware(i2c);
@@ -444,8 +444,9 @@ static const struct of_device_id cdns_i2c_match[] = {
{ .compatible = "cdns,i2c-r1p14" },
{},
};
+MODULE_DEVICE_TABLE(of, cdns_i2c_match);
-static struct driver_d cdns_i2c_driver = {
+static struct driver cdns_i2c_driver = {
.name = "cdns-i2c",
.of_compatible = cdns_i2c_match,
.probe = cdns_i2c_probe,
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index 93b7af6623..152b795c37 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -245,7 +245,7 @@ static void i2c_dw_setup_timings(struct dw_i2c_dev *dw)
u32 ht;
int ret;
- ret = of_property_read_u32(dw->adapter.dev.device_node,
+ ret = of_property_read_u32(dw->adapter.dev.of_node,
"i2c-sda-hold-time-ns", &ht);
if (ret) {
/* Keep previous hold time setting if no one set it */
@@ -504,7 +504,7 @@ static int i2c_dw_xfer(struct i2c_adapter *adapter,
}
-static int i2c_dw_probe(struct device_d *pdev)
+static int i2c_dw_probe(struct device *pdev)
{
struct resource *iores;
struct dw_i2c_dev *dw;
@@ -527,7 +527,7 @@ static int i2c_dw_probe(struct device_d *pdev)
dw->adapter.master_xfer = i2c_dw_xfer;
dw->adapter.nr = pdev->id;
dw->adapter.dev.parent = pdev;
- dw->adapter.dev.device_node = pdev->device_node;
+ dw->adapter.dev.of_node = pdev->of_node;
iores = dev_request_mem_resource(pdev, 0);
if (IS_ERR(iores)) {
@@ -599,8 +599,9 @@ static __maybe_unused struct of_device_id i2c_dw_dt_ids[] = {
{ .compatible = "snps,designware-i2c", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, i2c_dw_dt_ids);
-static struct driver_d i2c_dw_driver = {
+static struct driver i2c_dw_driver = {
.probe = i2c_dw_probe,
.name = "i2c-designware",
.of_compatible = DRV_OF_COMPAT(i2c_dw_dt_ids),
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index ad0c4c8f82..3649c8b189 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -126,7 +126,7 @@ static int of_i2c_gpio_probe(struct device_node *np,
return 0;
}
-static int i2c_gpio_probe(struct device_d *dev)
+static int i2c_gpio_probe(struct device *dev)
{
struct i2c_gpio_private_data *priv;
struct i2c_gpio_platform_data *pdata;
@@ -140,8 +140,8 @@ static int i2c_gpio_probe(struct device_d *dev)
bit_data = &priv->bit_data;
pdata = &priv->pdata;
- if (dev->device_node) {
- ret = of_i2c_gpio_probe(dev->device_node, pdata);
+ if (dev->of_node) {
+ ret = of_i2c_gpio_probe(dev->of_node, pdata);
if (ret)
return ret;
} else {
@@ -193,7 +193,7 @@ static int i2c_gpio_probe(struct device_d *dev)
adap->algo_data = bit_data;
adap->dev.parent = dev;
- adap->dev.device_node = dev->device_node;
+ adap->dev.of_node = dev->of_node;
adap->bus_recovery_info = xzalloc(sizeof(*adap->bus_recovery_info));
adap->bus_recovery_info->scl_gpio = pdata->scl_pin;
adap->bus_recovery_info->sda_gpio = pdata->sda_pin;
@@ -228,8 +228,9 @@ static struct of_device_id i2c_gpio_dt_ids[] = {
{ .compatible = "i2c-gpio", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
-static struct driver_d i2c_gpio_driver = {
+static struct driver i2c_gpio_driver = {
.name = "i2c-gpio",
.probe = i2c_gpio_probe,
.of_compatible = DRV_OF_COMPAT(i2c_gpio_dt_ids),
diff --git a/drivers/i2c/busses/i2c-imx-early.c b/drivers/i2c/busses/i2c-imx-early.c
index a79d7bd88c..1db48a85e5 100644
--- a/drivers/i2c/busses/i2c-imx-early.c
+++ b/drivers/i2c/busses/i2c-imx-early.c
@@ -9,11 +9,12 @@
*/
#include <common.h>
#include <i2c/i2c.h>
-#include <i2c/i2c-early.h>
+#include <pbl/i2c.h>
#include "i2c-imx.h"
struct fsl_i2c {
+ struct pbl_i2c i2c;
void __iomem *regs;
unsigned int i2cr_ien_opcode;
unsigned int i2sr_clr_opcode;
@@ -89,6 +90,26 @@ static int i2c_fsl_acked(struct fsl_i2c *fsl_i2c)
return i2c_fsl_poll_status(fsl_i2c, 0, I2SR_RXAK);
}
+static void i2c_fsl_settle(struct fsl_i2c *fsl_i2c)
+{
+#ifdef CPU_ARCH_ARMv8
+ udelay(100);
+#else
+ /*
+ * We lack udelay on the 32bit i.MX SoCs, so delay manually: On an
+ * i.MX6 with a 66Mhz I2C peripheral clock one cycle of this loop
+ * takes 1.30us. Let's be generous and round up to 100 cycles. Other
+ * i.MX SoCs do not have a higher peripheral clock, so we should be
+ * safe here as well.
+ */
+
+ volatile int i = 0;
+
+ for (i = 0; i < 100; i++)
+ fsl_i2c_read_reg(fsl_i2c, FSL_I2C_I2SR);
+#endif
+}
+
static int i2c_fsl_start(struct fsl_i2c *fsl_i2c)
{
unsigned int temp = 0;
@@ -103,7 +124,7 @@ static int i2c_fsl_start(struct fsl_i2c *fsl_i2c)
fsl_i2c, FSL_I2C_I2CR);
/* Wait controller to be stable */
- udelay(100);
+ i2c_fsl_settle(fsl_i2c);
/* Start I2C transaction */
temp = fsl_i2c_read_reg(fsl_i2c, FSL_I2C_I2CR);
@@ -170,7 +191,7 @@ static int i2c_fsl_write(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg)
/* write data */
for (i = 0; i < msg->len; i++) {
ret = i2c_fsl_send(fsl_i2c, msg->buf[i]);
- if (ret)
+ if (ret)
return ret;
}
@@ -229,9 +250,9 @@ static int i2c_fsl_read(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg)
* If successful returns the number of messages transferred, otherwise a negative
* error code is returned.
*/
-int i2c_fsl_xfer(void *ctx, struct i2c_msg *msgs, int num)
+static int i2c_fsl_xfer(struct pbl_i2c *i2c, struct i2c_msg *msgs, int num)
{
- struct fsl_i2c *fsl_i2c = ctx;
+ struct fsl_i2c *fsl_i2c = container_of(i2c, struct fsl_i2c, i2c);
unsigned int i, temp;
int ret;
@@ -288,7 +309,7 @@ static struct fsl_i2c fsl_i2c;
* This function returns a context pointer suitable to transfer I2C messages
* using i2c_fsl_xfer.
*/
-void *ls1046_i2c_init(void __iomem *regs)
+struct pbl_i2c *ls1046_i2c_init(void __iomem *regs)
{
fsl_i2c.regs = regs;
fsl_i2c.regshift = 0;
@@ -297,10 +318,26 @@ void *ls1046_i2c_init(void __iomem *regs)
/* Divider for ~100kHz when coming from the ROM */
fsl_i2c.ifdr = 0x3e;
- return &fsl_i2c;
+ fsl_i2c.i2c.xfer = i2c_fsl_xfer;
+
+ return &fsl_i2c.i2c;
}
-void *imx8m_i2c_early_init(void __iomem *regs)
+struct pbl_i2c *imx6_i2c_early_init(void __iomem *regs)
+{
+ fsl_i2c.regs = regs;
+ fsl_i2c.regshift = 2;
+ fsl_i2c.i2cr_ien_opcode = I2CR_IEN_OPCODE_1;
+ fsl_i2c.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C;
+ /* Divider for ~100kHz when coming from the ROM */
+ fsl_i2c.ifdr = 0x36;
+
+ fsl_i2c.i2c.xfer = i2c_fsl_xfer;
+
+ return &fsl_i2c.i2c;
+}
+
+struct pbl_i2c *imx8m_i2c_early_init(void __iomem *regs)
{
fsl_i2c.regs = regs;
fsl_i2c.regshift = 2;
@@ -309,5 +346,7 @@ void *imx8m_i2c_early_init(void __iomem *regs)
/* Divider for ~100kHz when coming from the ROM */
fsl_i2c.ifdr = 0x0f;
- return &fsl_i2c;
+ fsl_i2c.i2c.xfer = i2c_fsl_xfer;
+
+ return &fsl_i2c.i2c;
}
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
new file mode 100644
index 0000000000..e32bc4fd18
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This is i.MX low power i2c controller driver.
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <of.h>
+#include <gpio.h>
+#include <malloc.h>
+#include <types.h>
+#include <xfuncs.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <pinctrl.h>
+#include <of_gpio.h>
+#include <of_device.h>
+#include <pbl/i2c.h>
+
+#include <io.h>
+#include <i2c/i2c.h>
+
+#define DRIVER_NAME "imx-lpi2c"
+
+#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
+#define LPI2C_MCR 0x10 /* i2c contrl register */
+#define LPI2C_MSR 0x14 /* i2c status register */
+#define LPI2C_MIER 0x18 /* i2c interrupt enable */
+#define LPI2C_MCFGR0 0x20 /* i2c master configuration */
+#define LPI2C_MCFGR1 0x24 /* i2c master configuration */
+#define LPI2C_MCFGR2 0x28 /* i2c master configuration */
+#define LPI2C_MCFGR3 0x2C /* i2c master configuration */
+#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */
+#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */
+#define LPI2C_MFCR 0x58 /* i2c master FIFO control */
+#define LPI2C_MFSR 0x5C /* i2c master FIFO status */
+#define LPI2C_MTDR 0x60 /* i2c master TX data register */
+#define LPI2C_MRDR 0x70 /* i2c master RX data register */
+
+/* i2c command */
+#define TRAN_DATA 0X00
+#define RECV_DATA 0X01
+#define GEN_STOP 0X02
+#define RECV_DISCARD 0X03
+#define GEN_START 0X04
+#define START_NACK 0X05
+#define START_HIGH 0X06
+#define START_HIGH_NACK 0X07
+
+#define MCR_MEN BIT(0)
+#define MCR_RST BIT(1)
+#define MCR_DOZEN BIT(2)
+#define MCR_DBGEN BIT(3)
+#define MCR_RTF BIT(8)
+#define MCR_RRF BIT(9)
+#define MSR_TDF BIT(0)
+#define MSR_RDF BIT(1)
+#define MSR_SDF BIT(9)
+#define MSR_NDF BIT(10)
+#define MSR_ALF BIT(11)
+#define MSR_MBF BIT(24)
+#define MSR_BBF BIT(25)
+#define MIER_TDIE BIT(0)
+#define MIER_RDIE BIT(1)
+#define MIER_SDIE BIT(9)
+#define MIER_NDIE BIT(10)
+#define MCFGR1_AUTOSTOP BIT(8)
+#define MCFGR1_IGNACK BIT(9)
+#define MRDR_RXEMPTY BIT(14)
+
+#define I2C_CLK_RATIO 2
+#define CHUNK_DATA 256
+
+#define I2C_PM_TIMEOUT 10 /* ms */
+
+enum lpi2c_imx_mode {
+ STANDARD, /* 100+Kbps */
+ FAST, /* 400+Kbps */
+ FAST_PLUS, /* 1.0+Mbps */
+ HS, /* 3.4+Mbps */
+ ULTRA_FAST, /* 5.0+Mbps */
+};
+
+enum lpi2c_imx_pincfg {
+ TWO_PIN_OD,
+ TWO_PIN_OO,
+ TWO_PIN_PP,
+ FOUR_PIN_PP,
+};
+
+struct lpi2c_imx_struct {
+ struct i2c_adapter adapter;
+ struct pbl_i2c pbl_i2c;
+ int num_clks;
+ struct clk_bulk_data *clks;
+ void __iomem *base;
+ __u8 *rx_buf;
+ __u8 *tx_buf;
+ unsigned int msglen;
+ unsigned int delivered;
+ unsigned int bitrate;
+ unsigned int txfifosize;
+ unsigned int rxfifosize;
+ enum lpi2c_imx_mode mode;
+ unsigned long clk_rate;
+};
+
+static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
+ unsigned int enable)
+{
+ writel(enable, lpi2c_imx->base + LPI2C_MIER);
+}
+
+static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp;
+ unsigned int timeout = 500000;
+
+ while (1) {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+ /* check for arbitration lost, clear if set */
+ if (temp & (MSR_ALF | MSR_NDF)) {
+ writel(temp, lpi2c_imx->base + LPI2C_MSR);
+ return -EAGAIN;
+ }
+
+ if (temp & (MSR_BBF | MSR_MBF))
+ break;
+
+ udelay(1);
+ if (!timeout--) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int bitrate = lpi2c_imx->bitrate;
+ enum lpi2c_imx_mode mode;
+
+ if (bitrate < I2C_MAX_FAST_MODE_FREQ)
+ mode = STANDARD;
+ else if (bitrate < I2C_MAX_FAST_MODE_PLUS_FREQ)
+ mode = FAST;
+ else if (bitrate < I2C_MAX_HIGH_SPEED_MODE_FREQ)
+ mode = FAST_PLUS;
+ else if (bitrate < I2C_MAX_ULTRA_FAST_MODE_FREQ)
+ mode = HS;
+ else
+ mode = ULTRA_FAST;
+
+ lpi2c_imx->mode = mode;
+}
+
+static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_RRF | MCR_RTF;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
+
+ temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ return lpi2c_imx_bus_busy(lpi2c_imx);
+}
+
+static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp;
+ unsigned int timeout = 500000;
+
+ writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
+
+ do {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if (temp & MSR_SDF)
+ break;
+
+ udelay(1);
+ if (!timeout--) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
+ break;
+ }
+
+ } while (1);
+}
+
+/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
+static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u8 prescale, filt, sethold, datavd;
+ unsigned int clk_cycle, clkhi, clklo;
+ enum lpi2c_imx_pincfg pincfg;
+ unsigned int temp;
+
+ lpi2c_imx_set_mode(lpi2c_imx);
+
+ if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
+ filt = 0;
+ else
+ filt = 2;
+
+ for (prescale = 0; prescale <= 7; prescale++) {
+ clk_cycle = lpi2c_imx->clk_rate / ((1 << prescale) * lpi2c_imx->bitrate)
+ - 3 - (filt >> 1);
+ clkhi = DIV_ROUND_UP(clk_cycle, I2C_CLK_RATIO + 1);
+ clklo = clk_cycle - clkhi;
+ if (clklo < 64)
+ break;
+ }
+
+ if (prescale > 7)
+ return -EINVAL;
+
+ /* set MCFGR1: PINCFG, PRESCALE, IGNACK */
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ pincfg = TWO_PIN_OO;
+ else
+ pincfg = TWO_PIN_OD;
+ temp = prescale | pincfg << 24;
+
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ temp |= MCFGR1_IGNACK;
+
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR1);
+
+ /* set MCFGR2: FILTSDA, FILTSCL */
+ temp = (filt << 16) | (filt << 24);
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR2);
+
+ /* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */
+ sethold = clkhi;
+ datavd = clkhi >> 1;
+ temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo;
+
+ if (lpi2c_imx->mode == HS)
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR1);
+ else
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR0);
+
+ return 0;
+}
+
+static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp;
+ int ret;
+
+ temp = MCR_RST;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0, lpi2c_imx->base + LPI2C_MCR);
+
+ ret = lpi2c_imx_config(lpi2c_imx);
+ if (ret)
+ return ret;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ return 0;
+}
+
+static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u32 temp;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp &= ~MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ return 0;
+}
+
+static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u32 txcnt;
+ unsigned int timeout = 500000;
+
+ do {
+ txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+ if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
+ return -EIO;
+ }
+
+ udelay(1);
+ if (!timeout--) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ } while (txcnt);
+
+ return 0;
+}
+
+static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ writel(lpi2c_imx->txfifosize >> 1, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp, remaining;
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+ if (remaining > (lpi2c_imx->rxfifosize >> 1))
+ temp = lpi2c_imx->rxfifosize >> 1;
+ else
+ temp = 0;
+
+ writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static int lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int data, remaining;
+ unsigned int timeout = 100000;;
+
+ do {
+ u32 cnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+ if (cnt == lpi2c_imx->txfifosize) {
+ udelay(1);
+ if (!timeout--)
+ return -EIO;
+ continue;
+ }
+
+ data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++];
+
+ writel(data, lpi2c_imx->base + LPI2C_MTDR);
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+ } while (remaining);
+
+ return 0;
+}
+
+static int lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int remaining;
+ unsigned int data;
+ unsigned int timeout = 100000;;
+
+ do {
+ data = readl(lpi2c_imx->base + LPI2C_MRDR);
+ if (data & MRDR_RXEMPTY) {
+ udelay(1);
+ if (!timeout--)
+ return -EIO;
+ continue;
+ }
+
+ lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+ } while (remaining);
+
+ return 0;
+}
+
+static int lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ lpi2c_imx->tx_buf = msgs->buf;
+ lpi2c_imx_set_tx_watermark(lpi2c_imx);
+
+ return lpi2c_imx_write_txfifo(lpi2c_imx);
+}
+
+static int lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+
+ lpi2c_imx->rx_buf = msgs->buf;
+
+ lpi2c_imx_set_rx_watermark(lpi2c_imx);
+ temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
+
+ return lpi2c_imx_read_rxfifo(lpi2c_imx);
+}
+
+static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = container_of(adapter, struct lpi2c_imx_struct, adapter);
+ unsigned int temp;
+ int i, result;
+
+ result = lpi2c_imx_master_enable(lpi2c_imx);
+ if (result)
+ return result;
+
+ for (i = 0; i < num; i++) {
+ result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
+ if (result)
+ goto disable;
+
+ /* quick smbus */
+ if (num == 1 && msgs[0].len == 0)
+ goto stop;
+
+ lpi2c_imx->rx_buf = NULL;
+ lpi2c_imx->tx_buf = NULL;
+ lpi2c_imx->delivered = 0;
+ lpi2c_imx->msglen = msgs[i].len;
+
+ if (msgs[i].flags & I2C_M_RD)
+ result = lpi2c_imx_read(lpi2c_imx, &msgs[i]);
+ else
+ result = lpi2c_imx_write(lpi2c_imx, &msgs[i]);
+
+ if (result)
+ goto stop;
+
+ if (!(msgs[i].flags & I2C_M_RD)) {
+ result = lpi2c_imx_txfifo_empty(lpi2c_imx);
+ if (result)
+ goto stop;
+ }
+ }
+
+stop:
+ lpi2c_imx_stop(lpi2c_imx);
+
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if ((temp & MSR_NDF) && !result)
+ result = -EIO;
+
+disable:
+ lpi2c_imx_master_disable(lpi2c_imx);
+
+ dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+ (result < 0) ? "error" : "success msg",
+ (result < 0) ? result : num);
+
+ return (result < 0) ? result : num;
+}
+
+#ifdef __PBL__
+
+static int lpi2c_pbl_imx_xfer(struct pbl_i2c *lpi2c, struct i2c_msg *msgs, int num)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = container_of(lpi2c, struct lpi2c_imx_struct, pbl_i2c);
+
+ return lpi2c_imx_xfer(&lpi2c_imx->adapter, msgs, num);
+}
+
+struct pbl_i2c *imx93_i2c_early_init(void __iomem *regs)
+{
+ static struct lpi2c_imx_struct lpi2c;
+ u32 temp;
+
+ lpi2c.base = regs;
+
+ temp = readl(lpi2c.base + LPI2C_PARAM);
+ lpi2c.txfifosize = 1 << (temp & 0x0f);
+ lpi2c.rxfifosize = 1 << ((temp >> 8) & 0x0f);
+ lpi2c.bitrate = 100000;
+ lpi2c.clk_rate = 24000000;
+
+ lpi2c.pbl_i2c.xfer = lpi2c_pbl_imx_xfer;
+
+ return &lpi2c.pbl_i2c;
+}
+
+#else
+
+static const struct of_device_id lpi2c_imx_of_match[] = {
+ { .compatible = "fsl,imx7ulp-lpi2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
+
+static int lpi2c_imx_probe(struct device *dev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx;
+ struct resource *iores;
+ unsigned int temp;
+ int ret;
+
+ lpi2c_imx = xzalloc(sizeof(*lpi2c_imx));
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ lpi2c_imx->base = IOMEM(iores->start);
+
+ lpi2c_imx->adapter.nr = -1;
+ lpi2c_imx->adapter.master_xfer = lpi2c_imx_xfer;
+ lpi2c_imx->adapter.dev.parent = dev;
+ lpi2c_imx->adapter.dev.of_node = dev->of_node;
+
+ ret = clk_bulk_get_all(dev, &lpi2c_imx->clks);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "can't get I2C peripheral clock\n");
+ lpi2c_imx->num_clks = ret;
+
+ ret = of_property_read_u32(dev->of_node,
+ "clock-frequency", &lpi2c_imx->bitrate);
+ if (ret)
+ lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
+
+ ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ if (ret)
+ return ret;
+
+ lpi2c_imx->clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
+
+ temp = readl(lpi2c_imx->base + LPI2C_PARAM);
+ lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
+ lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+
+ ret = i2c_add_numbered_adapter(&lpi2c_imx->adapter);
+ if (ret)
+ return ret;
+
+ dev_dbg(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
+
+ return 0;
+}
+
+static struct driver lpi2c_imx_driver = {
+ .probe = lpi2c_imx_probe,
+ .name = "i2c-fsl",
+ .of_compatible = DRV_OF_COMPAT(lpi2c_imx_of_match),
+};
+coredevice_platform_driver(lpi2c_imx_driver);
+
+#endif
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a2abfa5b43..f6a67ec067 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -102,6 +102,7 @@ struct fsl_i2c_hwdata {
struct fsl_i2c_struct {
void __iomem *base;
struct clk *clk;
+ struct device *dev;
struct i2c_adapter adapter;
unsigned int disable_delay;
unsigned int ifdr; /* FSL_I2C_IFDR */
@@ -201,7 +202,7 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
static int i2c_fsl_acked(struct i2c_adapter *adapter)
{
- return i2c_fsl_poll_status(adapter, 1, 0, I2SR_RXAK);
+ return i2c_fsl_poll_status(adapter, 5, 0, I2SR_RXAK);
}
static int i2c_fsl_start(struct i2c_adapter *adapter)
@@ -295,7 +296,7 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
* Translate to dfsr = 5 * Frequency / 100,000,000
*/
dfsr = (5 * (i2c_clk / 1000)) / 100000;
- dev_dbg(&i2c_fsl->adapter.dev,
+ dev_dbg(i2c_fsl->dev,
"<%s> requested speed:%d, i2c_clk:%d\n", __func__,
rate, i2c_clk);
if (!dfsr)
@@ -314,12 +315,12 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
fdr = bin_gb | bin_ga;
rate = i2c_clk / est_div;
- dev_dbg(&i2c_fsl->adapter.dev,
+ dev_dbg(i2c_fsl->dev,
"FDR:0x%.2x, div:%ld, ga:0x%x, gb:0x%x,"
" a:%d, b:%d, speed:%d\n", fdr, est_div,
ga, gb, a, b, rate);
/* Condition 2 not accounted for */
- dev_dbg(&i2c_fsl->adapter.dev,
+ dev_dbg(i2c_fsl->dev,
"Tr <= %d ns\n", (b - 3 * dfsr) *
1000000 / (i2c_clk / 1000));
}
@@ -329,9 +330,9 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
if (a == 24)
a += 4;
}
- dev_dbg(&i2c_fsl->adapter.dev,
+ dev_dbg(i2c_fsl->dev,
"divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
- dev_dbg(&i2c_fsl->adapter.dev, "FDR:0x%.2x, speed:%d\n", fdr, rate);
+ dev_dbg(i2c_fsl->dev, "FDR:0x%.2x, speed:%d\n", fdr, rate);
i2c_fsl->ifdr = fdr;
i2c_fsl->dfsrr = dfsr;
}
@@ -368,9 +369,9 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
(500000U * i2c_clk_div[i].div + (i2c_clk_rate / 2) - 1) /
(i2c_clk_rate / 2);
- dev_dbg(&i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
+ dev_dbg(i2c_fsl->dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
__func__, i2c_clk_rate, div);
- dev_dbg(&i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+ dev_dbg(i2c_fsl->dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
__func__, i2c_clk_div[i].val, i2c_clk_div[i].div);
}
#endif
@@ -525,15 +526,18 @@ static void i2c_fsl_unprepare_recovery(struct i2c_adapter *adapter)
dev_err(adapter->dev.parent, "pinctrl failed: %s\n", strerror(-ret));
}
-static void i2c_fsl_init_recovery(struct fsl_i2c_struct *i2c_fsl, struct device_d *dev)
+static void i2c_fsl_init_recovery(struct fsl_i2c_struct *i2c_fsl,
+ struct device *dev)
{
- if (!dev->device_node)
+ if (!dev->of_node)
return;
- i2c_fsl->rinfo.sda_gpio = of_get_named_gpio_flags(dev->device_node,
- "sda-gpios", 0, NULL);
- i2c_fsl->rinfo.scl_gpio = of_get_named_gpio_flags(dev->device_node,
- "scl-gpios", 0, NULL);
+ i2c_fsl->rinfo.sda_gpio = of_get_named_gpio_flags(dev->of_node,
+ "sda-gpios", 0,
+ NULL);
+ i2c_fsl->rinfo.scl_gpio = of_get_named_gpio_flags(dev->of_node,
+ "scl-gpios", 0,
+ NULL);
if (!gpio_is_valid(i2c_fsl->rinfo.sda_gpio) ||
!gpio_is_valid(i2c_fsl->rinfo.scl_gpio))
@@ -550,7 +554,7 @@ static void i2c_fsl_init_recovery(struct fsl_i2c_struct *i2c_fsl, struct device_
dev_dbg(dev, "initialized recovery info\n");
}
-static int __init i2c_fsl_probe(struct device_d *pdev)
+static int __init i2c_fsl_probe(struct device *pdev)
{
struct resource *iores;
struct fsl_i2c_struct *i2c_fsl;
@@ -561,6 +565,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
pdata = pdev->platform_data;
i2c_fsl = xzalloc(sizeof(*i2c_fsl));
+ i2c_fsl->dev = pdev;
#ifdef CONFIG_COMMON_CLK
i2c_fsl->clk = clk_get(pdev, NULL);
@@ -585,7 +590,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
i2c_fsl->adapter.nr = pdev->id;
i2c_fsl->adapter.dev.parent = pdev;
- i2c_fsl->adapter.dev.device_node = pdev->device_node;
+ i2c_fsl->adapter.dev.of_node = pdev->of_node;
iores = dev_request_mem_resource(pdev, 0);
if (IS_ERR(iores)) {
ret = PTR_ERR(iores);
@@ -599,7 +604,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
/* Set up clock divider */
bitrate = 100000;
- of_property_read_u32(pdev->device_node, "clock-frequency", &bitrate);
+ of_property_read_u32(pdev->of_node, "clock-frequency", &bitrate);
if (pdata && pdata->bitrate)
bitrate = pdata->bitrate;
@@ -645,8 +650,9 @@ static __maybe_unused struct of_device_id imx_i2c_dt_ids[] = {
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx_i2c_dt_ids);
-static struct driver_d i2c_fsl_driver = {
+static struct driver i2c_fsl_driver = {
.probe = i2c_fsl_probe,
.name = "i2c-fsl",
.of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids),
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 765fc9926b..44f1fd4ce6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -495,6 +495,7 @@ static struct of_device_id mv64xxx_i2c_of_match_table[] = {
{ .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
{}
};
+MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
static inline int
mv64xxx_calc_freq(const int tclk, const int n, const int m)
@@ -528,9 +529,9 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
- struct device_d *pd)
+ struct device *pd)
{
- struct device_node *np = pd->device_node;
+ struct device_node *np = pd->of_node;
u32 bus_freq, tclk;
int rc = 0;
u32 prop;
@@ -596,13 +597,13 @@ out:
}
static int
-mv64xxx_i2c_probe(struct device_d *pd)
+mv64xxx_i2c_probe(struct device *pd)
{
struct resource *iores;
struct mv64xxx_i2c_data *drv_data;
int rc;
- if (!pd->device_node)
+ if (!pd->of_node)
return -ENODEV;
drv_data = xzalloc(sizeof(*drv_data));
@@ -625,7 +626,7 @@ mv64xxx_i2c_probe(struct device_d *pd)
drv_data->adapter.master_xfer = mv64xxx_i2c_xfer;
drv_data->adapter.dev.parent = pd;
drv_data->adapter.nr = pd->id;
- drv_data->adapter.dev.device_node = pd->device_node;
+ drv_data->adapter.dev.of_node = pd->of_node;
mv64xxx_i2c_hw_init(drv_data);
@@ -643,7 +644,7 @@ exit_clk:
return rc;
}
-static struct driver_d mv64xxx_i2c_driver = {
+static struct driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.name = "mv64xxx_i2c",
.of_compatible = DRV_OF_COMPAT(mv64xxx_i2c_of_match_table),
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 29a618c8b2..023c9673ba 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -28,8 +28,8 @@
#include <io.h>
#include <i2c/i2c.h>
-#include <mach/generic.h>
-#include <mach/omap3-clock.h>
+#include <mach/omap/generic.h>
+#include <mach/omap/omap3-clock.h>
/* This will be the driver name */
#define DRIVER_NAME "i2c-omap"
@@ -1059,7 +1059,7 @@ static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = {
};
static int __init
-i2c_omap_probe(struct device_d *pdev)
+i2c_omap_probe(struct device *pdev)
{
struct resource *iores;
struct omap_i2c_struct *i2c_omap;
@@ -1091,8 +1091,8 @@ i2c_omap_probe(struct device_d *pdev)
if (pdev->platform_data != NULL) {
speed = *(u32 *)pdev->platform_data;
} else {
- of_property_read_u32(pdev->device_node, "clock-frequency",
- &speed);
+ of_property_read_u32(pdev->of_node, "clock-frequency",
+ &speed);
/* convert DT freq value in Hz into kHz for speed */
speed /= 1000;
}
@@ -1170,7 +1170,7 @@ i2c_omap_probe(struct device_d *pdev)
i2c_omap->adapter.master_xfer = omap_i2c_xfer;
i2c_omap->adapter.nr = pdev->id;
i2c_omap->adapter.dev.parent = pdev;
- i2c_omap->adapter.dev.device_node = pdev->device_node;
+ i2c_omap->adapter.dev.of_node = pdev->of_node;
i2c_omap->adapter.bus_recovery_info = &omap_i2c_bus_recovery_info;
/* i2c device drivers may be active on return from add_adapter() */
@@ -1219,8 +1219,9 @@ static __maybe_unused struct of_device_id omap_i2c_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, omap_i2c_dt_ids);
-static struct driver_d omap_i2c_driver = {
+static struct driver omap_i2c_driver = {
.probe = i2c_omap_probe,
.name = DRIVER_NAME,
.id_table = omap_i2c_ids,
diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
index ca33905335..ce029d148f 100644
--- a/drivers/i2c/busses/i2c-rockchip.c
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -15,7 +15,7 @@
#include <io.h>
#include <linux/clk.h>
#include <mfd/syscon.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <linux/sizes.h>
struct i2c_regs {
@@ -108,7 +108,7 @@ static inline void rk_i2c_get_div(int div, int *divh, int *divl)
*/
static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
{
- struct device_d *dev = i2c->adapter.dev.parent;
+ struct device *dev = i2c->adapter.dev.parent;
uint32_t i2c_rate;
int div, divl, divh;
@@ -130,7 +130,7 @@ static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
static void rk_i2c_show_regs(struct rk_i2c *i2c)
{
- struct device_d *dev = &i2c->adapter.dev;
+ struct device *dev = &i2c->adapter.dev;
struct i2c_regs *regs = i2c->regs;
int i;
@@ -152,7 +152,7 @@ static void rk_i2c_show_regs(struct rk_i2c *i2c)
static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
{
- struct device_d *dev = &i2c->adapter.dev;
+ struct device *dev = &i2c->adapter.dev;
struct i2c_regs *regs = i2c->regs;
u32 val;
int err;
@@ -176,7 +176,7 @@ static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
{
- struct device_d *dev = &i2c->adapter.dev;
+ struct device *dev = &i2c->adapter.dev;
struct i2c_regs *regs = i2c->regs;
u32 val;
int err;
@@ -206,7 +206,7 @@ static inline void rk_i2c_disable(struct rk_i2c *i2c)
static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
- struct device_d *dev = &i2c->adapter.dev;
+ struct device *dev = &i2c->adapter.dev;
struct i2c_regs *regs = i2c->regs;
uchar *pbuf = buf;
uint bytes_remain_len = b_len;
@@ -302,7 +302,7 @@ i2c_exit:
static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
- struct device_d *dev = &i2c->adapter.dev;
+ struct device *dev = &i2c->adapter.dev;
struct i2c_regs *regs = i2c->regs;
u32 val;
int err;
@@ -379,7 +379,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
int nmsgs)
{
struct rk_i2c *i2c = to_rk_i2c(adapter);
- struct device_d *dev = &adapter->dev;
+ struct device *dev = &adapter->dev;
int i, ret = 0;
dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
@@ -408,9 +408,9 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
return ret < 0 ? ret : nmsgs;
}
-static int rk_i2c_probe(struct device_d *dev)
+static int rk_i2c_probe(struct device *dev)
{
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct resource *iores;
struct rk_i2c *i2c;
unsigned bitrate;
@@ -434,7 +434,7 @@ static int rk_i2c_probe(struct device_d *dev)
i2c->adapter.master_xfer = rockchip_i2c_xfer;
i2c->adapter.nr = dev->id;
i2c->adapter.dev.parent = dev;
- i2c->adapter.dev.device_node = np;
+ i2c->adapter.dev.of_node = np;
/* Set up clock divider */
bitrate = 100000;
@@ -452,8 +452,9 @@ static const struct of_device_id rk_i2c_match[] = {
{ .compatible = "rockchip,rk3399-i2c" },
{},
};
+MODULE_DEVICE_TABLE(of, rk_i2c_match);
-static struct driver_d rk_i2c_driver = {
+static struct driver rk_i2c_driver = {
.name = "rk3x-i2c",
.of_compatible = rk_i2c_match,
.probe = rk_i2c_probe,
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
index d412630365..1be52b3dd9 100644
--- a/drivers/i2c/busses/i2c-stm32.c
+++ b/drivers/i2c/busses/i2c-stm32.c
@@ -9,9 +9,11 @@
#include <common.h>
#include <i2c/i2c.h>
#include <init.h>
+#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/reset.h>
+#include <mfd/syscon.h>
/* STM32 I2C registers */
struct __packed stm32_i2c_regs {
@@ -38,6 +40,8 @@ struct __packed stm32_i2c_regs {
/* STM32 I2C control 1 */
#define STM32_I2C_CR1_ANFOFF BIT(12)
+#define STM32_I2C_CR1_DNF_MASK GENMASK(11, 8)
+#define STM32_I2C_CR1_DNF(n) (((n) & 0xf) << 8)
#define STM32_I2C_CR1_ERRIE BIT(7)
#define STM32_I2C_CR1_TCIE BIT(6)
#define STM32_I2C_CR1_STOPIE BIT(5)
@@ -48,7 +52,6 @@ struct __packed stm32_i2c_regs {
#define STM32_I2C_CR1_PE BIT(0)
/* STM32 I2C control 2 */
-#define STM32_I2C_CR2_AUTOEND BIT(25)
#define STM32_I2C_CR2_RELOAD BIT(24)
#define STM32_I2C_CR2_NBYTES_MASK GENMASK(23, 16)
#define STM32_I2C_CR2_NBYTES(n) ((n & 0xff) << 16)
@@ -98,10 +101,8 @@ struct __packed stm32_i2c_regs {
#define STM32_I2C_MAX_LEN 0xff
-#define STM32_I2C_DNF_DEFAULT 0
-#define STM32_I2C_DNF_MAX 16
+#define STM32_I2C_DNF_MAX 15
-#define STM32_I2C_ANALOG_FILTER_ENABLE 1
#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
@@ -119,10 +120,9 @@ struct __packed stm32_i2c_regs {
#define FAST_PLUS_RATE 1000000
enum stm32_i2c_speed {
- STM32_I2C_SPEED_STANDARD, /* 100 kHz */
- STM32_I2C_SPEED_FAST, /* 400 kHz */
- STM32_I2C_SPEED_FAST_PLUS, /* 1 MHz */
- STM32_I2C_SPEED_END,
+ IC_SPEED_MODE_STANDARD,
+ IC_SPEED_MODE_FAST,
+ IC_SPEED_MODE_FAST_PLUS,
};
/**
@@ -154,20 +154,23 @@ struct stm32_i2c_spec {
/**
* struct stm32_i2c_setup - private I2C timing setup parameters
- * @speed: I2C speed mode (standard, Fast Plus)
- * @speed_freq: actual I2C speed frequency (Hz)
* @clock_src: I2C clock source frequency (Hz)
- * @dnf: Digital filter coefficient (0-16)
+ * @timings: I2C timing information
* @analog_filter: Analog filter delay (On/Off)
- * @timings: I2C timings parameters
*/
struct stm32_i2c_setup {
- enum stm32_i2c_speed speed;
- u32 speed_freq;
u32 clock_src;
+ struct i2c_timings timings;
u8 dnf;
bool analog_filter;
- struct i2c_timings timings;
+};
+
+/**
+ * struct stm32_i2c_data - driver data for I2C configuration by compatible
+ * @fmp_clr_offset: Fast Mode Plus clear register offset from set register
+ */
+struct stm32_i2c_data {
+ u32 fmp_clr_offset;
};
/**
@@ -187,8 +190,32 @@ struct stm32_i2c_timings {
u8 scll;
};
+/**
+ * struct stm32_i2c_priv - private data of the controller
+ * @regs: I2C registers address
+ * @clk: hw i2c clock
+ * @setup: I2C timing setup parameters
+ * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+
+ * @regmap: holds SYSCFG phandle for Fast Mode Plus bit
+ * @regmap_sreg: register address for setting Fast Mode Plus bits
+ * @regmap_creg: register address for clearing Fast Mode Plus bits
+ * @regmap_mask: mask for Fast Mode Plus bits
+ */
+struct stm32_i2c_priv {
+ struct stm32_i2c_regs __iomem *regs;
+ struct clk *clk;
+ struct i2c_adapter adapter;
+ struct stm32_i2c_setup setup;
+ u32 speed;
+ struct regmap *regmap;
+ u32 regmap_sreg;
+ u32 regmap_creg;
+ u32 regmap_mask;
+};
+
static const struct stm32_i2c_spec i2c_specs[] = {
- [STM32_I2C_SPEED_STANDARD] = {
+ /* Standard speed - 100 KHz */
+ [IC_SPEED_MODE_STANDARD] = {
.rate = STANDARD_RATE,
.rate_min = 8000,
.rate_max = 120000,
@@ -200,7 +227,8 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 4700,
.h_min = 4000,
},
- [STM32_I2C_SPEED_FAST] = {
+ /* Fast speed - 400 KHz */
+ [IC_SPEED_MODE_FAST] = {
.rate = FAST_RATE,
.rate_min = 320000,
.rate_max = 480000,
@@ -212,7 +240,8 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 1300,
.h_min = 600,
},
- [STM32_I2C_SPEED_FAST_PLUS] = {
+ /* Fast Plus Speed - 1 MHz */
+ [IC_SPEED_MODE_FAST_PLUS] = {
.rate = FAST_PLUS_RATE,
.rate_min = 800000,
.rate_max = 1200000,
@@ -226,22 +255,30 @@ static const struct stm32_i2c_spec i2c_specs[] = {
},
};
-struct stm32_i2c {
- struct stm32_i2c_regs __iomem *regs;
- struct clk *clk;
- struct i2c_adapter adapter;
- struct stm32_i2c_setup setup;
+static const struct stm32_i2c_data stm32f7_data = {
+ .fmp_clr_offset = 0x00,
};
-#define to_stm32_i2c(a) container_of(a, struct stm32_i2c, adapter)
-static inline int stm32_i2c_check_device_busy(struct stm32_i2c *priv)
+static const struct stm32_i2c_data stm32mp15_data = {
+ .fmp_clr_offset = 0x40,
+};
+
+static const struct stm32_i2c_data stm32mp13_data = {
+ .fmp_clr_offset = 0x4,
+};
+
+static inline int stm32_i2c_check_device_busy(struct stm32_i2c_priv *priv)
{
u32 status = readl(&priv->regs->isr);
- return status & STM32_I2C_ISR_BUSY;
+
+ if (status & STM32_I2C_ISR_BUSY)
+ return -EBUSY;
+
+ return 0;
}
-static void stm32_i2c_message_start(struct stm32_i2c *i2c_priv,
- struct i2c_msg *msg, bool stop)
+static void stm32_i2c_message_start(struct stm32_i2c_priv *i2c_priv,
+ struct i2c_msg *msg)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 cr2 = readl(&regs->cr2);
@@ -262,9 +299,8 @@ static void stm32_i2c_message_start(struct stm32_i2c *i2c_priv,
cr2 |= STM32_I2C_CR2_SADD7(msg->addr);
}
- /* Set nb bytes to transfer and reload or autoend bits */
- cr2 &= ~(STM32_I2C_CR2_NBYTES_MASK | STM32_I2C_CR2_RELOAD |
- STM32_I2C_CR2_AUTOEND);
+ /* Set nb bytes to transfer and reload (if needed) */
+ cr2 &= ~(STM32_I2C_CR2_NBYTES_MASK | STM32_I2C_CR2_RELOAD);
if (msg->len > STM32_I2C_MAX_LEN) {
cr2 |= STM32_I2C_CR2_NBYTES(STM32_I2C_MAX_LEN);
cr2 |= STM32_I2C_CR2_RELOAD;
@@ -284,8 +320,8 @@ static void stm32_i2c_message_start(struct stm32_i2c *i2c_priv,
* sent is greater than MAX_LEN
*/
-static void stm32_i2c_handle_reload(struct stm32_i2c *i2c_priv,
- struct i2c_msg *msg, bool stop)
+static void stm32_i2c_handle_reload(struct stm32_i2c_priv *i2c_priv,
+ struct i2c_msg *msg)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 cr2 = readl(&regs->cr2);
@@ -302,7 +338,7 @@ static void stm32_i2c_handle_reload(struct stm32_i2c *i2c_priv,
writel(cr2, &regs->cr2);
}
-static int stm32_i2c_wait_flags(struct stm32_i2c *i2c_priv,
+static int stm32_i2c_wait_flags(struct stm32_i2c_priv *i2c_priv,
u32 flags, u32 *status)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
@@ -311,12 +347,12 @@ static int stm32_i2c_wait_flags(struct stm32_i2c *i2c_priv,
*status & flags, USEC_PER_SEC);
}
-static int stm32_i2c_check_end_of_message(struct stm32_i2c *i2c_priv)
+static int stm32_i2c_check_end_of_message(struct stm32_i2c_priv *i2c_priv)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
u32 mask = STM32_I2C_ISR_ERRORS | STM32_I2C_ISR_NACKF |
STM32_I2C_ISR_STOPF;
- struct device_d *dev = &i2c_priv->adapter.dev;
+ struct device *dev = &i2c_priv->adapter.dev;
u32 status;
int ret;
@@ -362,30 +398,29 @@ static int stm32_i2c_check_end_of_message(struct stm32_i2c *i2c_priv)
setbits_le32(&regs->icr, STM32_I2C_ICR_STOPCF);
/* Clear control register 2 */
- setbits_le32(&regs->cr2, STM32_I2C_CR2_RESET_MASK);
+ clrbits_le32(&regs->cr2, STM32_I2C_CR2_RESET_MASK);
}
return ret;
}
-static int stm32_i2c_message_xfer(struct stm32_i2c *i2c_priv,
+static int stm32_i2c_message_xfer(struct stm32_i2c_priv *i2c_priv,
struct i2c_msg *msg, bool stop)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
- int len = msg->len;
- u8 *buf = msg->buf;
u32 status;
u32 mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
- int bytes_to_rw = min(len, STM32_I2C_MAX_LEN);
+ int bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
+ STM32_I2C_MAX_LEN : msg->len;
int ret = 0;
/* Add errors */
mask |= STM32_I2C_ISR_ERRORS;
- stm32_i2c_message_start(i2c_priv, msg, stop);
+ stm32_i2c_message_start(i2c_priv, msg);
- while (len) {
+ while (msg->len) {
/*
* Wait until TXIS/NACKF/BERR/ARLO flags or
* RXNE/BERR/ARLO flags are set
@@ -398,29 +433,30 @@ static int stm32_i2c_message_xfer(struct stm32_i2c *i2c_priv,
break;
if (status & STM32_I2C_ISR_RXNE) {
- *buf++ = readb(&regs->rxdr);
- len--;
+ *msg->buf++ = readb(&regs->rxdr);
+ msg->len--;
bytes_to_rw--;
}
if (status & STM32_I2C_ISR_TXIS) {
- writeb(*buf++, &regs->txdr);
- len--;
+ writeb(*msg->buf++, &regs->txdr);
+ msg->len--;
bytes_to_rw--;
}
- if (!bytes_to_rw && len) {
+ if (!bytes_to_rw && msg->len) {
/* Wait until TCR flag is set */
mask = STM32_I2C_ISR_TCR;
ret = stm32_i2c_wait_flags(i2c_priv, mask, &status);
if (ret)
break;
- bytes_to_rw = min(len, STM32_I2C_MAX_LEN);
+ bytes_to_rw = msg->len > STM32_I2C_MAX_LEN ?
+ STM32_I2C_MAX_LEN : msg->len;
mask = msg->flags & I2C_M_RD ? STM32_I2C_ISR_RXNE :
STM32_I2C_ISR_TXIS | STM32_I2C_ISR_NACKF;
- stm32_i2c_handle_reload(i2c_priv, msg, stop);
+ stm32_i2c_handle_reload(i2c_priv, msg);
} else if (!bytes_to_rw) {
/* Wait until TC flag is set */
mask = STM32_I2C_ISR_TC;
@@ -434,9 +470,9 @@ static int stm32_i2c_message_xfer(struct stm32_i2c *i2c_priv,
}
}
- /* End of transfer, send stop condition */
- mask = STM32_I2C_CR2_STOP;
- setbits_le32(&regs->cr2, mask);
+ /* End of transfer, send stop condition if appropriate */
+ if (!ret && !(status & (STM32_I2C_ISR_NACKF | STM32_I2C_ISR_ERRORS)))
+ setbits_le32(&regs->cr2, STM32_I2C_CR2_STOP);
return stm32_i2c_check_end_of_message(i2c_priv);
}
@@ -444,16 +480,16 @@ static int stm32_i2c_message_xfer(struct stm32_i2c *i2c_priv,
static int stm32_i2c_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msg, int nmsgs)
{
- struct stm32_i2c *i2c_priv = to_stm32_i2c(adapter);
- int ret;
- int i;
+ struct stm32_i2c_priv *i2c_priv =
+ container_of(adapter, struct stm32_i2c_priv, adapter);
+ int i, ret;
ret = stm32_i2c_check_device_busy(i2c_priv);
if (ret)
- return -EBUSY;
+ return ret;
- for (i = 0; i < nmsgs; i++) {
- ret = stm32_i2c_message_xfer(i2c_priv, &msg[i], i == nmsgs - 1);
+ for (i = nmsgs; i > 0; i--, msg++) {
+ ret = stm32_i2c_message_xfer(i2c_priv, msg, i == 1);
if (ret)
return ret;
}
@@ -461,30 +497,30 @@ static int stm32_i2c_xfer(struct i2c_adapter *adapter,
return nmsgs;
}
-
-static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
+static int stm32_i2c_compute_solutions(u32 i2cclk,
+ struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions)
{
struct stm32_i2c_timings *v;
u32 p_prev = STM32_PRESC_MAX;
- u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->clock_src);
- u32 af_delay_min = 0, af_delay_max = 0;
+ u32 af_delay_min, af_delay_max;
u16 p, l, a;
int sdadel_min, sdadel_max, scldel_min;
int ret = 0;
- if (setup->analog_filter) {
- af_delay_min = STM32_I2C_ANALOG_FILTER_DELAY_MIN;
- af_delay_max = STM32_I2C_ANALOG_FILTER_DELAY_MAX;
- }
+ af_delay_min = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
+ af_delay_max = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
- sdadel_min = i2c_specs[setup->speed].hddat_min + setup->timings.scl_fall_ns -
+ sdadel_min = specs->hddat_min + setup->timings.scl_fall_ns -
af_delay_min - (setup->dnf + 3) * i2cclk;
- sdadel_max = i2c_specs[setup->speed].vddat_max - setup->timings.scl_rise_ns -
+ sdadel_max = specs->vddat_max - setup->timings.scl_rise_ns -
af_delay_max - (setup->dnf + 4) * i2cclk;
- scldel_min = setup->timings.scl_rise_ns + i2c_specs[setup->speed].sudat_min;
+ scldel_min = setup->timings.scl_rise_ns + specs->sudat_min;
if (sdadel_min < 0)
sdadel_min = 0;
@@ -497,13 +533,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
/* Compute possible values for PRESC, SCLDEL and SDADEL */
for (p = 0; p < STM32_PRESC_MAX; p++) {
for (l = 0; l < STM32_SCLDEL_MAX; l++) {
- u32 scldel = (l + 1) * (p + 1) * i2cclk;
+ int scldel = (l + 1) * (p + 1) * i2cclk;
if (scldel < scldel_min)
continue;
for (a = 0; a < STM32_SDADEL_MAX; a++) {
- u32 sdadel = (a * (p + 1) + 1) * i2cclk;
+ int sdadel = (a * (p + 1) + 1) * i2cclk;
if (((sdadel >= sdadel_min) &&
(sdadel <= sdadel_max)) &&
@@ -527,36 +563,40 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
}
}
- if (list_empty(solutions))
+ if (list_empty(solutions)) {
+ pr_err("no Prescaler solution\n");
ret = -EPERM;
+ }
return ret;
}
-static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
+static int stm32_i2c_choose_solution(u32 i2cclk,
+ struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions,
struct stm32_i2c_timings *s)
{
struct stm32_i2c_timings *v;
- u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->speed_freq);
+ u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
+ setup->timings.bus_freq_hz);
u32 clk_error_prev = i2cbus;
- u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->clock_src);
u32 clk_min, clk_max;
- u32 af_delay_min = 0;
+ u32 af_delay_min;
u32 dnf_delay;
u32 tsync;
u16 l, h;
bool sol_found = false;
int ret = 0;
- if (setup->analog_filter)
- af_delay_min = STM32_I2C_ANALOG_FILTER_DELAY_MIN;
+ af_delay_min = setup->analog_filter ?
+ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0;
dnf_delay = setup->dnf * i2cclk;
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
- clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
- clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
+ clk_max = NSEC_PER_SEC / specs->rate_min;
+ clk_min = NSEC_PER_SEC / specs->rate_max;
/*
* Among Prescaler possibilities discovered above figures out SCL Low
@@ -574,7 +614,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
for (l = 0; l < STM32_SCLL_MAX; l++) {
u32 tscl_l = (l + 1) * prescaler + tsync;
- if ((tscl_l < i2c_specs[setup->speed].l_min) ||
+ if (tscl_l < specs->l_min ||
(i2cclk >=
((tscl_l - af_delay_min - dnf_delay) / 4))) {
continue;
@@ -583,16 +623,17 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
for (h = 0; h < STM32_SCLH_MAX; h++) {
u32 tscl_h = (h + 1) * prescaler + tsync;
u32 tscl = tscl_l + tscl_h +
- setup->timings.scl_rise_ns +
- setup->timings.scl_fall_ns;
+ setup->timings.scl_rise_ns + setup->timings.scl_fall_ns;
if ((tscl >= clk_min) && (tscl <= clk_max) &&
- (tscl_h >= i2c_specs[setup->speed].h_min) &&
+ (tscl_h >= specs->h_min) &&
(i2cclk < tscl_h)) {
- int clk_error = tscl - i2cbus;
+ u32 clk_error;
- if (clk_error < 0)
- clk_error = -clk_error;
+ if (tscl > i2cbus)
+ clk_error = tscl - i2cbus;
+ else
+ clk_error = i2cbus - tscl;
if (clk_error < clk_error_prev) {
clk_error_prev = clk_error;
@@ -606,61 +647,68 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
}
}
- if (!sol_found)
+ if (!sol_found) {
+ pr_err("no solution at all\n");
ret = -EPERM;
+ }
return ret;
}
-static int stm32_i2c_compute_timing(struct stm32_i2c *i2c_priv,
- struct stm32_i2c_setup *setup,
+static const struct stm32_i2c_spec *get_specs(u32 rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
+ if (rate <= i2c_specs[i].rate)
+ return &i2c_specs[i];
+
+ /* NOT REACHED */
+ return ERR_PTR(-EINVAL);
+}
+
+static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_timings *output)
{
- struct device_d *dev = &i2c_priv->adapter.dev;
+ struct device *dev = &i2c_priv->adapter.dev;
+ struct stm32_i2c_setup *setup = &i2c_priv->setup;
+ const struct stm32_i2c_spec *specs;
struct stm32_i2c_timings *v, *_v;
struct list_head solutions;
+ u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->clock_src);
int ret;
- if (setup->speed >= STM32_I2C_SPEED_END) {
- dev_err(dev, "speed out of bound {%d/%d}\n",
- setup->speed, STM32_I2C_SPEED_END - 1);
+ specs = get_specs(setup->timings.bus_freq_hz);
+ if (specs == ERR_PTR(-EINVAL)) {
+ dev_err(dev, "speed out of bound {%d}\n",
+ setup->timings.bus_freq_hz);
return -EINVAL;
}
- if ((setup->timings.scl_rise_ns > i2c_specs[setup->speed].rise_max) ||
- (setup->timings.scl_fall_ns > i2c_specs[setup->speed].fall_max)) {
+ if (setup->timings.scl_rise_ns > specs->rise_max ||
+ setup->timings.scl_fall_ns > specs->fall_max) {
dev_err(dev, "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
- setup->timings.scl_rise_ns, i2c_specs[setup->speed].rise_max,
- setup->timings.scl_fall_ns, i2c_specs[setup->speed].fall_max);
+ setup->timings.scl_rise_ns, specs->rise_max,
+ setup->timings.scl_fall_ns, specs->fall_max);
return -EINVAL;
}
+ /* Analog and Digital Filters */
+ setup->dnf = DIV_ROUND_CLOSEST(i2c_priv->setup.timings.digital_filter_width_ns, i2cclk);
if (setup->dnf > STM32_I2C_DNF_MAX) {
dev_err(dev, "DNF out of bound %d/%d\n",
- setup->dnf, STM32_I2C_DNF_MAX);
- return -EINVAL;
- }
-
- if (setup->speed_freq > i2c_specs[setup->speed].rate) {
- dev_err(dev, "Freq {%d/%d}\n",
- setup->speed_freq, i2c_specs[setup->speed].rate);
+ setup->dnf, STM32_I2C_DNF_MAX);
return -EINVAL;
}
INIT_LIST_HEAD(&solutions);
- ret = stm32_i2c_compute_solutions(setup, &solutions);
- if (ret) {
- if (ret == -EPERM)
- dev_err(dev, "No prescaler solution\n");
+ ret = stm32_i2c_compute_solutions(i2cclk, setup, specs, &solutions);
+ if (ret)
goto exit;
- }
- ret = stm32_i2c_choose_solution(setup, &solutions, output);
- if (ret) {
- if (ret == -EPERM)
- dev_err(dev, "no solution at all\n");
+ ret = stm32_i2c_choose_solution(i2cclk, setup, specs, &solutions, output);
+ if (ret)
goto exit;
- }
dev_dbg(dev, "Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n",
output->presc,
@@ -677,16 +725,25 @@ exit:
return ret;
}
-static int stm32_i2c_setup_timing(struct stm32_i2c *i2c_priv,
- enum stm32_i2c_speed speed,
+static u32 get_lower_rate(u32 rate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
+ if (rate > i2c_specs[i].rate)
+ return i2c_specs[i].rate;
+
+ return i2c_specs[0].rate;
+}
+
+static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_timings *timing)
{
- struct device_d *dev = &i2c_priv->adapter.dev;
+ struct device *dev = &i2c_priv->adapter.dev;
struct stm32_i2c_setup *setup = &i2c_priv->setup;
int ret = 0;
- setup->speed = speed;
- setup->speed_freq = i2c_specs[setup->speed].rate;
+ setup->timings.bus_freq_hz = i2c_priv->speed;
setup->clock_src = clk_get_rate(i2c_priv->clk);
if (!setup->clock_src) {
@@ -695,15 +752,14 @@ static int stm32_i2c_setup_timing(struct stm32_i2c *i2c_priv,
}
do {
- ret = stm32_i2c_compute_timing(i2c_priv, setup, timing);
+ ret = stm32_i2c_compute_timing(i2c_priv, timing);
if (ret) {
dev_dbg(dev, "failed to compute I2C timings.\n");
- if (speed > STM32_I2C_SPEED_STANDARD) {
- speed--;
- setup->speed = speed;
- setup->speed_freq = i2c_specs[setup->speed].rate;
+ if (setup->timings.bus_freq_hz > STANDARD_RATE) {
+ setup->timings.bus_freq_hz =
+ get_lower_rate(setup->timings.bus_freq_hz);
dev_dbg(dev, "downgrade I2C Speed Freq to (%i)\n",
- i2c_specs[setup->speed].rate);
+ setup->timings.bus_freq_hz);
} else {
break;
}
@@ -715,31 +771,60 @@ static int stm32_i2c_setup_timing(struct stm32_i2c *i2c_priv,
return ret;
}
- dev_dbg(dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n",
- setup->speed, setup->speed_freq, setup->clock_src);
+ dev_dbg(dev, "I2C Freq(%i), Clk Source(%i)\n",
+ setup->timings.bus_freq_hz, setup->clock_src);
dev_dbg(dev, "I2C Rise(%i) and Fall(%i) Time\n",
- setup->timings.scl_rise_ns, setup->timings.scl_fall_ns);
+ setup->timings.scl_rise_ns, setup->timings.scl_fall_ns);
dev_dbg(dev, "I2C Analog Filter(%s), DNF(%i)\n",
- setup->analog_filter ? "On" : "Off", setup->dnf);
+ setup->analog_filter ? "On" : "Off", setup->dnf);
+
+ i2c_priv->speed = setup->timings.bus_freq_hz;
return 0;
}
-static int stm32_i2c_hw_config(struct stm32_i2c *i2c_priv,
- enum stm32_i2c_speed speed)
+static int stm32_i2c_write_fm_plus_bits(struct stm32_i2c_priv *i2c_priv)
+{
+ int ret;
+ bool enable = i2c_priv->speed > FAST_RATE;
+
+ /* Optional */
+ if (IS_ERR_OR_NULL(i2c_priv->regmap))
+ return 0;
+
+ if (i2c_priv->regmap_sreg == i2c_priv->regmap_creg)
+ ret = regmap_update_bits(i2c_priv->regmap,
+ i2c_priv->regmap_sreg,
+ i2c_priv->regmap_mask,
+ enable ? i2c_priv->regmap_mask : 0);
+ else
+ ret = regmap_write(i2c_priv->regmap,
+ enable ? i2c_priv->regmap_sreg :
+ i2c_priv->regmap_creg,
+ i2c_priv->regmap_mask);
+
+ return ret;
+}
+
+static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv)
{
struct stm32_i2c_regs *regs = i2c_priv->regs;
struct stm32_i2c_timings t;
int ret;
u32 timing = 0;
- ret = stm32_i2c_setup_timing(i2c_priv, speed, &t);
+ ret = stm32_i2c_setup_timing(i2c_priv, &t);
if (ret)
return ret;
/* Disable I2C */
clrbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
+ /* Setup Fast mode plus if necessary */
+ ret = stm32_i2c_write_fm_plus_bits(i2c_priv);
+ if (ret)
+ return ret;
+
/* Timing settings */
timing |= STM32_I2C_TIMINGR_PRESC(t.presc);
timing |= STM32_I2C_TIMINGR_SCLDEL(t.scldel);
@@ -753,44 +838,74 @@ static int stm32_i2c_hw_config(struct stm32_i2c *i2c_priv,
clrbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
else
setbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
+
+ /* Program the Digital Filter */
+ clrsetbits_le32(&regs->cr1, STM32_I2C_CR1_DNF_MASK,
+ STM32_I2C_CR1_DNF(i2c_priv->setup.dnf));
+
setbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
return 0;
}
-static int stm32_i2c_set_bus_speed(struct stm32_i2c *i2c_priv, unsigned speed)
+static int stm32_i2c_set_bus_speed(struct stm32_i2c_priv *i2c_priv, unsigned int speed)
{
- struct device_d *parent_dev = i2c_priv->adapter.dev.parent;
- enum stm32_i2c_speed stm32_speed;
- switch (speed) {
- case STANDARD_RATE:
- stm32_speed = STM32_I2C_SPEED_STANDARD;
- break;
- case FAST_RATE:
- stm32_speed = STM32_I2C_SPEED_FAST;
- break;
- case FAST_PLUS_RATE:
- stm32_speed = STM32_I2C_SPEED_FAST_PLUS;
- break;
- default:
- dev_warn(parent_dev, "Speed %d not supported\n", speed);
+ struct device *dev = &i2c_priv->adapter.dev;
+
+ if (speed > FAST_PLUS_RATE) {
+ dev_dbg(dev, "Speed %d not supported\n", speed);
return -EINVAL;
}
- return stm32_i2c_hw_config(i2c_priv, stm32_speed);
+ i2c_priv->speed = speed;
+
+ return stm32_i2c_hw_config(i2c_priv);
+}
+
+static int stm32_of_to_plat(struct device *dev, struct stm32_i2c_priv *i2c_priv)
+{
+ const struct stm32_i2c_data *data;
+ int ret;
+
+ ret = dev_get_drvdata(dev, (const void **)&data);
+ if (ret)
+ return ret;
+
+ if (of_property_read_u32(dev->of_node, "i2c-digital-filter-width-ns",
+ &i2c_priv->setup.timings.digital_filter_width_ns))
+ i2c_priv->setup.timings.digital_filter_width_ns = 0;
+ if (!of_property_read_bool(dev->of_node, "i2c-digital-filter"))
+ i2c_priv->setup.timings.digital_filter_width_ns = 0;
+
+ i2c_priv->setup.analog_filter =
+ of_property_read_bool(dev->of_node, "i2c-analog-filter");
+
+ /* Optional */
+ i2c_priv->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "st,syscfg-fmp");
+ if (!IS_ERR(i2c_priv->regmap)) {
+ u32 fmp[3];
+
+ ret = of_property_read_u32_array(dev->of_node, "st,syscfg-fmp", fmp, 3);
+ if (ret)
+ return ret;
+
+ i2c_priv->regmap_sreg = fmp[1];
+ i2c_priv->regmap_creg = fmp[1] + data->fmp_clr_offset;
+ i2c_priv->regmap_mask = fmp[2];
+ }
+
+ return 0;
}
-static int __init stm32_i2c_probe(struct device_d *dev)
+static int __init stm32_i2c_probe(struct device *dev)
{
struct resource *iores;
- struct stm32_i2c *stm32_i2c;
+ struct stm32_i2c_priv *stm32_i2c;
struct i2c_platform_data *pdata;
- const struct stm32_i2c_setup *setup;
struct i2c_timings *timings;
int ret;
- pdata = dev->platform_data;
-
stm32_i2c = xzalloc(sizeof(*stm32_i2c));
stm32_i2c->clk = clk_get(dev, NULL);
@@ -798,15 +913,20 @@ static int __init stm32_i2c_probe(struct device_d *dev)
return PTR_ERR(stm32_i2c->clk);
clk_enable(stm32_i2c->clk);
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ stm32_i2c->regs = IOMEM(iores->start);
+
ret = device_reset_us(dev, 2);
if (ret)
return ret;
- ret = dev_get_drvdata(dev, (const void **)&setup);
+ ret = stm32_of_to_plat(dev, stm32_i2c);
if (ret)
return ret;
- stm32_i2c->setup = *setup;
timings = &stm32_i2c->setup.timings;
/* We've our own defaults, so don't use the i2c_parse_fw_timings ones */
@@ -823,13 +943,9 @@ static int __init stm32_i2c_probe(struct device_d *dev)
stm32_i2c->adapter.master_xfer = stm32_i2c_xfer;
stm32_i2c->adapter.nr = dev->id;
stm32_i2c->adapter.dev.parent = dev;
- stm32_i2c->adapter.dev.device_node = dev->device_node;
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
-
- stm32_i2c->regs = IOMEM(iores->start);
+ stm32_i2c->adapter.dev.of_node = dev->of_node;
+ pdata = dev->platform_data;
if (pdata && pdata->bitrate)
timings->bus_freq_hz = pdata->bitrate;
@@ -840,18 +956,15 @@ static int __init stm32_i2c_probe(struct device_d *dev)
return i2c_add_numbered_adapter(&stm32_i2c->adapter);
}
-static const struct stm32_i2c_setup stm32f7_setup = {
- .dnf = STM32_I2C_DNF_DEFAULT,
- .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
-};
-
static __maybe_unused struct of_device_id stm32_i2c_dt_ids[] = {
- { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup, },
- { .compatible = "st,stm32mp15-i2c", .data = &stm32f7_setup},
+ { .compatible = "st,stm32f7-i2c", .data = &stm32f7_data },
+ { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_data },
+ { .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_data },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, stm32_i2c_dt_ids);
-static struct driver_d stm32_i2c_driver = {
+static struct driver stm32_i2c_driver = {
.probe = stm32_i2c_probe,
.name = "stm32f7-i2c",
.of_compatible = DRV_OF_COMPAT(stm32_i2c_dt_ids),
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 077b55e175..f86f64f573 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -137,7 +137,7 @@ struct tegra_i2c_hw_feature {
* @bus_clk_rate: current i2c bus clock rate
*/
struct tegra_i2c_dev {
- struct device_d *dev;
+ struct device *dev;
const struct tegra_i2c_hw_feature *hw;
struct i2c_adapter adapter;
struct clk *div_clk;
@@ -594,7 +594,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.clk_divisor_std_fast_mode = 0x19,
};
-static int tegra_i2c_probe(struct device_d *dev)
+static int tegra_i2c_probe(struct device *dev)
{
struct resource *iores;
struct tegra_i2c_dev *i2c_dev;
@@ -627,14 +627,14 @@ static int tegra_i2c_probe(struct device_d *dev)
return PTR_ERR(i2c_dev->rst);
}
- ret = of_property_read_u32(dev->device_node, "clock-frequency",
+ ret = of_property_read_u32(dev->of_node, "clock-frequency",
&i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
i2c_dev->hw = &tegra20_i2c_hw;
dev_get_drvdata(dev, (const void **)&i2c_dev->hw);
- i2c_dev->is_dvc = of_device_is_compatible(dev->device_node,
+ i2c_dev->is_dvc = of_device_is_compatible(dev->of_node,
"nvidia,tegra20-i2c-dvc");
if (!i2c_dev->hw->has_single_clk_source) {
@@ -655,7 +655,7 @@ static int tegra_i2c_probe(struct device_d *dev)
i2c_dev->adapter.master_xfer = tegra_i2c_xfer;
i2c_dev->adapter.dev.parent = dev;
i2c_dev->adapter.nr = dev->id;
- i2c_dev->adapter.dev.device_node = dev->device_node;
+ i2c_dev->adapter.dev.of_node = dev->of_node;
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
if (ret) {
@@ -683,8 +683,9 @@ static __maybe_unused struct of_device_id tegra_i2c_compatible[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, tegra_i2c_compatible);
-static struct driver_d tegra_i2c_driver = {
+static struct driver tegra_i2c_driver = {
.name = "tegra-i2c",
.probe = tegra_i2c_probe,
.of_compatible = DRV_OF_COMPAT(tegra_i2c_compatible),
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
index ece483f6f5..f508cf1506 100644
--- a/drivers/i2c/busses/i2c-versatile.c
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -63,7 +63,7 @@ static struct i2c_algo_bit_data i2c_versatile_algo = {
.timeout_ms = 100,
};
-static int i2c_versatile_probe(struct device_d *dev)
+static int i2c_versatile_probe(struct device *dev)
{
struct resource *iores;
struct i2c_versatile *i2c;
@@ -86,7 +86,7 @@ static int i2c_versatile_probe(struct device_d *dev)
i2c->adap.algo_data = &i2c->algo;
i2c->adap.dev.parent = dev;
- i2c->adap.dev.device_node = dev->device_node;
+ i2c->adap.dev.of_node = dev->of_node;
i2c->algo = i2c_versatile_algo;
i2c->algo.data = i2c;
@@ -106,8 +106,9 @@ static struct of_device_id i2c_versatile_match[] = {
{ .compatible = "arm,versatile-i2c", },
{},
};
+MODULE_DEVICE_TABLE(of, i2c_versatile_match);
-static struct driver_d i2c_versatile_driver = {
+static struct driver i2c_versatile_driver = {
.name = "versatile-i2c",
.probe = i2c_versatile_probe,
.of_compatible = DRV_OF_COMPAT(i2c_versatile_match),
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 233d231525..6695ec0411 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -31,7 +31,7 @@ struct i2c_mux_priv {
struct i2c_adapter adap;
struct i2c_adapter *parent;
- struct device_d *mux_dev;
+ struct device *mux_dev;
void *mux_priv;
u32 chan_id;
@@ -58,7 +58,7 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
}
struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
- struct device_d *mux_dev,
+ struct device *mux_dev,
void *mux_priv, u32 force_nr, u32 chan_id,
int (*select) (struct i2c_adapter *,
void *, u32),
@@ -95,16 +95,16 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
* Try to populate the mux adapter's device_node, expands to
* nothing if !CONFIG_OFDEVICE.
*/
- if (mux_dev->device_node) {
+ if (mux_dev->of_node) {
struct device_node *child;
u32 reg;
- for_each_child_of_node(mux_dev->device_node, child) {
+ for_each_child_of_node(mux_dev->of_node, child) {
ret = of_property_read_u32(child, "reg", &reg);
if (ret)
continue;
if (chan_id == reg) {
- priv->adap.dev.device_node = child;
+ priv->adap.dev.of_node = child;
break;
}
}
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index b24fd88f5b..5471519045 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -23,6 +23,7 @@
#include <init.h>
#include <of.h>
#include <gpio.h>
+#include <slice.h>
#include <i2c/i2c.h>
@@ -62,6 +63,8 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
uint64_t start;
int ret, try;
+ slice_acquire(&adap->slice);
+
/*
* REVISIT the fault reporting model here is weak:
*
@@ -96,6 +99,8 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
break;
}
+ slice_release(&adap->slice);
+
return ret;
}
EXPORT_SYMBOL(i2c_transfer);
@@ -253,7 +258,7 @@ int i2c_get_sda_gpio_value(struct i2c_adapter *adap)
static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
- struct device_d *dev = &adap->dev;
+ struct device *dev = &adap->dev;
int ret = 0;
ret = gpio_request_one(bri->scl_gpio, GPIOF_IN, "i2c-scl");
@@ -353,13 +358,13 @@ int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
int i2c_recover_bus(struct i2c_adapter *adap)
{
if (!adap->bus_recovery_info)
- return -EOPNOTSUPP;
+ return -EBUSY;
dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
return adap->bus_recovery_info->recover_bus(adap);
}
-static void i2c_info(struct device_d *dev)
+static void i2c_info(struct device *dev)
{
const struct i2c_client *client = to_i2c_client(dev);
@@ -394,7 +399,7 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
client->dev.platform_data = chip->platform_data;
client->dev.id = DEVICE_ID_DYNAMIC;
client->dev.bus = &i2c_bus;
- client->dev.device_node = chip->of_node;
+ client->dev.of_node = chip->of_node;
client->adapter = adapter;
client->addr = chip->addr;
@@ -410,6 +415,9 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
if (chip->of_node)
chip->of_node->dev = &client->dev;
+ dev_dbg(&client->dev, "registered on bus %d, chip->addr 0x%02x\n",
+ adapter->nr, client->addr);
+
return client;
}
@@ -418,37 +426,68 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
struct device_node *n;
/* Only register child devices if the adapter has a node pointer set */
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !adap->dev.device_node)
+ if (!IS_ENABLED(CONFIG_OFDEVICE) || !adap->dev.of_node)
return;
- for_each_available_child_of_node(adap->dev.device_node, n) {
+ for_each_available_child_of_node(adap->dev.of_node, n) {
struct i2c_board_info info = {};
struct i2c_client *result;
const __be32 *addr;
int len;
+ if (n->dev) {
+ dev_dbg(&adap->dev, "of_i2c: skipping already registered %s\n",
+ dev_name(n->dev));
+ continue;
+ }
+
of_modalias_node(n, info.type, I2C_NAME_SIZE);
info.of_node = n;
addr = of_get_property(n, "reg", &len);
if (!addr || (len < sizeof(int))) {
- dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
- n->full_name);
+ dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", n);
continue;
}
info.addr = be32_to_cpup(addr);
if (info.addr > (1 << 10) - 1) {
- dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, n->full_name);
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %pOF\n",
+ info.addr, n);
continue;
}
result = i2c_new_device(adap, &info);
if (!result)
- dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
- n->full_name);
+ dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n",
+ n);
+ }
+}
+
+int of_i2c_register_devices_by_node(struct device_node *node)
+{
+ struct i2c_adapter *adap;
+
+ adap = of_find_i2c_adapter_by_node(node);
+ if (!adap)
+ return -ENODEV;
+ if (IS_ERR(adap))
+ return PTR_ERR(adap);
+
+ of_i2c_register_devices(adap);
+ return 0;
+}
+
+static void i2c_hw_rescan(struct device *dev)
+{
+ struct i2c_adapter *adap;
+
+ list_for_each_entry(adap, &i2c_adapter_list, list) {
+ if (dev != adap->dev.parent)
+ continue;
+ of_i2c_register_devices(adap);
+ break;
}
}
@@ -521,7 +560,6 @@ static void scan_boardinfo(struct i2c_adapter *adapter)
continue;
for (n = bi->n_board_info; n > 0; n--, chip++) {
- debug("%s: bus_num: %d, chip->addr 0x%02x\n", __func__, bi->bus_num, chip->addr);
/*
* NOTE: this relies on i2c_new_device to
* issue diagnostics when given bogus inputs
@@ -555,10 +593,10 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
ret = of_device_ensure_probed(node);
if (ret)
- return ERR_PTR(ret);
+ return NULL;
for_each_i2c_adapter(adap)
- if (adap->dev.device_node == node)
+ if (adap->dev.of_node == node)
return adap;
return NULL;
@@ -566,7 +604,7 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
- struct device_d *dev = of_find_device_by_node(node);
+ struct device *dev = of_find_device_by_node(node);
if (!dev)
return NULL;
@@ -577,12 +615,26 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
return to_i2c_client(dev);
}
-static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val_p,
- u32 def_val, bool use_def)
+int of_i2c_device_enable_and_register_by_alias(const char *alias)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_alias(NULL, alias);
+ if (!np)
+ return -ENODEV;
+
+ of_device_enable(np);
+ return of_i2c_register_devices_by_node(np->parent);
+}
+
+
+static void i2c_parse_timing(struct device *dev, char *prop_name,
+ u32 *cur_val_p,
+ u32 def_val, bool use_def)
{
int ret;
- ret = of_property_read_u32(dev->device_node, prop_name, cur_val_p);
+ ret = of_property_read_u32(dev->of_node, prop_name, cur_val_p);
if (ret && use_def)
*cur_val_p = def_val;
@@ -605,7 +657,8 @@ static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val
* to switch to this function. New drivers almost always should use the defaults.
*/
-void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults)
+void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t,
+ bool use_defaults)
{
bool u = use_defaults;
u32 d;
@@ -649,6 +702,7 @@ EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
*/
int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
{
+ struct device *hw_dev;
int ret;
if (adapter->nr < 0) {
@@ -672,31 +726,26 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
list_add_tail(&adapter->list, &i2c_adapter_list);
+ slice_init(&adapter->slice, dev_name(&adapter->dev));
+
/* populate children from any i2c device tables */
scan_boardinfo(adapter);
of_i2c_register_devices(adapter);
+ hw_dev = adapter->dev.parent;
+ if (hw_dev && dev_of_node(hw_dev)) {
+ if (!hw_dev->rescan)
+ hw_dev->rescan = i2c_hw_rescan;
+ }
+
return 0;
}
EXPORT_SYMBOL(i2c_add_numbered_adapter);
-static int i2c_probe(struct device_d *dev)
-{
- return dev->driver->probe(dev);
-}
-
-static void i2c_remove(struct device_d *dev)
-{
- if (dev->driver->remove)
- dev->driver->remove(dev);
-}
-
struct bus_type i2c_bus = {
.name = "i2c",
.match = device_match_of_modalias,
- .probe = i2c_probe,
- .remove = i2c_remove,
};
static int i2c_bus_init(void)
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index f547527fed..6c21b92860 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -180,7 +180,7 @@ static int pca954x_deselect_chan(struct i2c_adapter *adap,
/*
* I2C init/probing/exit functions
*/
-static int pca954x_probe(struct device_d *dev)
+static int pca954x_probe(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
@@ -199,7 +199,7 @@ static int pca954x_probe(struct device_d *dev)
i2c_set_clientdata(client, data);
- gpio = of_get_named_gpio(dev->device_node, "reset-gpios", 0);
+ gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
if (gpio_is_valid(gpio))
gpio_direction_output(gpio, 1);
@@ -215,7 +215,7 @@ static int pca954x_probe(struct device_d *dev)
if (ret)
goto exit_free;
- idle_disconnect = of_property_read_bool(dev->device_node,
+ idle_disconnect = of_property_read_bool(dev->of_node,
"i2c-mux-idle-disconnect");
data->last_chan = 0; /* force the first selection */
@@ -255,7 +255,7 @@ err:
return ret;
}
-static struct driver_d pca954x_driver = {
+static struct driver pca954x_driver = {
.name = "pca954x",
.probe = pca954x_probe,
.id_table = pca954x_id,