summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-amd-asf-plat.c8
-rw-r--r--drivers/i2c/busses/i2c-axxia.c21
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c13
-rw-r--r--drivers/i2c/busses/i2c-bcm-kona.c6
-rw-r--r--drivers/i2c/busses/i2c-brcmstb.c11
-rw-r--r--drivers/i2c/busses/i2c-cadence.c19
-rw-r--r--drivers/i2c/busses/i2c-designware-amdpsp.c26
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c2
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c28
-rw-r--r--drivers/i2c/busses/i2c-exynos5.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c271
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c14
-rw-r--r--drivers/i2c/busses/i2c-k1.c602
-rw-r--r--drivers/i2c/busses/i2c-kempld.c10
-rw-r--r--drivers/i2c/busses/i2c-mlxbf.c106
-rw-r--r--drivers/i2c/busses/i2c-mt7621.c20
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c12
-rw-r--r--drivers/i2c/busses/i2c-octeon-core.c111
-rw-r--r--drivers/i2c/busses/i2c-omap.c22
-rw-r--r--drivers/i2c/busses/i2c-pasemi-core.c40
-rw-r--r--drivers/i2c/busses/i2c-pxa.c5
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c6
-rw-r--r--drivers/i2c/busses/i2c-qup.c36
-rw-r--r--drivers/i2c/busses/i2c-rzv2m.c15
-rw-r--r--drivers/i2c/i2c-core-of.c1
-rw-r--r--drivers/i2c/i2c-core.h9
-rw-r--r--drivers/i2c/muxes/i2c-mux-ltc4306.c2
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c2
-rw-r--r--drivers/i2c/muxes/i2c-mux-reg.c2
31 files changed, 1000 insertions, 441 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index fc438f445771..83c88c79afe2 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -783,6 +783,23 @@ config I2C_JZ4780
If you don't know what to do here, say N.
+config I2C_K1
+ tristate "SpacemiT K1 I2C adapter"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ depends on OF
+ help
+ This option enables support for the I2C interface on the SpacemiT K1
+ platform.
+
+ If you enable this configuration, the kernel will include support for
+ the I2C adapter specific to the SpacemiT K1 platform. This driver can
+ be used to manage I2C bus transactions, which are necessary for
+ interfacing with I2C peripherals such as sensors, EEPROMs, and other
+ devices.
+
+ This driver can also be built as a module. If so, the
+ module will be called `i2c-k1`.
+
config I2C_KEBA
tristate "KEBA I2C controller support"
depends on HAS_IOMEM
@@ -940,6 +957,7 @@ config I2C_OMAP
tristate "OMAP I2C adapter"
depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
default MACH_OMAP_OSK
+ select MULTIPLEXER
help
If you say yes to this option, support will be included for the
I2C interface on the Texas Instruments OMAP1/2 family of processors.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 1c2a4510abe4..c1252e2b779e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
+obj-$(CONFIG_I2C_K1) += i2c-k1.o
obj-$(CONFIG_I2C_KEBA) += i2c-keba.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c
index 93ebec162c6d..ca45f0f23321 100644
--- a/drivers/i2c/busses/i2c-amd-asf-plat.c
+++ b/drivers/i2c/busses/i2c-amd-asf-plat.c
@@ -69,7 +69,7 @@ static void amd_asf_process_target(struct work_struct *work)
/* Check if no error bits are set in target status register */
if (reg & ASF_ERROR_STATUS) {
/* Set bank as full */
- cmd = 0;
+ cmd = 1;
reg |= GENMASK(3, 2);
outb_p(reg, ASFDATABNKSEL);
} else {
@@ -272,9 +272,9 @@ static u32 amd_asf_func(struct i2c_adapter *adapter)
}
static const struct i2c_algorithm amd_asf_smbus_algorithm = {
- .master_xfer = amd_asf_xfer,
- .reg_slave = amd_asf_reg_target,
- .unreg_slave = amd_asf_unreg_target,
+ .xfer = amd_asf_xfer,
+ .reg_target = amd_asf_reg_target,
+ .unreg_target = amd_asf_unreg_target,
.functionality = amd_asf_func,
};
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 48916cf45ff7..50030256cd85 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -255,11 +255,6 @@ static int i2c_m_rd(const struct i2c_msg *msg)
return (msg->flags & I2C_M_RD) != 0;
}
-static int i2c_m_ten(const struct i2c_msg *msg)
-{
- return (msg->flags & I2C_M_TEN) != 0;
-}
-
static int i2c_m_recv_len(const struct i2c_msg *msg)
{
return (msg->flags & I2C_M_RECV_LEN) != 0;
@@ -439,20 +434,10 @@ static void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
{
u32 addr_1, addr_2;
- if (i2c_m_ten(msg)) {
- /* 10-bit address
- * addr_1: 5'b11110 | addr[9:8] | (R/nW)
- * addr_2: addr[7:0]
- */
- addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06);
- if (i2c_m_rd(msg))
- addr_1 |= 1; /* Set the R/nW bit of the address */
- addr_2 = msg->addr & 0xFF;
+ if (msg->flags & I2C_M_TEN) {
+ addr_1 = i2c_10bit_addr_hi_from_msg(msg);
+ addr_2 = i2c_10bit_addr_lo_from_msg(msg);
} else {
- /* 7-bit address
- * addr_1: addr[6:0] | (R/nW)
- * addr_2: dont care
- */
addr_1 = i2c_8bit_addr_from_msg(msg);
addr_2 = 0;
}
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index 15b632a146e1..332a0fcca28d 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -678,7 +678,7 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
return IRQ_HANDLED;
}
-static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
+static void bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
{
u32 val;
@@ -706,8 +706,6 @@ static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
/* clear all pending interrupts */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, 0xffffffff);
-
- return 0;
}
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
@@ -1081,9 +1079,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
bcm_iproc_algo.unreg_slave = NULL;
}
- ret = bcm_iproc_i2c_init(iproc_i2c);
- if (ret)
- return ret;
+ bcm_iproc_i2c_init(iproc_i2c);
ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
if (ret)
@@ -1162,16 +1158,13 @@ static int bcm_iproc_i2c_suspend(struct device *dev)
static int bcm_iproc_i2c_resume(struct device *dev)
{
struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
- int ret;
u32 val;
/*
* Power domain could have been shut off completely in system deep
* sleep, so re-initialize the block here
*/
- ret = bcm_iproc_i2c_init(iproc_i2c);
- if (ret)
- return ret;
+ bcm_iproc_i2c_init(iproc_i2c);
/* configure to the desired bus speed */
val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET);
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 340fe1305dd9..9d8838bbd938 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -471,12 +471,12 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
if (msg->flags & I2C_M_TEN) {
/* First byte is 11110XX0 where XX is upper 2 bits */
- addr = 0xF0 | ((msg->addr & 0x300) >> 7);
+ addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
/* Second byte is the remaining 8 bits */
- addr = msg->addr & 0xFF;
+ addr = i2c_10bit_addr_lo_from_msg(msg);
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
@@ -486,7 +486,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
return -EREMOTEIO;
/* Then re-send the first byte with the read bit set */
- addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
+ addr = i2c_10bit_addr_hi_from_msg(msg);
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
}
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 00f1a046e985..5fa30e8926c5 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -414,23 +414,22 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
if (msg->flags & I2C_M_TEN) {
/* First byte is 11110XX0 where XX is upper 2 bits */
- addr = 0xF0 | ((msg->addr & 0x300) >> 7);
+ addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD;
bsc_writel(dev, addr, chip_address);
/* Second byte is the remaining 8 bits */
- addr = msg->addr & 0xFF;
+ addr = i2c_10bit_addr_lo_from_msg(msg);
if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
return -EREMOTEIO;
if (msg->flags & I2C_M_RD) {
/* For read, send restart without stop condition */
- brcmstb_set_i2c_start_stop(dev, COND_RESTART
- | COND_NOSTOP);
+ brcmstb_set_i2c_start_stop(dev, COND_RESTART | COND_NOSTOP);
+
/* Then re-send the first byte with the read bit set */
- addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
+ addr = i2c_10bit_addr_hi_from_msg(msg);
if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
return -EREMOTEIO;
-
}
} else {
addr = i2c_8bit_addr_from_msg(msg);
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index b64026fbca66..8df63aaf2a80 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -1541,7 +1541,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
snprintf(id->adap.name, sizeof(id->adap.name),
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
- id->clk = devm_clk_get(&pdev->dev, NULL);
+ id->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(id->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(id->clk),
"input clock not found.\n");
@@ -1551,16 +1551,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(id->reset),
"Failed to request reset.\n");
- ret = clk_prepare_enable(id->clk);
- if (ret)
- dev_err(&pdev->dev, "Unable to enable clock.\n");
-
ret = reset_control_deassert(id->reset);
- if (ret) {
- dev_err_probe(&pdev->dev, ret,
- "Failed to de-assert reset.\n");
- goto err_clk_dis;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to de-assert reset.\n");
pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(id->dev);
@@ -1615,11 +1609,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
err_clk_notifier_unregister:
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
- reset_control_assert(id->reset);
-err_clk_dis:
- clk_disable_unprepare(id->clk);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ reset_control_assert(id->reset);
return ret;
}
@@ -1642,7 +1634,6 @@ static void cdns_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&id->adap);
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
reset_control_assert(id->reset);
- clk_disable_unprepare(id->clk);
}
static struct platform_driver cdns_i2c_drv = {
diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c
index 8fbd2a10c31a..404571ad61a8 100644
--- a/drivers/i2c/busses/i2c-designware-amdpsp.c
+++ b/drivers/i2c/busses/i2c-designware-amdpsp.c
@@ -151,19 +151,16 @@ static void release_bus(void)
static void psp_release_i2c_bus_deferred(struct work_struct *work)
{
- mutex_lock(&psp_i2c_access_mutex);
+ guard(mutex)(&psp_i2c_access_mutex);
/*
* If there is any pending transaction, cannot release the bus here.
* psp_release_i2c_bus() will take care of this later.
*/
if (psp_i2c_access_count)
- goto cleanup;
+ return;
release_bus();
-
-cleanup:
- mutex_unlock(&psp_i2c_access_mutex);
}
static DECLARE_DELAYED_WORK(release_queue, psp_release_i2c_bus_deferred);
@@ -171,11 +168,11 @@ static int psp_acquire_i2c_bus(void)
{
int status;
- mutex_lock(&psp_i2c_access_mutex);
+ guard(mutex)(&psp_i2c_access_mutex);
/* Return early if mailbox malfunctioned */
if (psp_i2c_mbox_fail)
- goto cleanup;
+ return 0;
psp_i2c_access_count++;
@@ -184,11 +181,11 @@ static int psp_acquire_i2c_bus(void)
* reservation period.
*/
if (psp_i2c_sem_acquired)
- goto cleanup;
+ return 0;
status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE);
if (status)
- goto cleanup;
+ return 0;
psp_i2c_sem_acquired = jiffies;
@@ -201,18 +198,16 @@ static int psp_acquire_i2c_bus(void)
* communication with PSP. At any case i2c bus is granted to the caller,
* thus always return success.
*/
-cleanup:
- mutex_unlock(&psp_i2c_access_mutex);
return 0;
}
static void psp_release_i2c_bus(void)
{
- mutex_lock(&psp_i2c_access_mutex);
+ guard(mutex)(&psp_i2c_access_mutex);
/* Return early if mailbox was malfunctioned */
if (psp_i2c_mbox_fail)
- goto cleanup;
+ return;
/*
* If we are last owner of PSP semaphore, need to release arbitration
@@ -220,7 +215,7 @@ static void psp_release_i2c_bus(void)
*/
psp_i2c_access_count--;
if (psp_i2c_access_count)
- goto cleanup;
+ return;
/*
* Send a release command to PSP if the semaphore reservation timeout
@@ -228,9 +223,6 @@ static void psp_release_i2c_bus(void)
*/
if (!delayed_work_pending(&release_queue))
release_bus();
-
-cleanup:
- mutex_unlock(&psp_i2c_access_mutex);
}
/*
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 2569bf1a72e0..c5394229b77f 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -907,7 +907,7 @@ done_nolock:
}
static const struct i2c_algorithm i2c_dw_algo = {
- .master_xfer = i2c_dw_xfer,
+ .xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
};
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 4914bfbee2a9..efdaddf99f9e 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -48,8 +48,6 @@
#define BUS_IDLE_TIMEOUT 20
#define PCH_I2CCTL_I2CMEN 0x0080
-#define TEN_BIT_ADDR_DEFAULT 0xF000
-#define TEN_BIT_ADDR_MASK 0xF0
#define PCH_START 0x0020
#define PCH_RESTART 0x0004
#define PCH_ESR_START 0x0001
@@ -58,7 +56,6 @@
#define PCH_ACK 0x0008
#define PCH_GETACK 0x0001
#define CLR_REG 0x0
-#define I2C_RD 0x1
#define I2CMCF_BIT 0x0080
#define I2CMIF_BIT 0x0002
#define I2CMAL_BIT 0x0010
@@ -76,8 +73,6 @@
#define I2CMBB_BIT 0x0020
#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
I2CBMTO_BIT | I2CBMIS_BIT)
-#define I2C_ADDR_MSK 0xFF
-#define I2C_MSB_2B_MSK 0x300
#define FAST_MODE_CLK 400
#define FAST_MODE_EN 0x0001
#define SUB_ADDR_LEN_MAX 4
@@ -371,16 +366,12 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
u8 *buf;
u32 length;
- u32 addr;
- u32 addr_2_msb;
- u32 addr_8_lsb;
s32 wrcount;
s32 rtn;
void __iomem *p = adap->pch_base_address;
length = msgs->len;
buf = msgs->buf;
- addr = msgs->addr;
/* enable master tx */
pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
@@ -394,8 +385,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
}
if (msgs->flags & I2C_M_TEN) {
- addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
- iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR);
if (first)
pch_i2c_start(adap);
@@ -403,8 +393,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
if (rtn)
return rtn;
- addr_8_lsb = (addr & I2C_ADDR_MSK);
- iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR);
} else {
/* set 7 bit slave address and R/W bit as 0 */
iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
@@ -490,15 +479,11 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
u8 *buf;
u32 count;
u32 length;
- u32 addr;
- u32 addr_2_msb;
- u32 addr_8_lsb;
void __iomem *p = adap->pch_base_address;
s32 rtn;
length = msgs->len;
buf = msgs->buf;
- addr = msgs->addr;
/* enable master reception */
pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
@@ -509,8 +494,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
}
if (msgs->flags & I2C_M_TEN) {
- addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
- iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ iowrite32(i2c_10bit_addr_hi_from_msg(msgs) & ~I2C_M_RD, p + PCH_I2CDR);
if (first)
pch_i2c_start(adap);
@@ -518,8 +502,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
if (rtn)
return rtn;
- addr_8_lsb = (addr & I2C_ADDR_MSK);
- iowrite32(addr_8_lsb, p + PCH_I2CDR);
+ iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR);
pch_i2c_restart(adap);
@@ -527,8 +510,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
if (rtn)
return rtn;
- addr_2_msb |= I2C_RD;
- iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+ iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR);
} else {
/* 7 address bits + R/W bit */
iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index 6cdd957ea7e4..02f24479aa07 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -814,7 +814,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
ret = i2c->state;
/*
- * If this is the last message to be transfered (stop == 1)
+ * If this is the last message to be transferred (stop == 1)
* Then check if the bus can be brought back to idle.
*/
if (ret == 0 && stop)
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 171d29d2770e..48e1af544b75 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -144,6 +144,7 @@
#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */
/* PCI Address Constants */
+#define SMBBAR_MMIO 0
#define SMBBAR 4
#define SMBHSTCFG 0x040
#define TCOBASE 0x050
@@ -276,7 +277,7 @@ struct i801_mux_config {
struct i801_priv {
struct i2c_adapter adapter;
- unsigned long smba;
+ void __iomem *smba;
unsigned char original_hstcfg;
unsigned char original_hstcnt;
unsigned char original_slvcmd;
@@ -337,9 +338,43 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
"\t\t 0x10 don't use interrupts\n"
"\t\t 0x20 disable SMBus Host Notify ");
+/* Wait for BUSY being cleared and either INTR or an error flag being set */
+static int i801_wait_intr(struct i801_priv *priv)
+{
+ unsigned long timeout = jiffies + priv->adapter.timeout;
+ int status, busy;
+
+ do {
+ usleep_range(250, 500);
+ status = ioread8(SMBHSTSTS(priv));
+ busy = status & SMBHSTSTS_HOST_BUSY;
+ status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
+ if (!busy && status)
+ return status & STATUS_ERROR_FLAGS;
+ } while (time_is_after_eq_jiffies(timeout));
+
+ return -ETIMEDOUT;
+}
+
+/* Wait for either BYTE_DONE or an error flag being set */
+static int i801_wait_byte_done(struct i801_priv *priv)
+{
+ unsigned long timeout = jiffies + priv->adapter.timeout;
+ int status;
+
+ do {
+ usleep_range(250, 500);
+ status = ioread8(SMBHSTSTS(priv));
+ if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
+ return status & STATUS_ERROR_FLAGS;
+ } while (time_is_after_eq_jiffies(timeout));
+
+ return -ETIMEDOUT;
+}
+
static int i801_get_block_len(struct i801_priv *priv)
{
- u8 len = inb_p(SMBHSTDAT0(priv));
+ u8 len = ioread8(SMBHSTDAT0(priv));
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
pci_err(priv->pci_dev, "Illegal SMBus block read size %u\n", len);
@@ -356,9 +391,9 @@ static int i801_check_and_clear_pec_error(struct i801_priv *priv)
if (!(priv->features & FEATURE_SMBUS_PEC))
return 0;
- status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+ status = ioread8(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
if (status) {
- outb_p(status, SMBAUXSTS(priv));
+ iowrite8(status, SMBAUXSTS(priv));
return -EBADMSG;
}
@@ -371,7 +406,7 @@ static int i801_check_pre(struct i801_priv *priv)
{
int status, result;
- status = inb_p(SMBHSTSTS(priv));
+ status = ioread8(SMBHSTSTS(priv));
if (status & SMBHSTSTS_HOST_BUSY) {
pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n");
return -EBUSY;
@@ -380,7 +415,7 @@ static int i801_check_pre(struct i801_priv *priv)
status &= STATUS_FLAGS;
if (status) {
pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status);
- outb_p(status, SMBHSTSTS(priv));
+ iowrite8(status, SMBHSTSTS(priv));
}
/*
@@ -406,22 +441,19 @@ static int i801_check_post(struct i801_priv *priv, int status)
*/
if (unlikely(status < 0)) {
/* try to stop the current command */
- outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
- usleep_range(1000, 2000);
- outb_p(0, SMBHSTCNT(priv));
+ iowrite8(SMBHSTCNT_KILL, SMBHSTCNT(priv));
+ status = i801_wait_intr(priv);
+ iowrite8(0, SMBHSTCNT(priv));
/* Check if it worked */
- status = inb_p(SMBHSTSTS(priv));
- if ((status & SMBHSTSTS_HOST_BUSY) ||
- !(status & SMBHSTSTS_FAILED))
- dev_dbg(&priv->pci_dev->dev,
- "Failed terminating the transaction\n");
+ if (status < 0 || !(status & SMBHSTSTS_FAILED))
+ pci_dbg(priv->pci_dev, "Failed terminating the transaction\n");
return -ETIMEDOUT;
}
if (status & SMBHSTSTS_FAILED) {
result = -EIO;
- dev_err(&priv->pci_dev->dev, "Transaction failed\n");
+ pci_err(priv->pci_dev, "Transaction failed\n");
}
if (status & SMBHSTSTS_DEV_ERR) {
/*
@@ -449,46 +481,12 @@ static int i801_check_post(struct i801_priv *priv, int status)
}
if (status & SMBHSTSTS_BUS_ERR) {
result = -EAGAIN;
- dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
+ pci_dbg(priv->pci_dev, "Lost arbitration\n");
}
return result;
}
-/* Wait for BUSY being cleared and either INTR or an error flag being set */
-static int i801_wait_intr(struct i801_priv *priv)
-{
- unsigned long timeout = jiffies + priv->adapter.timeout;
- int status, busy;
-
- do {
- usleep_range(250, 500);
- status = inb_p(SMBHSTSTS(priv));
- busy = status & SMBHSTSTS_HOST_BUSY;
- status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
- if (!busy && status)
- return status & STATUS_ERROR_FLAGS;
- } while (time_is_after_eq_jiffies(timeout));
-
- return -ETIMEDOUT;
-}
-
-/* Wait for either BYTE_DONE or an error flag being set */
-static int i801_wait_byte_done(struct i801_priv *priv)
-{
- unsigned long timeout = jiffies + priv->adapter.timeout;
- int status;
-
- do {
- usleep_range(250, 500);
- status = inb_p(SMBHSTSTS(priv));
- if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
- return status & STATUS_ERROR_FLAGS;
- } while (time_is_after_eq_jiffies(timeout));
-
- return -ETIMEDOUT;
-}
-
static int i801_transaction(struct i801_priv *priv, int xact)
{
unsigned long result;
@@ -496,13 +494,13 @@ static int i801_transaction(struct i801_priv *priv, int xact)
if (priv->features & FEATURE_IRQ) {
reinit_completion(&priv->done);
- outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
+ iowrite8(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
return result ? priv->status : -ETIMEDOUT;
}
- outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
+ iowrite8(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
return i801_wait_intr(priv);
}
@@ -511,7 +509,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
union i2c_smbus_data *data,
char read_write, int command)
{
- int i, len, status, xact;
+ int len, status, xact;
switch (command) {
case I2C_SMBUS_BLOCK_PROC_CALL:
@@ -525,14 +523,13 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
}
/* Set block buffer mode */
- outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
- outb_p(len, SMBHSTDAT0(priv));
- inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
- for (i = 0; i < len; i++)
- outb_p(data->block[i+1], SMBBLKDAT(priv));
+ iowrite8(len, SMBHSTDAT0(priv));
+ ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */
+ iowrite8_rep(SMBBLKDAT(priv), data->block + 1, len);
}
status = i801_transaction(priv, xact);
@@ -548,12 +545,11 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
}
data->block[0] = len;
- inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
- for (i = 0; i < len; i++)
- data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+ ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */
+ ioread8_rep(SMBBLKDAT(priv), data->block + 1, len);
}
out:
- outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
return status;
}
@@ -576,18 +572,17 @@ static void i801_isr_byte_done(struct i801_priv *priv)
/* Read next byte */
if (priv->count < priv->len)
- priv->data[priv->count++] = inb(SMBBLKDAT(priv));
+ priv->data[priv->count++] = ioread8(SMBBLKDAT(priv));
else
- dev_dbg(&priv->pci_dev->dev,
- "Discarding extra byte on block read\n");
+ pci_dbg(priv->pci_dev, "Discarding extra byte on block read\n");
/* Set LAST_BYTE for last byte of read transaction */
if (priv->count == priv->len - 1)
- outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
+ iowrite8(priv->cmd | SMBHSTCNT_LAST_BYTE,
SMBHSTCNT(priv));
} else if (priv->count < priv->len - 1) {
/* Write next byte, except for IRQ after last byte */
- outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
+ iowrite8(priv->data[++priv->count], SMBBLKDAT(priv));
}
}
@@ -595,7 +590,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
{
unsigned short addr;
- addr = inb_p(SMBNTFDADD(priv)) >> 1;
+ addr = ioread8(SMBNTFDADD(priv)) >> 1;
/*
* With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba)
@@ -605,7 +600,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
i2c_handle_smbus_host_notify(&priv->adapter, addr);
/* clear Host Notify bit and return */
- outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+ iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
return IRQ_HANDLED;
}
@@ -636,12 +631,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
return IRQ_NONE;
if (priv->features & FEATURE_HOST_NOTIFY) {
- status = inb_p(SMBSLVSTS(priv));
+ status = ioread8(SMBSLVSTS(priv));
if (status & SMBSLVSTS_HST_NTFY_STS)
return i801_host_notify_isr(priv);
}
- status = inb_p(SMBHSTSTS(priv));
+ status = ioread8(SMBHSTSTS(priv));
if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv);
@@ -651,7 +646,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
* so clear it always when the status is set.
*/
status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS;
- outb_p(status, SMBHSTSTS(priv));
+ iowrite8(status, SMBHSTSTS(priv));
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
if (status) {
@@ -683,8 +678,8 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
- outb_p(len, SMBHSTDAT0(priv));
- outb_p(data->block[1], SMBBLKDAT(priv));
+ iowrite8(len, SMBHSTDAT0(priv));
+ iowrite8(data->block[1], SMBBLKDAT(priv));
}
if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
@@ -703,14 +698,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
priv->data = &data->block[1];
reinit_completion(&priv->done);
- outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
+ iowrite8(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
return result ? priv->status : -ETIMEDOUT;
}
if (len == 1 && read_write == I2C_SMBUS_READ)
smbcmd |= SMBHSTCNT_LAST_BYTE;
- outb_p(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
+ iowrite8(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
for (i = 1; i <= len; i++) {
status = i801_wait_byte_done(priv);
@@ -726,27 +721,27 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
len = i801_get_block_len(priv);
if (len < 0) {
/* Recover */
- while (inb_p(SMBHSTSTS(priv)) &
+ while (ioread8(SMBHSTSTS(priv)) &
SMBHSTSTS_HOST_BUSY)
- outb_p(SMBHSTSTS_BYTE_DONE,
+ iowrite8(SMBHSTSTS_BYTE_DONE,
SMBHSTSTS(priv));
- outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+ iowrite8(SMBHSTSTS_INTR, SMBHSTSTS(priv));
return -EPROTO;
}
data->block[0] = len;
}
if (read_write == I2C_SMBUS_READ) {
- data->block[i] = inb_p(SMBBLKDAT(priv));
+ data->block[i] = ioread8(SMBBLKDAT(priv));
if (i == len - 1)
- outb_p(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
+ iowrite8(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
}
if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
- outb_p(data->block[i+1], SMBBLKDAT(priv));
+ iowrite8(data->block[i+1], SMBBLKDAT(priv));
/* signals SMBBLKDAT ready */
- outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
+ iowrite8(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
return i801_wait_intr(priv);
@@ -754,7 +749,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
{
- outb_p((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
+ iowrite8((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
}
/* Single value transaction function */
@@ -771,30 +766,30 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
case I2C_SMBUS_BYTE:
i801_set_hstadd(priv, addr, read_write);
if (read_write == I2C_SMBUS_WRITE)
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
xact = I801_BYTE;
break;
case I2C_SMBUS_BYTE_DATA:
i801_set_hstadd(priv, addr, read_write);
if (read_write == I2C_SMBUS_WRITE)
- outb_p(data->byte, SMBHSTDAT0(priv));
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(data->byte, SMBHSTDAT0(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
xact = I801_BYTE_DATA;
break;
case I2C_SMBUS_WORD_DATA:
i801_set_hstadd(priv, addr, read_write);
if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ iowrite8(data->word & 0xff, SMBHSTDAT0(priv));
+ iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
}
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
xact = I801_WORD_DATA;
break;
case I2C_SMBUS_PROC_CALL:
i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(data->word & 0xff, SMBHSTDAT0(priv));
+ iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
read_write = I2C_SMBUS_READ;
xact = I801_PROC_CALL;
break;
@@ -810,12 +805,12 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
switch (command) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
- data->byte = inb_p(SMBHSTDAT0(priv));
+ data->byte = ioread8(SMBHSTDAT0(priv));
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
- data->word = inb_p(SMBHSTDAT0(priv)) +
- (inb_p(SMBHSTDAT1(priv)) << 8);
+ data->word = ioread8(SMBHSTDAT0(priv)) +
+ (ioread8(SMBHSTDAT1(priv)) << 8);
break;
}
@@ -836,7 +831,7 @@ static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_
i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
else
i801_set_hstadd(priv, addr, read_write);
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
if (priv->features & FEATURE_BLOCK_BUFFER)
return i801_block_transaction_by_block(priv, data, read_write, command);
@@ -862,9 +857,9 @@ static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_da
/* NB: page 240 of ICH5 datasheet shows that DATA1 is the cmd field when reading */
if (read_write == I2C_SMBUS_READ)
- outb_p(hstcmd, SMBHSTDAT1(priv));
+ iowrite8(hstcmd, SMBHSTDAT1(priv));
else
- outb_p(hstcmd, SMBHSTCMD(priv));
+ iowrite8(hstcmd, SMBHSTCMD(priv));
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
@@ -907,9 +902,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
if (hwpec) /* enable/disable hardware PEC */
- outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+ iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
else
- outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+ iowrite8(ioread8(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
SMBAUXCTL(priv));
if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_BLOCK_PROC_CALL)
@@ -925,13 +920,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
* time, so we forcibly disable it after every transaction.
*/
if (hwpec)
- outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
+ iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
* and clear status flags if not done already.
*/
- outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
+ iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
@@ -968,11 +963,11 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter)
* from the SMB_ALERT signal because the driver does not support
* SMBus Alert.
*/
- outb_p(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
+ iowrite8(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
priv->original_slvcmd, SMBSLVCMD(priv));
/* clear Host Notify bit to allow a new notification */
- outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+ iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
}
static void i801_disable_host_notify(struct i801_priv *priv)
@@ -980,7 +975,7 @@ static void i801_disable_host_notify(struct i801_priv *priv)
if (!(priv->features & FEATURE_HOST_NOTIFY))
return;
- outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
+ iowrite8(priv->original_slvcmd, SMBSLVCMD(priv));
}
static const struct i2c_algorithm smbus_algorithm = {
@@ -1438,14 +1433,14 @@ static void i801_add_tco(struct i801_priv *priv)
priv->tco_pdev = i801_add_tco_spt(pci_dev, tco_res);
if (IS_ERR(priv->tco_pdev))
- dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
+ pci_warn(pci_dev, "failed to create iTCO device\n");
}
#ifdef CONFIG_ACPI
static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
acpi_physical_address address)
{
- return address >= priv->smba &&
+ return address >= pci_resource_start(priv->pci_dev, SMBBAR) &&
address <= pci_resource_end(priv->pci_dev, SMBBAR);
}
@@ -1467,8 +1462,8 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true;
- dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
- dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
+ pci_warn(pdev, "BIOS is accessing SMBus registers\n");
+ pci_warn(pdev, "Driver SMBus register access inhibited\n");
/*
* BIOS is accessing the host controller so prevent it from
@@ -1522,13 +1517,13 @@ static void i801_setup_hstcfg(struct i801_priv *priv)
static void i801_restore_regs(struct i801_priv *priv)
{
- outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
+ iowrite8(priv->original_hstcnt, SMBHSTCNT(priv));
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg);
}
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
- int err, i;
+ int err, i, bar = SMBBAR;
struct i801_priv *priv;
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
@@ -1549,8 +1544,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Disable features on user request */
for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
if (priv->features & disable_features & (1 << i))
- dev_notice(&dev->dev, "%s disabled by user\n",
- i801_feature_names[i]);
+ pci_notice(dev, "%s disabled by user\n", i801_feature_names[i]);
}
priv->features &= ~disable_features;
@@ -1564,48 +1558,46 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
*/
err = pci_enable_device(dev);
if (err) {
- dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
- err);
+ pci_err(dev, "Failed to enable SMBus PCI device (%d)\n", err);
return err;
}
/* Determine the address of the SMBus area */
- priv->smba = pci_resource_start(dev, SMBBAR);
- if (!priv->smba) {
- dev_err(&dev->dev,
- "SMBus base address uninitialized, upgrade BIOS\n");
+ if (!pci_resource_start(dev, SMBBAR)) {
+ pci_err(dev, "SMBus base address uninitialized, upgrade BIOS\n");
return -ENODEV;
}
if (i801_acpi_probe(priv))
return -ENODEV;
- err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME);
- if (err) {
- dev_err(&dev->dev,
- "Failed to request SMBus region 0x%lx-0x%Lx\n",
- priv->smba,
- (unsigned long long)pci_resource_end(dev, SMBBAR));
+ if (pci_resource_flags(dev, SMBBAR_MMIO) & IORESOURCE_MEM)
+ bar = SMBBAR_MMIO;
+
+ priv->smba = pcim_iomap_region(dev, bar, DRV_NAME);
+ if (IS_ERR(priv->smba)) {
+ pci_err(dev, "Failed to request SMBus region %pr\n",
+ pci_resource_n(dev, bar));
i801_acpi_remove(priv);
- return err;
+ return PTR_ERR(priv->smba);
}
- pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
+ pci_read_config_byte(dev, SMBHSTCFG, &priv->original_hstcfg);
i801_setup_hstcfg(priv);
if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
- dev_info(&dev->dev, "Enabling SMBus device\n");
+ pci_info(dev, "Enabling SMBus device\n");
if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) {
- dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+ pci_dbg(dev, "SMBus using interrupt SMI#\n");
/* Disable SMBus interrupt feature if SMBus using SMI# */
priv->features &= ~FEATURE_IRQ;
}
if (priv->original_hstcfg & SMBHSTCFG_SPD_WD)
- dev_info(&dev->dev, "SPD Write Disable is set\n");
+ pci_info(dev, "SPD Write Disable is set\n");
/* Clear special mode bits */
if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
- outb_p(inb_p(SMBAUXCTL(priv)) &
+ iowrite8(ioread8(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
/* Default timeout in interrupt mode: 200 ms */
@@ -1620,7 +1612,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* Complain if an interrupt is already pending */
pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
if (pcists & PCI_STATUS_INTERRUPT)
- dev_warn(&dev->dev, "An interrupt is pending!\n");
+ pci_warn(dev, "An interrupt is pending!\n");
}
if (priv->features & FEATURE_IRQ) {
@@ -1629,12 +1621,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
- dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
- dev->irq, err);
+ pci_err(dev, "Failed to allocate irq %d: %d\n", dev->irq, err);
priv->features &= ~FEATURE_IRQ;
}
}
- dev_info(&dev->dev, "SMBus using %s\n",
+ pci_info(dev, "SMBus using %s\n",
priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
/* Host notification uses an interrupt */
@@ -1642,9 +1633,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->features &= ~FEATURE_HOST_NOTIFY;
/* Remember original Interrupt and Host Notify settings */
- priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
+ priv->original_hstcnt = ioread8(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
if (priv->features & FEATURE_HOST_NOTIFY)
- priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
+ priv->original_slvcmd = ioread8(SMBSLVCMD(priv));
i801_add_tco(priv);
@@ -1653,9 +1644,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
* to instantiante i2c_clients, do not change.
*/
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
- "SMBus %s adapter at %04lx",
+ "SMBus %s adapter at %s",
(priv->features & FEATURE_IDF) ? "I801 IDF" : "I801",
- priv->smba);
+ pci_name(dev));
err = i2c_add_adapter(&priv->adapter);
if (err) {
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index c76c4116ddc7..6bf45d752ff9 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -512,19 +512,17 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
{
volatile struct iic_regs __iomem *iic = dev->vaddr;
- u16 addr = msg->addr;
DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
- addr, msg->flags & I2C_M_TEN ? 10 : 7);
+ msg->addr, msg->flags & I2C_M_TEN ? 10 : 7);
- if (msg->flags & I2C_M_TEN){
+ if (msg->flags & I2C_M_TEN) {
out_8(&iic->cntl, CNTL_AMD);
- out_8(&iic->lmadr, addr);
- out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
- }
- else {
+ out_8(&iic->lmadr, i2c_10bit_addr_lo_from_msg(msg));
+ out_8(&iic->hmadr, i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD);
+ } else {
out_8(&iic->cntl, 0);
- out_8(&iic->lmadr, addr << 1);
+ out_8(&iic->lmadr, i2c_8bit_addr_from_msg(msg) & ~I2C_M_RD);
}
}
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
new file mode 100644
index 000000000000..5965b4cf6220
--- /dev/null
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -0,0 +1,602 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com>
+ */
+
+ #include <linux/clk.h>
+ #include <linux/i2c.h>
+ #include <linux/iopoll.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/platform_device.h>
+
+/* spacemit i2c registers */
+#define SPACEMIT_ICR 0x0 /* Control register */
+#define SPACEMIT_ISR 0x4 /* Status register */
+#define SPACEMIT_IDBR 0xc /* Data buffer register */
+#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
+
+/* SPACEMIT_ICR register fields */
+#define SPACEMIT_CR_START BIT(0) /* start bit */
+#define SPACEMIT_CR_STOP BIT(1) /* stop bit */
+#define SPACEMIT_CR_ACKNAK BIT(2) /* send ACK(0) or NAK(1) */
+#define SPACEMIT_CR_TB BIT(3) /* transfer byte bit */
+/* Bits 4-7 are reserved */
+#define SPACEMIT_CR_MODE_FAST BIT(8) /* bus mode (master operation) */
+/* Bit 9 is reserved */
+#define SPACEMIT_CR_UR BIT(10) /* unit reset */
+/* Bits 11-12 are reserved */
+#define SPACEMIT_CR_SCLE BIT(13) /* master clock enable */
+#define SPACEMIT_CR_IUE BIT(14) /* unit enable */
+/* Bits 15-17 are reserved */
+#define SPACEMIT_CR_ALDIE BIT(18) /* enable arbitration interrupt */
+#define SPACEMIT_CR_DTEIE BIT(19) /* enable TX interrupts */
+#define SPACEMIT_CR_DRFIE BIT(20) /* enable RX interrupts */
+#define SPACEMIT_CR_GCD BIT(21) /* general call disable */
+#define SPACEMIT_CR_BEIE BIT(22) /* enable bus error ints */
+/* Bits 23-24 are reserved */
+#define SPACEMIT_CR_MSDIE BIT(25) /* master STOP detected int enable */
+#define SPACEMIT_CR_MSDE BIT(26) /* master STOP detected enable */
+#define SPACEMIT_CR_TXDONEIE BIT(27) /* transaction done int enable */
+#define SPACEMIT_CR_TXEIE BIT(28) /* transmit FIFO empty int enable */
+#define SPACEMIT_CR_RXHFIE BIT(29) /* receive FIFO half-full int enable */
+#define SPACEMIT_CR_RXFIE BIT(30) /* receive FIFO full int enable */
+#define SPACEMIT_CR_RXOVIE BIT(31) /* receive FIFO overrun int enable */
+
+#define SPACEMIT_I2C_INT_CTRL_MASK (SPACEMIT_CR_ALDIE | SPACEMIT_CR_DTEIE | \
+ SPACEMIT_CR_DRFIE | SPACEMIT_CR_BEIE | \
+ SPACEMIT_CR_TXDONEIE | SPACEMIT_CR_TXEIE | \
+ SPACEMIT_CR_RXHFIE | SPACEMIT_CR_RXFIE | \
+ SPACEMIT_CR_RXOVIE | SPACEMIT_CR_MSDIE)
+
+/* SPACEMIT_ISR register fields */
+/* Bits 0-13 are reserved */
+#define SPACEMIT_SR_ACKNAK BIT(14) /* ACK/NACK status */
+#define SPACEMIT_SR_UB BIT(15) /* unit busy */
+#define SPACEMIT_SR_IBB BIT(16) /* i2c bus busy */
+#define SPACEMIT_SR_EBB BIT(17) /* early bus busy */
+#define SPACEMIT_SR_ALD BIT(18) /* arbitration loss detected */
+#define SPACEMIT_SR_ITE BIT(19) /* TX buffer empty */
+#define SPACEMIT_SR_IRF BIT(20) /* RX buffer full */
+#define SPACEMIT_SR_GCAD BIT(21) /* general call address detected */
+#define SPACEMIT_SR_BED BIT(22) /* bus error no ACK/NAK */
+#define SPACEMIT_SR_SAD BIT(23) /* slave address detected */
+#define SPACEMIT_SR_SSD BIT(24) /* slave stop detected */
+/* Bit 25 is reserved */
+#define SPACEMIT_SR_MSD BIT(26) /* master stop detected */
+#define SPACEMIT_SR_TXDONE BIT(27) /* transaction done */
+#define SPACEMIT_SR_TXE BIT(28) /* TX FIFO empty */
+#define SPACEMIT_SR_RXHF BIT(29) /* RX FIFO half-full */
+#define SPACEMIT_SR_RXF BIT(30) /* RX FIFO full */
+#define SPACEMIT_SR_RXOV BIT(31) /* RX FIFO overrun */
+
+#define SPACEMIT_I2C_INT_STATUS_MASK (SPACEMIT_SR_RXOV | SPACEMIT_SR_RXF | SPACEMIT_SR_RXHF | \
+ SPACEMIT_SR_TXE | SPACEMIT_SR_TXDONE | SPACEMIT_SR_MSD | \
+ SPACEMIT_SR_SSD | SPACEMIT_SR_SAD | SPACEMIT_SR_BED | \
+ SPACEMIT_SR_GCAD | SPACEMIT_SR_IRF | SPACEMIT_SR_ITE | \
+ SPACEMIT_SR_ALD)
+
+/* SPACEMIT_IBMR register fields */
+#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
+#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
+
+/* i2c bus recover timeout: us */
+#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
+
+#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
+#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
+
+#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
+
+enum spacemit_i2c_state {
+ SPACEMIT_STATE_IDLE,
+ SPACEMIT_STATE_START,
+ SPACEMIT_STATE_READ,
+ SPACEMIT_STATE_WRITE,
+};
+
+/* i2c-spacemit driver's main struct */
+struct spacemit_i2c_dev {
+ struct device *dev;
+ struct i2c_adapter adapt;
+
+ /* hardware resources */
+ void __iomem *base;
+ int irq;
+ u32 clock_freq;
+
+ struct i2c_msg *msgs;
+ u32 msg_num;
+
+ /* index of the current message being processed */
+ u32 msg_idx;
+ u8 *msg_buf;
+ /* the number of unprocessed bytes remaining in the current message */
+ u32 unprocessed;
+
+ enum spacemit_i2c_state state;
+ bool read;
+ struct completion complete;
+ u32 status;
+};
+
+static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
+{
+ u32 val;
+
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val |= SPACEMIT_CR_IUE;
+ writel(val, i2c->base + SPACEMIT_ICR);
+}
+
+static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
+{
+ u32 val;
+
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val &= ~SPACEMIT_CR_IUE;
+ writel(val, i2c->base + SPACEMIT_ICR);
+}
+
+static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
+{
+ writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
+ udelay(5);
+ writel(0, i2c->base + SPACEMIT_ICR);
+}
+
+static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
+{
+ dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status);
+
+ if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) {
+ spacemit_i2c_reset(i2c);
+ return -EAGAIN;
+ }
+
+ return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
+}
+
+static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
+{
+ u32 status;
+
+ /* if bus is locked, reset unit. 0: locked */
+ status = readl(i2c->base + SPACEMIT_IBMR);
+ if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL))
+ return;
+
+ spacemit_i2c_reset(i2c);
+ usleep_range(10, 20);
+
+ /* check scl status again */
+ status = readl(i2c->base + SPACEMIT_IBMR);
+ if (!(status & SPACEMIT_BMR_SCL))
+ dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
+}
+
+static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
+{
+ int ret;
+ u32 val;
+
+ val = readl(i2c->base + SPACEMIT_ISR);
+ if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))
+ return 0;
+
+ ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
+ val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
+ 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
+ if (ret)
+ spacemit_i2c_reset(i2c);
+
+ return ret;
+}
+
+static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
+{
+ /* in case bus is not released after transfer completes */
+ if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {
+ spacemit_i2c_conditionally_reset_bus(i2c);
+ usleep_range(90, 150);
+ }
+}
+
+static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
+{
+ u32 val;
+
+ /*
+ * Unmask interrupt bits for all xfer mode:
+ * bus error, arbitration loss detected.
+ * For transaction complete signal, we use master stop
+ * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
+ */
+ val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
+
+ /*
+ * Unmask interrupt bits for interrupt xfer mode:
+ * When IDBR receives a byte, an interrupt is triggered.
+ *
+ * For the tx empty interrupt, it will be enabled in the
+ * i2c_start function.
+ * Otherwise, it will cause an erroneous empty interrupt before i2c_start.
+ */
+ val |= SPACEMIT_CR_DRFIE;
+
+ if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
+ val |= SPACEMIT_CR_MODE_FAST;
+
+ /* disable response to general call */
+ val |= SPACEMIT_CR_GCD;
+
+ /* enable SCL clock output */
+ val |= SPACEMIT_CR_SCLE;
+
+ /* enable master stop detected */
+ val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
+
+ writel(val, i2c->base + SPACEMIT_ICR);
+}
+
+static inline void
+spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
+{
+ writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR);
+}
+
+static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
+{
+ u32 target_addr_rw, val;
+ struct i2c_msg *cur_msg = i2c->msgs + i2c->msg_idx;
+
+ i2c->read = !!(cur_msg->flags & I2C_M_RD);
+
+ i2c->state = SPACEMIT_STATE_START;
+
+ target_addr_rw = (cur_msg->addr & 0x7f) << 1;
+ if (cur_msg->flags & I2C_M_RD)
+ target_addr_rw |= 1;
+
+ writel(target_addr_rw, i2c->base + SPACEMIT_IDBR);
+
+ /* send start pulse */
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val &= ~SPACEMIT_CR_STOP;
+ val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;
+ writel(val, i2c->base + SPACEMIT_ICR);
+}
+
+static void spacemit_i2c_stop(struct spacemit_i2c_dev *i2c)
+{
+ u32 val;
+
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val |= SPACEMIT_CR_STOP | SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
+
+ if (i2c->read)
+ val |= SPACEMIT_CR_ACKNAK;
+
+ writel(val, i2c->base + SPACEMIT_ICR);
+}
+
+static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
+{
+ unsigned long time_left;
+ struct i2c_msg *msg;
+
+ for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) {
+ msg = &i2c->msgs[i2c->msg_idx];
+ i2c->msg_buf = msg->buf;
+ i2c->unprocessed = msg->len;
+ i2c->status = 0;
+
+ reinit_completion(&i2c->complete);
+
+ spacemit_i2c_start(i2c);
+
+ time_left = wait_for_completion_timeout(&i2c->complete,
+ i2c->adapt.timeout);
+ if (!time_left) {
+ dev_err(i2c->dev, "msg completion timeout\n");
+ spacemit_i2c_conditionally_reset_bus(i2c);
+ spacemit_i2c_reset(i2c);
+ return -ETIMEDOUT;
+ }
+
+ if (i2c->status & SPACEMIT_SR_ERR)
+ return spacemit_i2c_handle_err(i2c);
+ }
+
+ return 0;
+}
+
+static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)
+{
+ if (i2c->msg_idx != i2c->msg_num - 1)
+ return false;
+
+ if (i2c->read)
+ return i2c->unprocessed == 1;
+
+ return !i2c->unprocessed;
+}
+
+static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
+{
+ /* if transfer completes, SPACEMIT_ISR will handle it */
+ if (i2c->status & SPACEMIT_SR_MSD)
+ return;
+
+ if (i2c->unprocessed) {
+ writel(*i2c->msg_buf++, i2c->base + SPACEMIT_IDBR);
+ i2c->unprocessed--;
+ return;
+ }
+
+ /* SPACEMIT_STATE_IDLE avoids trigger next byte */
+ i2c->state = SPACEMIT_STATE_IDLE;
+ complete(&i2c->complete);
+}
+
+static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)
+{
+ if (i2c->unprocessed) {
+ *i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR);
+ i2c->unprocessed--;
+ }
+
+ /* if transfer completes, SPACEMIT_ISR will handle it */
+ if (i2c->status & (SPACEMIT_SR_MSD | SPACEMIT_SR_ACKNAK))
+ return;
+
+ /* it has to append stop bit in icr that read last byte */
+ if (i2c->unprocessed)
+ return;
+
+ /* SPACEMIT_STATE_IDLE avoids trigger next byte */
+ i2c->state = SPACEMIT_STATE_IDLE;
+ complete(&i2c->complete);
+}
+
+static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c)
+{
+ i2c->state = i2c->read ? SPACEMIT_STATE_READ : SPACEMIT_STATE_WRITE;
+ if (i2c->state == SPACEMIT_STATE_WRITE)
+ spacemit_i2c_handle_write(i2c);
+}
+
+static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c)
+{
+ u32 val;
+
+ /*
+ * Send transaction complete signal:
+ * error happens, detect master stop
+ */
+ if (!(i2c->status & (SPACEMIT_SR_ERR | SPACEMIT_SR_MSD)))
+ return;
+
+ /*
+ * Here the transaction is already done, we don't need any
+ * other interrupt signals from now, in case any interrupt
+ * happens before spacemit_i2c_xfer to disable irq and i2c unit,
+ * we mask all the interrupt signals and clear the interrupt
+ * status.
+ */
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val &= ~SPACEMIT_I2C_INT_CTRL_MASK;
+ writel(val, i2c->base + SPACEMIT_ICR);
+
+ spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
+
+ i2c->state = SPACEMIT_STATE_IDLE;
+ complete(&i2c->complete);
+}
+
+static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
+{
+ struct spacemit_i2c_dev *i2c = devid;
+ u32 status, val;
+
+ status = readl(i2c->base + SPACEMIT_ISR);
+ if (!status)
+ return IRQ_HANDLED;
+
+ i2c->status = status;
+
+ spacemit_i2c_clear_int_status(i2c, status);
+
+ if (i2c->status & SPACEMIT_SR_ERR)
+ goto err_out;
+
+ val = readl(i2c->base + SPACEMIT_ICR);
+ val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
+ writel(val, i2c->base + SPACEMIT_ICR);
+
+ switch (i2c->state) {
+ case SPACEMIT_STATE_START:
+ spacemit_i2c_handle_start(i2c);
+ break;
+ case SPACEMIT_STATE_READ:
+ spacemit_i2c_handle_read(i2c);
+ break;
+ case SPACEMIT_STATE_WRITE:
+ spacemit_i2c_handle_write(i2c);
+ break;
+ default:
+ break;
+ }
+
+ if (i2c->state != SPACEMIT_STATE_IDLE) {
+ if (spacemit_i2c_is_last_msg(i2c)) {
+ /* trigger next byte with stop */
+ spacemit_i2c_stop(i2c);
+ } else {
+ /* trigger next byte */
+ val |= SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
+ writel(val, i2c->base + SPACEMIT_ICR);
+ }
+ }
+
+err_out:
+ spacemit_i2c_err_check(i2c);
+ return IRQ_HANDLED;
+}
+
+static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)
+{
+ unsigned long timeout;
+ int idx = 0, cnt = 0;
+
+ for (; idx < i2c->msg_num; idx++)
+ cnt += (i2c->msgs + idx)->len + 1;
+
+ /*
+ * Multiply by 9 because each byte in I2C transmission requires
+ * 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit.
+ */
+ timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq;
+
+ i2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num;
+}
+
+static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
+{
+ struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt);
+ int ret;
+
+ i2c->msgs = msgs;
+ i2c->msg_num = num;
+
+ spacemit_i2c_calc_timeout(i2c);
+
+ spacemit_i2c_init(i2c);
+
+ spacemit_i2c_enable(i2c);
+
+ ret = spacemit_i2c_wait_bus_idle(i2c);
+ if (!ret)
+ spacemit_i2c_xfer_msg(i2c);
+ else if (ret < 0)
+ dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
+ else
+ spacemit_i2c_check_bus_release(i2c);
+
+ spacemit_i2c_disable(i2c);
+
+ if (ret == -ETIMEDOUT || ret == -EAGAIN)
+ dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n",
+ ret, i2c->status & SPACEMIT_SR_ERR);
+
+ return ret < 0 ? ret : num;
+}
+
+static u32 spacemit_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm spacemit_i2c_algo = {
+ .xfer = spacemit_i2c_xfer,
+ .functionality = spacemit_i2c_func,
+};
+
+static int spacemit_i2c_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ struct device *dev = &pdev->dev;
+ struct device_node *of_node = pdev->dev.of_node;
+ struct spacemit_i2c_dev *i2c;
+ int ret;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
+ if (ret && ret != -EINVAL)
+ dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
+
+ /* For now, this driver doesn't support high-speed. */
+ if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
+ dev_warn(dev, "unsupported clock frequency %u; using %u\n",
+ i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
+ i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
+ } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
+ dev_warn(dev, "unsupported clock frequency %u; using %u\n",
+ i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
+ i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
+ }
+
+ i2c->dev = &pdev->dev;
+
+ i2c->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(i2c->base))
+ return dev_err_probe(dev, PTR_ERR(i2c->base), "failed to do ioremap");
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ if (i2c->irq < 0)
+ return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
+
+ ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(i2c->dev), i2c);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request irq");
+
+ clk = devm_clk_get_enabled(dev, "func");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
+
+ clk = devm_clk_get_enabled(dev, "bus");
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
+
+ spacemit_i2c_reset(i2c);
+
+ i2c_set_adapdata(&i2c->adapt, i2c);
+ i2c->adapt.owner = THIS_MODULE;
+ i2c->adapt.algo = &spacemit_i2c_algo;
+ i2c->adapt.dev.parent = i2c->dev;
+ i2c->adapt.nr = pdev->id;
+
+ i2c->adapt.dev.of_node = of_node;
+
+ strscpy(i2c->adapt.name, "spacemit-i2c-adapter", sizeof(i2c->adapt.name));
+
+ init_completion(&i2c->complete);
+
+ platform_set_drvdata(pdev, i2c);
+
+ ret = i2c_add_numbered_adapter(&i2c->adapt);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to add i2c adapter");
+
+ return 0;
+}
+
+static void spacemit_i2c_remove(struct platform_device *pdev)
+{
+ struct spacemit_i2c_dev *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adapt);
+}
+
+static const struct of_device_id spacemit_i2c_of_match[] = {
+ { .compatible = "spacemit,k1-i2c", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_i2c_of_match);
+
+static struct platform_driver spacemit_i2c_driver = {
+ .probe = spacemit_i2c_probe,
+ .remove = spacemit_i2c_remove,
+ .driver = {
+ .name = "i2c-k1",
+ .of_match_table = spacemit_i2c_of_match,
+ },
+};
+module_platform_driver(spacemit_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("I2C bus driver for SpacemiT K1 SoC");
diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c
index 212196af68ba..9b4c7cba62b6 100644
--- a/drivers/i2c/busses/i2c-kempld.c
+++ b/drivers/i2c/busses/i2c-kempld.c
@@ -115,9 +115,7 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c)
if (i2c->state == STATE_ADDR) {
/* 10 bit address? */
if (i2c->msg->flags & I2C_M_TEN) {
- addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
- /* Set read bit if necessary */
- addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
+ addr = i2c_10bit_addr_hi_from_msg(msg);
i2c->state = STATE_ADDR10;
} else {
addr = i2c_8bit_addr_from_msg(i2c->msg);
@@ -132,10 +130,12 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c)
/* Second part of 10 bit addressing */
if (i2c->state == STATE_ADDR10) {
- kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
+ addr = i2c_10bit_addr_lo_from_msg(msg);
+ i2c->state = STATE_START;
+
+ kempld_write8(pld, KEMPLD_I2C_DATA, addr);
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
- i2c->state = STATE_START;
return 0;
}
diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c
index 21f67f3b65b6..280dde53d7f3 100644
--- a/drivers/i2c/busses/i2c-mlxbf.c
+++ b/drivers/i2c/busses/i2c-mlxbf.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -495,65 +496,6 @@ static u8 mlxbf_i2c_bus_count;
static struct mutex mlxbf_i2c_bus_lock;
-/*
- * Function to poll a set of bits at a specific address; it checks whether
- * the bits are equal to zero when eq_zero is set to 'true', and not equal
- * to zero when eq_zero is set to 'false'.
- * Note that the timeout is given in microseconds.
- */
-static u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask,
- bool eq_zero, u32 timeout)
-{
- u32 bits;
-
- timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1;
-
- do {
- bits = readl(io + addr) & mask;
- if (eq_zero ? bits == 0 : bits != 0)
- return eq_zero ? 1 : bits;
- udelay(MLXBF_I2C_POLL_FREQ_IN_USEC);
- } while (timeout-- != 0);
-
- return 0;
-}
-
-/*
- * SW must make sure that the SMBus Master GW is idle before starting
- * a transaction. Accordingly, this function polls the Master FSM stop
- * bit; it returns false when the bit is asserted, true if not.
- */
-static bool mlxbf_i2c_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv)
-{
- u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK;
- u32 addr = priv->chip->smbus_master_fsm_off;
- u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT;
-
- if (mlxbf_i2c_poll(priv->mst->io, addr, mask, true, timeout))
- return true;
-
- return false;
-}
-
-/*
- * wait for the lock to be released before acquiring it.
- */
-static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv)
-{
- if (mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW,
- MLXBF_I2C_MASTER_LOCK_BIT, true,
- MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT))
- return true;
-
- return false;
-}
-
-static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv)
-{
- /* Clear the gw to clear the lock */
- writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW);
-}
-
static bool mlxbf_i2c_smbus_transaction_success(u32 master_status,
u32 cause_status)
{
@@ -583,6 +525,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
{
u32 master_status_bits;
u32 cause_status_bits;
+ u32 bits;
/*
* GW busy bit is raised by the driver and cleared by the HW
@@ -591,9 +534,9 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
* then read the cause and master status bits to determine if
* errors occurred during the transaction.
*/
- mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW,
- MLXBF_I2C_MASTER_BUSY_BIT, true,
- MLXBF_I2C_SMBUS_TIMEOUT);
+ readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW,
+ bits, !(bits & MLXBF_I2C_MASTER_BUSY_BIT),
+ MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
/* Read cause status bits. */
cause_status_bits = readl(priv->mst_cause->io +
@@ -740,7 +683,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
u8 read_en, write_en, block_en, pec_en;
u8 slave, flags, addr;
u8 *read_buf;
- int ret = 0;
+ u32 bits;
+ int ret;
if (request->operation_cnt > MLXBF_I2C_SMBUS_MAX_OP_CNT)
return -EINVAL;
@@ -760,11 +704,22 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
* Try to acquire the smbus gw lock before any reads of the GW register since
* a read sets the lock.
*/
- if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv)))
+ ret = readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW,
+ bits, !(bits & MLXBF_I2C_MASTER_LOCK_BIT),
+ MLXBF_I2C_POLL_FREQ_IN_USEC,
+ MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT);
+ if (WARN_ON(ret))
return -EBUSY;
- /* Check whether the HW is idle */
- if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) {
+ /*
+ * SW must make sure that the SMBus Master GW is idle before starting
+ * a transaction. Accordingly, this call polls the Master FSM stop bit;
+ * it returns -ETIMEDOUT when the bit is asserted, 0 if not.
+ */
+ ret = readl_poll_timeout_atomic(priv->mst->io + priv->chip->smbus_master_fsm_off,
+ bits, !(bits & MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK),
+ MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
+ if (WARN_ON(ret)) {
ret = -EBUSY;
goto out_unlock;
}
@@ -855,7 +810,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
}
out_unlock:
- mlxbf_i2c_smbus_master_unlock(priv);
+ /* Clear the gw to clear the lock */
+ writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW);
return ret;
}
@@ -1829,18 +1785,6 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read,
return true;
}
-static bool mlxbf_i2c_slave_wait_for_idle(struct mlxbf_i2c_priv *priv,
- u32 timeout)
-{
- u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL;
- u32 addr = MLXBF_I2C_CAUSE_ARBITER;
-
- if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout))
- return true;
-
- return false;
-}
-
static struct i2c_client *mlxbf_i2c_get_slave_from_addr(
struct mlxbf_i2c_priv *priv, u8 addr)
{
@@ -1943,7 +1887,9 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
* Wait until the transfer is completed; the driver will wait
* until the GW is idle, a cause will rise on fall of GW busy.
*/
- mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
+ readl_poll_timeout_atomic(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER,
+ data32, data32 & MLXBF_I2C_CAUSE_S_GW_BUSY_FALL,
+ MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
clear_csr:
/* Release the Slave GW. */
diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c
index 2103f21f9ddd..0a288c998419 100644
--- a/drivers/i2c/busses/i2c-mt7621.c
+++ b/drivers/i2c/busses/i2c-mt7621.c
@@ -164,22 +164,18 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
/* write address */
if (pmsg->flags & I2C_M_TEN) {
/* 10 bits address */
- addr = 0xf0 | ((pmsg->addr >> 7) & 0x06);
- addr |= (pmsg->addr & 0xff) << 8;
- if (pmsg->flags & I2C_M_RD)
- addr |= 1;
- iowrite32(addr, i2c->base + REG_SM0D0_REG);
- ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, 2);
- if (ret)
- goto err_timeout;
+ addr = i2c_10bit_addr_hi_from_msg(pmsg);
+ addr |= i2c_10bit_addr_lo_from_msg(pmsg) << 8;
+ len = 2;
} else {
/* 7 bits address */
addr = i2c_8bit_addr_from_msg(pmsg);
- iowrite32(addr, i2c->base + REG_SM0D0_REG);
- ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, 1);
- if (ret)
- goto err_timeout;
+ len = 1;
}
+ iowrite32(addr, i2c->base + REG_SM0D0_REG);
+ ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, len);
+ if (ret)
+ goto err_timeout;
/* check address ACK */
if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 874309580c33..8fc26a511320 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -27,7 +27,6 @@
#include <linux/err.h>
#include <linux/delay.h>
-#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
@@ -176,22 +175,17 @@ static void
mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
struct i2c_msg *msg)
{
- u32 dir = 0;
-
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
MV64XXX_I2C_REG_CONTROL_TWSIEN;
if (!drv_data->atomic)
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN;
- if (msg->flags & I2C_M_RD)
- dir = 1;
-
if (msg->flags & I2C_M_TEN) {
- drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
- drv_data->addr2 = (u32)msg->addr & 0xff;
+ drv_data->addr1 = i2c_10bit_addr_hi_from_msg(msg);
+ drv_data->addr2 = i2c_10bit_addr_lo_from_msg(msg);
} else {
- drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir;
+ drv_data->addr1 = i2c_8bit_addr_from_msg(msg);
drv_data->addr2 = 0;
}
}
diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c
index 16cc34a0526e..baf6b27f3752 100644
--- a/drivers/i2c/busses/i2c-octeon-core.c
+++ b/drivers/i2c/busses/i2c-octeon-core.c
@@ -45,7 +45,7 @@ static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
* octeon_i2c_wait - wait for the IFLG to be set
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_wait(struct octeon_i2c *i2c)
{
@@ -139,7 +139,7 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
* octeon_i2c_hlc_wait - wait for an HLC operation to complete
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise -ETIMEDOUT.
+ * Returns: 0 on success, otherwise -ETIMEDOUT.
*/
static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
{
@@ -273,7 +273,7 @@ static int octeon_i2c_recovery(struct octeon_i2c *i2c)
* octeon_i2c_start - send START to the bus
* @i2c: The struct octeon_i2c
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_start(struct octeon_i2c *i2c)
{
@@ -314,7 +314,7 @@ static void octeon_i2c_stop(struct octeon_i2c *i2c)
*
* The address is sent over the bus, then the data is read.
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
u8 *data, u16 *rlength, bool recv_len)
@@ -382,7 +382,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
*
* The address is sent over the bus, then the data.
*
- * Returns 0 on success, otherwise a negative errno.
+ * Returns: 0 on success, otherwise a negative errno.
*/
static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
const u8 *data, int length)
@@ -421,17 +421,12 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
octeon_i2c_hlc_enable(i2c);
octeon_i2c_hlc_int_clear(i2c);
- cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7;
/* SIZE */
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10;
- else
- cmd |= SW_TWSI_OP_7;
-
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
ret = octeon_i2c_hlc_wait(i2c);
if (ret)
@@ -463,17 +458,12 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
octeon_i2c_hlc_enable(i2c);
octeon_i2c_hlc_int_clear(i2c);
- cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7;
/* SIZE */
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10;
- else
- cmd |= SW_TWSI_OP_7;
-
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
cmd |= (u64)msgs[0].buf[j] << (8 * i);
@@ -498,6 +488,45 @@ err:
return ret;
}
+/* Process hlc transaction */
+static int octeon_i2c_hlc_cmd_send(struct octeon_i2c *i2c, u64 cmd)
+{
+ octeon_i2c_hlc_int_clear(i2c);
+ octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
+
+ return octeon_i2c_hlc_wait(i2c);
+}
+
+/* Generic consideration for extended internal addresses in i2c hlc r/w ops */
+static bool octeon_i2c_hlc_ext(struct octeon_i2c *i2c, struct i2c_msg msg, u64 *cmd_in, u64 *ext)
+{
+ bool set_ext = false;
+ u64 cmd = 0;
+
+ if (msg.len == 2) {
+ cmd |= SW_TWSI_EIA;
+ *ext = (u64)msg.buf[0] << SW_TWSI_IA_SHIFT;
+ cmd |= (u64)msg.buf[1] << SW_TWSI_IA_SHIFT;
+ set_ext = true;
+ } else {
+ cmd |= (u64)msg.buf[0] << SW_TWSI_IA_SHIFT;
+ }
+
+ *cmd_in |= cmd;
+ return set_ext;
+}
+
+/* Construct and send i2c transaction core cmd for read ops */
+static int octeon_i2c_hlc_read_cmd(struct octeon_i2c *i2c, struct i2c_msg msg, u64 cmd)
+{
+ u64 ext = 0;
+
+ if (octeon_i2c_hlc_ext(i2c, msg, &cmd, &ext))
+ octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
+
+ return octeon_i2c_hlc_cmd_send(i2c, cmd);
+}
+
/* high-level-controller composite write+read, msg0=addr, msg1=data */
static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
{
@@ -506,32 +535,14 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
octeon_i2c_hlc_enable(i2c);
- cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
/* SIZE */
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10_IA;
- else
- cmd |= SW_TWSI_OP_7_IA;
-
- if (msgs[0].len == 2) {
- u64 ext = 0;
-
- cmd |= SW_TWSI_EIA;
- ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
- cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
- octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
- } else {
- cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
- }
-
- octeon_i2c_hlc_int_clear(i2c);
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
-
- ret = octeon_i2c_hlc_wait(i2c);
+ /* Send core command */
+ ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd);
if (ret)
goto err;
@@ -561,25 +572,14 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
octeon_i2c_hlc_enable(i2c);
- cmd = SW_TWSI_V | SW_TWSI_SOVR;
+ cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
/* SIZE */
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
/* A */
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
- if (msgs[0].flags & I2C_M_TEN)
- cmd |= SW_TWSI_OP_10_IA;
- else
- cmd |= SW_TWSI_OP_7_IA;
-
- if (msgs[0].len == 2) {
- cmd |= SW_TWSI_EIA;
- ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
- set_ext = true;
- cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
- } else {
- cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
- }
+ /* Set parameters for extended message (if required) */
+ set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext);
for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--)
cmd |= (u64)msgs[1].buf[j] << (8 * i);
@@ -592,10 +592,7 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
if (set_ext)
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
- octeon_i2c_hlc_int_clear(i2c);
- octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
-
- ret = octeon_i2c_hlc_wait(i2c);
+ ret = octeon_i2c_hlc_cmd_send(i2c, cmd);
if (ret)
goto err;
@@ -613,7 +610,7 @@ err:
* @msgs: Pointer to the messages to be processed
* @num: Length of the MSGS array
*
- * Returns the number of messages processed, or a negative errno on failure.
+ * Returns: the number of messages processed, or a negative errno on failure.
*/
int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index f18c3e74b076..16afb9ca19bb 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/mux/consumer.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/platform_data/i2c-omap.h>
@@ -211,6 +212,7 @@ struct omap_i2c_dev {
u16 syscstate;
u16 westate;
u16 errata;
+ struct mux_state *mux_state;
};
static const u8 reg_map_ip_v1[] = {
@@ -1452,6 +1454,23 @@ omap_i2c_probe(struct platform_device *pdev)
(1000 * omap->speed / 8);
}
+ if (of_property_read_bool(node, "mux-states")) {
+ struct mux_state *mux_state;
+
+ mux_state = devm_mux_state_get(&pdev->dev, NULL);
+ if (IS_ERR(mux_state)) {
+ r = PTR_ERR(mux_state);
+ dev_dbg(&pdev->dev, "failed to get I2C mux: %d\n", r);
+ goto err_disable_pm;
+ }
+ omap->mux_state = mux_state;
+ r = mux_state_select(omap->mux_state);
+ if (r) {
+ dev_err(&pdev->dev, "failed to select I2C mux: %d\n", r);
+ goto err_disable_pm;
+ }
+ }
+
/* reset ASAP, clearing any IRQs */
omap_i2c_init(omap);
@@ -1511,6 +1530,9 @@ static void omap_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&omap->adapter);
+ if (omap->mux_state)
+ mux_state_deselect(omap->mux_state);
+
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
dev_err(omap->dev, "Failed to resume hardware, skip disable\n");
diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c
index dac694a9d781..bd128ab2e2eb 100644
--- a/drivers/i2c/busses/i2c-pasemi-core.c
+++ b/drivers/i2c/busses/i2c-pasemi-core.c
@@ -5,6 +5,7 @@
* SMBus host driver for PA Semi PWRficient
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -26,21 +27,30 @@
#define REG_REV 0x28
/* Register defs */
-#define MTXFIFO_READ 0x00000400
-#define MTXFIFO_STOP 0x00000200
-#define MTXFIFO_START 0x00000100
-#define MTXFIFO_DATA_M 0x000000ff
-
-#define MRXFIFO_EMPTY 0x00000100
-#define MRXFIFO_DATA_M 0x000000ff
-
-#define SMSTA_XEN 0x08000000
-#define SMSTA_MTN 0x00200000
-
-#define CTL_MRR 0x00000400
-#define CTL_MTR 0x00000200
-#define CTL_EN 0x00000800
-#define CTL_CLK_M 0x000000ff
+#define MTXFIFO_READ BIT(10)
+#define MTXFIFO_STOP BIT(9)
+#define MTXFIFO_START BIT(8)
+#define MTXFIFO_DATA_M GENMASK(7, 0)
+
+#define MRXFIFO_EMPTY BIT(8)
+#define MRXFIFO_DATA_M GENMASK(7, 0)
+
+#define SMSTA_XIP BIT(28)
+#define SMSTA_XEN BIT(27)
+#define SMSTA_JMD BIT(25)
+#define SMSTA_JAM BIT(24)
+#define SMSTA_MTO BIT(23)
+#define SMSTA_MTA BIT(22)
+#define SMSTA_MTN BIT(21)
+#define SMSTA_MRNE BIT(19)
+#define SMSTA_MTE BIT(16)
+#define SMSTA_TOM BIT(6)
+
+#define CTL_EN BIT(11)
+#define CTL_MRR BIT(10)
+#define CTL_MTR BIT(9)
+#define CTL_UJM BIT(8)
+#define CTL_CLK_M GENMASK(7, 0)
static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
{
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index cb6988482673..4415a29f749b 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1503,7 +1503,10 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.name);
}
- clk_prepare_enable(i2c->clk);
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret)
+ return dev_err_probe(&dev->dev, ret,
+ "failed to enable clock\n");
if (i2c->use_pio) {
i2c->adap.algo = &i2c_pxa_pio_algorithm;
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 7bbd478171e0..515a784c951c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -148,9 +148,9 @@ struct geni_i2c_clk_fld {
* source_clock = 19.2 MHz
*/
static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
- {KHZ(100), 7, 10, 11, 26},
- {KHZ(400), 2, 5, 12, 24},
- {KHZ(1000), 1, 3, 9, 18},
+ {KHZ(100), 7, 10, 12, 26},
+ {KHZ(400), 2, 5, 11, 22},
+ {KHZ(1000), 1, 2, 8, 18},
{},
};
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index da20b4487c9a..3a36d682ed57 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -14,6 +14,7 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/i2c.h>
+#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -150,6 +151,8 @@
/* TAG length for DATA READ in RX FIFO */
#define READ_RX_TAGS_LEN 2
+#define QUP_BUS_WIDTH 8
+
static unsigned int scl_freq;
module_param_named(scl_freq, scl_freq, uint, 0444);
MODULE_PARM_DESC(scl_freq, "SCL frequency override");
@@ -227,6 +230,7 @@ struct qup_i2c_dev {
int irq;
struct clk *clk;
struct clk *pclk;
+ struct icc_path *icc_path;
struct i2c_adapter adap;
int clk_ctl;
@@ -255,6 +259,10 @@ struct qup_i2c_dev {
/* To configure when bus is in run state */
u32 config_run;
+ /* bandwidth votes */
+ u32 src_clk_freq;
+ u32 cur_bw_clk_freq;
+
/* dma parameters */
bool is_dma;
/* To check if the current transfer is using DMA */
@@ -453,6 +461,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
return ret;
}
+static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq)
+{
+ u32 needed_peak_bw;
+ int ret;
+
+ if (qup->cur_bw_clk_freq == clk_freq)
+ return 0;
+
+ needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH);
+ ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw);
+ if (ret)
+ return ret;
+
+ qup->cur_bw_clk_freq = clk_freq;
+ return 0;
+}
+
static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
{
struct qup_i2c_block *blk = &qup->blk;
@@ -838,6 +863,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int ret = 0;
int idx = 0;
+ ret = qup_i2c_vote_bw(qup, qup->src_clk_freq);
+ if (ret)
+ return ret;
+
enable_irq(qup->irq);
ret = qup_i2c_req_dma(qup);
@@ -1643,6 +1672,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
config = readl(qup->base + QUP_CONFIG);
config |= QUP_CLOCK_AUTO_GATE;
writel(config, qup->base + QUP_CONFIG);
+ qup_i2c_vote_bw(qup, 0);
clk_disable_unprepare(qup->pclk);
}
@@ -1743,6 +1773,11 @@ static int qup_i2c_probe(struct platform_device *pdev)
goto fail_dma;
}
qup->is_dma = true;
+
+ qup->icc_path = devm_of_icc_get(&pdev->dev, NULL);
+ if (IS_ERR(qup->icc_path))
+ return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path),
+ "failed to get interconnect path\n");
}
nodma:
@@ -1791,6 +1826,7 @@ nodma:
qup_i2c_enable_clocks(qup);
src_clk_freq = clk_get_rate(qup->clk);
}
+ qup->src_clk_freq = src_clk_freq;
/*
* Bootloaders might leave a pending interrupt on certain QUP's,
diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c
index 02b76e24a476..53762cc56d28 100644
--- a/drivers/i2c/busses/i2c-rzv2m.c
+++ b/drivers/i2c/busses/i2c-rzv2m.c
@@ -287,20 +287,15 @@ static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv,
int ret;
if (msg->flags & I2C_M_TEN) {
- /*
- * 10-bit address
- * addr_1: 5'b11110 | addr[9:8] | (R/nW)
- * addr_2: addr[7:0]
- */
- addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7);
- addr |= !!(msg->flags & I2C_M_RD);
- /* Send 1st address(extend code) */
+ /* 10-bit address: Send 1st address(extend code) */
+ addr = i2c_10bit_addr_hi_from_msg(msg);
ret = rzv2m_i2c_write_with_ack(priv, addr);
if (ret)
return ret;
- /* Send 2nd address */
- ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff);
+ /* 10-bit address: Send 2nd address */
+ addr = i2c_10bit_addr_lo_from_msg(msg);
+ ret = rzv2m_i2c_write_with_ack(priv, addr);
} else {
/* 7-bit address */
addr = i2c_8bit_addr_from_msg(msg);
diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index a6c407d36800..02feee6c9ba9 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -157,7 +157,6 @@ const struct of_device_id
return i2c_of_match_device_sysfs(matches, client);
}
-EXPORT_SYMBOL_GPL(i2c_of_match_device);
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
index 36587f38dff3..4797ba88331c 100644
--- a/drivers/i2c/i2c-core.h
+++ b/drivers/i2c/i2c-core.h
@@ -84,8 +84,17 @@ static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) {
#ifdef CONFIG_OF
void of_i2c_register_devices(struct i2c_adapter *adap);
+const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches,
+ struct i2c_client *client);
+
#else
static inline void of_i2c_register_devices(struct i2c_adapter *adap) { }
+static inline
+const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches,
+ struct i2c_client *client)
+{
+ return NULL;
+}
#endif
extern struct notifier_block i2c_of_notifier;
diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
index 19a7c370946d..8a87f19bf5d5 100644
--- a/drivers/i2c/muxes/i2c-mux-ltc4306.c
+++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
@@ -303,7 +303,7 @@ static void ltc4306_remove(struct i2c_client *client)
static struct i2c_driver ltc4306_driver = {
.driver = {
.name = "ltc4306",
- .of_match_table = of_match_ptr(ltc4306_of_match),
+ .of_match_table = ltc4306_of_match,
},
.probe = ltc4306_probe,
.remove = ltc4306_remove,
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 6f84018258c4..db95113a5b49 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -414,7 +414,7 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1);
for_each_set_bit(i, &pending, data->chip->nchans)
- handle_nested_irq(irq_linear_revmap(data->irq, i));
+ handle_nested_irq(irq_find_mapping(data->irq, i));
return IRQ_RETVAL(pending);
}
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index dfa472d514cc..1e566ea92bc9 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -250,7 +250,7 @@ static struct platform_driver i2c_mux_reg_driver = {
.remove = i2c_mux_reg_remove,
.driver = {
.name = "i2c-mux-reg",
- .of_match_table = of_match_ptr(i2c_mux_reg_of_match),
+ .of_match_table = i2c_mux_reg_of_match,
},
};