Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torvalds/linux.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-10-05 04:54:33 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-10-05 04:54:33 +0300
commitb86406d42ae3c41ae0ce332ea24350829b88af51 (patch)
treee60af933a10a3f238c0f4711c65008ed41bad133 /drivers/i2c/busses
parent0326074ff4652329f2a1a9c8685104576bd8d131 (diff)
parent228336f50711e9f0f47352483a8501e0c598845b (diff)
Merge tag 'i2c-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - 'remove' callback converted to return void. Big change with trivial fixes all over the tree. Other subsystems depending on this change have been asked to pull an immutable topic branch for this. - new driver for Microchip PCI1xxxx switch - heavy refactoring of the Mellanox BlueField driver - we prefer async probe in the i801 driver now - the rest is usual driver updates (support for more SoCs, some refactoring, some feature additions) * tag 'i2c-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (37 commits) i2c: pci1xxxx: prevent signed integer overflow i2c: acpi: Replace zero-length array with DECLARE_FLEX_ARRAY() helper i2c: i801: Prefer async probe i2c: designware-pci: Use standard pattern for memory allocation i2c: designware-pci: Group AMD NAVI quirk parts together i2c: microchip: pci1xxxx: Add driver for I2C host controller in multifunction endpoint of pci1xxxx switch docs: i2c: slave-interface: return errno when handle I2C_SLAVE_WRITE_REQUESTED i2c: mlxbf: remove device tree support i2c: mlxbf: support BlueField-3 SoC i2c: cadence: Add standard bus recovery support i2c: mlxbf: add multi slave functionality i2c: mlxbf: support lock mechanism macintosh/ams: Adapt declaration of ams_i2c_remove() to earlier change i2c: riic: Use devm_platform_ioremap_resource() i2c: mlxbf: remove IRQF_ONESHOT dt-bindings: i2c: rockchip: add rockchip,rk3128-i2c dt-bindings: i2c: renesas,rcar-i2c: Add r8a779g0 support i2c: tegra: Add GPCDMA support i2c: scmi: Convert to be a platform driver i2c: rk3x: Add rv1126 support ...
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-cadence.c20
-rw-r--r--drivers/i2c/busses/i2c-designware-amdpsp.c67
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c37
-rw-r--r--drivers/i2c/busses/i2c-i801.c1
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c24
-rw-r--r--drivers/i2c/busses/i2c-ismt.c7
-rw-r--r--drivers/i2c/busses/i2c-mchp-pci1xxxx.c1210
-rw-r--r--drivers/i2c/busses/i2c-mlxbf.c846
-rw-r--r--drivers/i2c/busses/i2c-riic.c4
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c9
-rw-r--r--drivers/i2c/busses/i2c-scmi.c48
-rw-r--r--drivers/i2c/busses/i2c-tegra.c11
14 files changed, 1826 insertions, 469 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 7284206b278b..a8b873b30b00 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1267,6 +1267,16 @@ config I2C_PARPORT
This support is also available as a module. If so, the module
will be called i2c-parport.
+config I2C_PCI1XXXX
+ tristate "PCI1XXXX I2C Host Adapter"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for
+ Microchip PCI1XXXX's I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-mchp-pci1xxxx.
+
config I2C_ROBOTFUZZ_OSIF
tristate "RobotFuzz Open Source InterFace USB adapter"
depends on USB
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index c5cac15f075c..e73cdb1d2b5a 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+obj-$(CONFIG_I2C_PCI1XXXX) += i2c-mchp-pci1xxxx.o
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 33f5588a50c0..fe0cd205502d 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -10,10 +10,12 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
/* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
@@ -127,6 +129,8 @@
#define CDNS_I2C_TIMEOUT_MAX 0xFF
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
+#define CDNS_I2C_POLL_US 100000
+#define CDNS_I2C_TIMEOUT_US 500000
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
@@ -204,6 +208,7 @@ struct cdns_i2c {
struct notifier_block clk_rate_change_nb;
u32 quirks;
u32 ctrl_reg;
+ struct i2c_bus_recovery_info rinfo;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
u16 ctrl_reg_diva_divb;
struct i2c_client *slave;
@@ -840,8 +845,14 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
#endif
/* Check if the bus is free */
- if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
+
+ ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET,
+ reg,
+ !(reg & CDNS_I2C_SR_BA),
+ CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
+ if (ret) {
ret = -EAGAIN;
+ i2c_recover_bus(adap);
goto out;
}
@@ -1250,6 +1261,12 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->quirks = data->quirks;
}
+ id->rinfo.pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(id->rinfo.pinctrl)) {
+ dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
+ return PTR_ERR(id->rinfo.pinctrl);
+ }
+
id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem);
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
@@ -1266,6 +1283,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->adap.retries = 3; /* Default retry value. */
id->adap.algo_data = id;
id->adap.dev.parent = &pdev->dev;
+ id->adap.bus_recovery_info = &id->rinfo;
init_completion(&id->xfer_done);
snprintf(id->adap.name, sizeof(id->adap.name),
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c
index b624356c945f..8f36167bce62 100644
--- a/drivers/i2c/busses/i2c-designware-amdpsp.c
+++ b/drivers/i2c/busses/i2c-designware-amdpsp.c
@@ -6,6 +6,7 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/psp-sev.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <asm/msr.h>
@@ -15,6 +16,8 @@
#define PSP_MBOX_OFFSET 0x10570
#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC)
+#define PSP_I2C_RESERVATION_TIME_MS 100
+
#define PSP_I2C_REQ_BUS_CMD 0x64
#define PSP_I2C_REQ_RETRY_CNT 400
#define PSP_I2C_REQ_RETRY_DELAY_US (25 * USEC_PER_MSEC)
@@ -240,6 +243,41 @@ cleanup:
return ret;
}
+static void release_bus(void)
+{
+ int status;
+
+ if (!psp_i2c_sem_acquired)
+ return;
+
+ status = psp_send_i2c_req(PSP_I2C_REQ_RELEASE);
+ if (status)
+ return;
+
+ dev_dbg(psp_i2c_dev, "PSP semaphore held for %ums\n",
+ jiffies_to_msecs(jiffies - psp_i2c_sem_acquired));
+
+ psp_i2c_sem_acquired = 0;
+}
+
+static void psp_release_i2c_bus_deferred(struct work_struct *work)
+{
+ mutex_lock(&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;
+
+ release_bus();
+
+cleanup:
+ mutex_unlock(&psp_i2c_access_mutex);
+}
+static DECLARE_DELAYED_WORK(release_queue, psp_release_i2c_bus_deferred);
+
static int psp_acquire_i2c_bus(void)
{
int status;
@@ -250,21 +288,23 @@ static int psp_acquire_i2c_bus(void)
if (psp_i2c_mbox_fail)
goto cleanup;
+ psp_i2c_access_count++;
+
/*
- * Simply increment usage counter and return if PSP semaphore was
- * already taken by kernel.
+ * No need to request bus arbitration once we are inside semaphore
+ * reservation period.
*/
- if (psp_i2c_access_count) {
- psp_i2c_access_count++;
+ if (psp_i2c_sem_acquired)
goto cleanup;
- }
status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE);
if (status)
goto cleanup;
psp_i2c_sem_acquired = jiffies;
- psp_i2c_access_count++;
+
+ schedule_delayed_work(&release_queue,
+ msecs_to_jiffies(PSP_I2C_RESERVATION_TIME_MS));
/*
* In case of errors with PSP arbitrator psp_i2c_mbox_fail variable is
@@ -279,8 +319,6 @@ cleanup:
static void psp_release_i2c_bus(void)
{
- int status;
-
mutex_lock(&psp_i2c_access_mutex);
/* Return early if mailbox was malfunctional */
@@ -295,13 +333,12 @@ static void psp_release_i2c_bus(void)
if (psp_i2c_access_count)
goto cleanup;
- /* Send a release command to PSP */
- status = psp_send_i2c_req(PSP_I2C_REQ_RELEASE);
- if (status)
- goto cleanup;
-
- dev_dbg(psp_i2c_dev, "PSP semaphore held for %ums\n",
- jiffies_to_msecs(jiffies - psp_i2c_sem_acquired));
+ /*
+ * Send a release command to PSP if the semaphore reservation timeout
+ * elapsed but x86 still owns the controller.
+ */
+ if (!delayed_work_pending(&release_queue))
+ release_bus();
cleanup:
mutex_unlock(&psp_i2c_access_mutex);
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 608e61209455..e499f96506c5 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -27,7 +27,6 @@
#include "i2c-ccgx-ucsi.h"
#define DRIVER_NAME "i2c-designware-pci"
-#define AMD_CLK_RATE_HZ 100000
enum dw_pci_ctl_id_t {
medfield,
@@ -100,11 +99,6 @@ static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
return 25000;
}
-static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev)
-{
- return AMD_CLK_RATE_HZ;
-}
-
static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
@@ -126,15 +120,6 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
return -ENODEV;
}
-static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
-{
- struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
-
- dev->flags |= MODEL_AMD_NAVI_GPU;
- dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
- return 0;
-}
-
static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
/*
@@ -159,6 +144,20 @@ static u32 ehl_get_clk_rate_khz(struct dw_i2c_dev *dev)
return 100000;
}
+static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return 100000;
+}
+
+static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
+
+ dev->flags |= MODEL_AMD_NAVI_GPU;
+ dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
+ return 0;
+}
+
static struct dw_pci_controller dw_pci_controllers[] = {
[medfield] = {
.bus_num = -1,
@@ -243,6 +242,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
int r;
struct dw_pci_controller *controller;
struct dw_scl_sda_cfg *cfg;
+ struct i2c_timings *t;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers))
return dev_err_probe(&pdev->dev, -EINVAL,
@@ -263,7 +263,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
return dev_err_probe(&pdev->dev, r,
"I/O memory remapping failed\n");
- dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
@@ -272,12 +272,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
return r;
dev->get_clk_rate_khz = controller->get_clk_rate_khz;
- dev->timings.bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
dev->irq = pci_irq_vector(pdev, 0);
dev->flags |= controller->flags;
+ t = &dev->timings;
+ i2c_parse_fw_timings(&pdev->dev, t, false);
+
pci_set_drvdata(pdev, dev);
if (controller->setup) {
@@ -389,6 +391,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
+ /* AMD NAVI */
{ PCI_VDEVICE(ATI, 0x7314), navi_amd },
{ PCI_VDEVICE(ATI, 0x73a4), navi_amd },
{ PCI_VDEVICE(ATI, 0x73e4), navi_amd },
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index a176296f4fff..e06509edc5f3 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1838,6 +1838,7 @@ static struct pci_driver i801_driver = {
.shutdown = i801_shutdown,
.driver = {
.pm = &i801_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index b51ab3cad2b1..188f2a36d2fd 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -94,7 +94,8 @@ enum lpi2c_imx_pincfg {
struct lpi2c_imx_struct {
struct i2c_adapter adapter;
- struct clk *clk;
+ int num_clks;
+ struct clk_bulk_data *clks;
void __iomem *base;
__u8 *rx_buf;
__u8 *tx_buf;
@@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
lpi2c_imx_set_mode(lpi2c_imx);
- clk_rate = clk_get_rate(lpi2c_imx->clk);
+ clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
filt = 0;
else
@@ -561,11 +562,12 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
strscpy(lpi2c_imx->adapter.name, pdev->name,
sizeof(lpi2c_imx->adapter.name));
- lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(lpi2c_imx->clk)) {
- dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
- return PTR_ERR(lpi2c_imx->clk);
+ ret = devm_clk_bulk_get_all(&pdev->dev, &lpi2c_imx->clks);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't get I2C peripheral clock, ret=%d\n", ret);
+ return ret;
}
+ lpi2c_imx->num_clks = ret;
ret = of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &lpi2c_imx->bitrate);
@@ -582,11 +584,9 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
platform_set_drvdata(pdev, lpi2c_imx);
- ret = clk_prepare_enable(lpi2c_imx->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk enable failed %d\n", ret);
+ ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ if (ret)
return ret;
- }
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -633,7 +633,7 @@ static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
- clk_disable_unprepare(lpi2c_imx->clk);
+ clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks);
pinctrl_pm_select_sleep_state(dev);
return 0;
@@ -645,7 +645,7 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
int ret;
pinctrl_pm_select_default_state(dev);
- ret = clk_prepare_enable(lpi2c_imx->clk);
+ ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
if (ret) {
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
return ret;
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index 6078fa0c0d48..fe2349590f75 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -937,11 +937,8 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- dev_err(&pdev->dev, "dma_set_mask fail\n");
- return -ENODEV;
- }
+ dev_err(&pdev->dev, "dma_set_mask fail\n");
+ return -ENODEV;
}
err = ismt_dev_init(priv);
diff --git a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c
new file mode 100644
index 000000000000..f5342201eb6b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c
@@ -0,0 +1,1210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip PCI1XXXX I2C adapter driver for PCIe Switch
+ * which has I2C controller in one of its downstream functions
+ *
+ * Copyright (C) 2021 - 2022 Microchip Technology Inc.
+ *
+ * Authors: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
+ * Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#define SMBUS_MAST_CORE_ADDR_BASE 0x00000
+#define SMBUS_MAST_SYS_REG_ADDR_BASE 0x01000
+
+/* SMB register space. */
+#define SMB_CORE_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x00)
+
+#define SMB_CORE_CTRL_ESO BIT(6)
+#define SMB_CORE_CTRL_FW_ACK BIT(4)
+#define SMB_CORE_CTRL_ACK BIT(0)
+
+#define SMB_CORE_CMD_REG_OFF3 (SMBUS_MAST_CORE_ADDR_BASE + 0x0F)
+#define SMB_CORE_CMD_REG_OFF2 (SMBUS_MAST_CORE_ADDR_BASE + 0x0E)
+#define SMB_CORE_CMD_REG_OFF1 (SMBUS_MAST_CORE_ADDR_BASE + 0x0D)
+
+#define SMB_CORE_CMD_READM BIT(4)
+#define SMB_CORE_CMD_STOP BIT(2)
+#define SMB_CORE_CMD_START BIT(0)
+
+#define SMB_CORE_CMD_REG_OFF0 (SMBUS_MAST_CORE_ADDR_BASE + 0x0C)
+
+#define SMB_CORE_CMD_M_PROCEED BIT(1)
+#define SMB_CORE_CMD_M_RUN BIT(0)
+
+#define SMB_CORE_SR_HOLD_TIME_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x18)
+
+/*
+ * SR_HOLD_TIME_XK_TICKS field will indicate the number of ticks of the
+ * baud clock required to program 'Hold Time' at X KHz.
+ */
+#define SR_HOLD_TIME_100K_TICKS 133
+#define SR_HOLD_TIME_400K_TICKS 20
+#define SR_HOLD_TIME_1000K_TICKS 11
+
+#define SMB_CORE_COMPLETION_REG_OFF3 (SMBUS_MAST_CORE_ADDR_BASE + 0x23)
+
+#define COMPLETION_MDONE BIT(6)
+#define COMPLETION_IDLE BIT(5)
+#define COMPLETION_MNAKX BIT(0)
+
+#define SMB_CORE_IDLE_SCALING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x24)
+
+/*
+ * FAIR_BUS_IDLE_MIN_XK_TICKS field will indicate the number of ticks of
+ * the baud clock required to program 'fair idle delay' at X KHz. Fair idle
+ * delay establishes the MCTP T(IDLE_DELAY) period.
+ */
+#define FAIR_BUS_IDLE_MIN_100K_TICKS 969
+#define FAIR_BUS_IDLE_MIN_400K_TICKS 157
+#define FAIR_BUS_IDLE_MIN_1000K_TICKS 157
+
+/*
+ * FAIR_IDLE_DELAY_XK_TICKS field will indicate the number of ticks of the
+ * baud clock required to satisfy the fairness protocol at X KHz.
+ */
+#define FAIR_IDLE_DELAY_100K_TICKS 1000
+#define FAIR_IDLE_DELAY_400K_TICKS 500
+#define FAIR_IDLE_DELAY_1000K_TICKS 500
+
+#define SMB_IDLE_SCALING_100K \
+ ((FAIR_IDLE_DELAY_100K_TICKS << 16) | FAIR_BUS_IDLE_MIN_100K_TICKS)
+#define SMB_IDLE_SCALING_400K \
+ ((FAIR_IDLE_DELAY_400K_TICKS << 16) | FAIR_BUS_IDLE_MIN_400K_TICKS)
+#define SMB_IDLE_SCALING_1000K \
+ ((FAIR_IDLE_DELAY_1000K_TICKS << 16) | FAIR_BUS_IDLE_MIN_1000K_TICKS)
+
+#define SMB_CORE_CONFIG_REG3 (SMBUS_MAST_CORE_ADDR_BASE + 0x2B)
+
+#define SMB_CONFIG3_ENMI BIT(6)
+#define SMB_CONFIG3_ENIDI BIT(5)
+
+#define SMB_CORE_CONFIG_REG2 (SMBUS_MAST_CORE_ADDR_BASE + 0x2A)
+#define SMB_CORE_CONFIG_REG1 (SMBUS_MAST_CORE_ADDR_BASE + 0x29)
+
+#define SMB_CONFIG1_ASR BIT(7)
+#define SMB_CONFIG1_ENAB BIT(2)
+#define SMB_CONFIG1_RESET BIT(1)
+#define SMB_CONFIG1_FEN BIT(0)
+
+#define SMB_CORE_BUS_CLK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x2C)
+
+/*
+ * BUS_CLK_XK_LOW_PERIOD_TICKS field defines the number of I2C Baud Clock
+ * periods that make up the low phase of the I2C/SMBus bus clock at X KHz.
+ */
+#define BUS_CLK_100K_LOW_PERIOD_TICKS 156
+#define BUS_CLK_400K_LOW_PERIOD_TICKS 41
+#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15
+
+/*
+ * BUS_CLK_XK_HIGH_PERIOD_TICKS field defines the number of I2C Baud Clock
+ * periods that make up the high phase of the I2C/SMBus bus clock at X KHz.
+ */
+#define BUS_CLK_100K_HIGH_PERIOD_TICKS 154
+#define BUS_CLK_400K_HIGH_PERIOD_TICKS 35
+#define BUS_CLK_1000K_HIGH_PERIOD_TICKS 14
+
+#define BUS_CLK_100K \
+ ((BUS_CLK_100K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_100K_LOW_PERIOD_TICKS)
+#define BUS_CLK_400K \
+ ((BUS_CLK_400K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_400K_LOW_PERIOD_TICKS)
+#define BUS_CLK_1000K \
+ ((BUS_CLK_1000K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_1000K_LOW_PERIOD_TICKS)
+
+#define SMB_CORE_CLK_SYNC_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x3C)
+
+/*
+ * CLK_SYNC_XK defines the number of clock cycles to sync up to the external
+ * clock before comparing the internal and external clocks for clock stretching
+ * at X KHz.
+ */
+#define CLK_SYNC_100K 4
+#define CLK_SYNC_400K 4
+#define CLK_SYNC_1000K 4
+
+#define SMB_CORE_DATA_TIMING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x40)
+
+/*
+ *
+ * FIRST_START_HOLD_XK_TICKS will indicate the number of ticks of the baud
+ * clock required to program 'FIRST_START_HOLD' timer at X KHz. This timer
+ * determines the SCLK hold time following SDAT driven low during the first
+ * START bit in a transfer.
+ */
+#define FIRST_START_HOLD_100K_TICKS 22
+#define FIRST_START_HOLD_400K_TICKS 16
+#define FIRST_START_HOLD_1000K_TICKS 6
+
+/*
+ * STOP_SETUP_XK_TICKS will indicate the number of ticks of the baud clock
+ * required to program 'STOP_SETUP' timer at X KHz. This timer determines the
+ * SDAT setup time from the rising edge of SCLK for a STOP condition.
+ */
+#define STOP_SETUP_100K_TICKS 157
+#define STOP_SETUP_400K_TICKS 20
+#define STOP_SETUP_1000K_TICKS 12
+
+/*
+ * RESTART_SETUP_XK_TICKS will indicate the number of ticks of the baud clock
+ * required to program 'RESTART_SETUP' timer at X KHz. This timer determines the
+ * SDAT setup time from the rising edge of SCLK for a repeated START condition.
+ */
+#define RESTART_SETUP_100K_TICKS 157
+#define RESTART_SETUP_400K_TICKS 20
+#define RESTART_SETUP_1000K_TICKS 12
+
+/*
+ * DATA_HOLD_XK_TICKS will indicate the number of ticks of the baud clock
+ * required to program 'DATA_HOLD' timer at X KHz. This timer determines the
+ * SDAT hold time following SCLK driven low.
+ */
+#define DATA_HOLD_100K_TICKS 2
+#define DATA_HOLD_400K_TICKS 2
+#define DATA_HOLD_1000K_TICKS 2
+
+#define DATA_TIMING_100K \
+ ((FIRST_START_HOLD_100K_TICKS << 24) | (STOP_SETUP_100K_TICKS << 16) | \
+ (RESTART_SETUP_100K_TICKS << 8) | DATA_HOLD_100K_TICKS)
+#define DATA_TIMING_400K \
+ ((FIRST_START_HOLD_400K_TICKS << 24) | (STOP_SETUP_400K_TICKS << 16) | \
+ (RESTART_SETUP_400K_TICKS << 8) | DATA_HOLD_400K_TICKS)
+#define DATA_TIMING_1000K \
+ ((FIRST_START_HOLD_1000K_TICKS << 24) | (STOP_SETUP_1000K_TICKS << 16) | \
+ (RESTART_SETUP_1000K_TICKS << 8) | DATA_HOLD_1000K_TICKS)
+
+#define SMB_CORE_TO_SCALING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x44)
+
+/*
+ * BUS_IDLE_MIN_XK_TICKS defines Bus Idle Minimum Time.
+ * Bus Idle Minimum time = BUS_IDLE_MIN[7:0] x Baud_Clock_Period x
+ * (BUS_IDLE_MIN_XK_TICKS[7] ? 4,1)
+ */
+#define BUS_IDLE_MIN_100K_TICKS 167UL
+#define BUS_IDLE_MIN_400K_TICKS 139UL
+#define BUS_IDLE_MIN_1000K_TICKS 133UL
+
+/*
+ * CTRL_CUM_TIME_OUT_XK_TICKS defines SMBus Controller Cumulative Time-Out.
+ * SMBus Controller Cumulative Time-Out duration =
+ * CTRL_CUM_TIME_OUT_XK_TICKS[7:0] x Baud_Clock_Period x 2048
+ */
+#define CTRL_CUM_TIME_OUT_100K_TICKS 159
+#define CTRL_CUM_TIME_OUT_400K_TICKS 159
+#define CTRL_CUM_TIME_OUT_1000K_TICKS 159
+
+/*
+ * TARGET_CUM_TIME_OUT_XK_TICKS defines SMBus Target Cumulative Time-Out duration.
+ * SMBus Target Cumulative Time-Out duration = TARGET_CUM_TIME_OUT_XK_TICKS[7:0] x
+ * Baud_Clock_Period x 4096
+ */
+#define TARGET_CUM_TIME_OUT_100K_TICKS 199
+#define TARGET_CUM_TIME_OUT_400K_TICKS 199
+#define TARGET_CUM_TIME_OUT_1000K_TICKS 199
+
+/*
+ * CLOCK_HIGH_TIME_OUT_XK defines Clock High time out period.
+ * Clock High time out period = CLOCK_HIGH_TIME_OUT_XK[7:0] x Baud_Clock_Period x 8
+ */
+#define CLOCK_HIGH_TIME_OUT_100K_TICKS 204
+#define CLOCK_HIGH_TIME_OUT_400K_TICKS 204
+#define CLOCK_HIGH_TIME_OUT_1000K_TICKS 204
+
+#define TO_SCALING_100K \
+ ((BUS_IDLE_MIN_100K_TICKS << 24) | (CTRL_CUM_TIME_OUT_100K_TICKS << 16) | \
+ (TARGET_CUM_TIME_OUT_100K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_100K_TICKS)
+#define TO_SCALING_400K \
+ ((BUS_IDLE_MIN_400K_TICKS << 24) | (CTRL_CUM_TIME_OUT_400K_TICKS << 16) | \
+ (TARGET_CUM_TIME_OUT_400K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_400K_TICKS)
+#define TO_SCALING_1000K \
+ ((BUS_IDLE_MIN_1000K_TICKS << 24) | (CTRL_CUM_TIME_OUT_1000K_TICKS << 16) | \
+ (TARGET_CUM_TIME_OUT_1000K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_1000K_TICKS)
+
+#define I2C_SCL_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x100)
+#define I2C_SDA_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x101)
+
+#define I2C_FOD_EN BIT(4)
+#define I2C_PULL_UP_EN BIT(3)
+#define I2C_PULL_DOWN_EN BIT(2)
+#define I2C_INPUT_EN BIT(1)
+#define I2C_OUTPUT_EN BIT(0)
+
+#define SMBUS_CONTROL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x200)
+
+#define CTL_RESET_COUNTERS BIT(3)
+#define CTL_TRANSFER_DIR BIT(2)
+#define CTL_HOST_FIFO_ENTRY BIT(1)
+#define CTL_RUN BIT(0)
+
+#define I2C_DIRN_WRITE 0
+#define I2C_DIRN_READ 1
+
+#define SMBUS_STATUS_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x204)
+
+#define STA_DMA_TERM BIT(7)
+#define STA_DMA_REQ BIT(6)
+#define STA_THRESHOLD BIT(2)
+#define STA_BUF_FULL BIT(1)
+#define STA_BUF_EMPTY BIT(0)
+
+#define SMBUS_INTR_STAT_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x208)
+
+#define INTR_STAT_DMA_TERM BIT(7)
+#define INTR_STAT_THRESHOLD BIT(2)
+#define INTR_STAT_BUF_FULL BIT(1)
+#define INTR_STAT_BUF_EMPTY BIT(0)
+
+#define SMBUS_INTR_MSK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x20C)
+
+#define INTR_MSK_DMA_TERM BIT(7)
+#define INTR_MSK_THRESHOLD BIT(2)
+#define INTR_MSK_BUF_FULL BIT(1)
+#define INTR_MSK_BUF_EMPTY BIT(0)
+
+#define ALL_NW_LAYER_INTERRUPTS \
+ (INTR_MSK_DMA_TERM | INTR_MSK_THRESHOLD | INTR_MSK_BUF_FULL | \
+ INTR_MSK_BUF_EMPTY)
+
+#define SMBUS_MCU_COUNTER_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x214)
+
+#define SMBALERT_MST_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x230)
+
+#define SMBALERT_MST_PU BIT(0)
+
+#define SMBUS_GEN_INT_STAT_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x23C)
+
+#define SMBUS_GEN_INT_MASK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x240)
+
+#define SMBALERT_INTR_MASK BIT(10)
+#define I2C_BUF_MSTR_INTR_MASK BIT(9)
+#define I2C_INTR_MASK BIT(8)
+#define SMBALERT_WAKE_INTR_MASK BIT(2)
+#define I2C_BUF_MSTR_WAKE_INTR_MASK BIT(1)
+#define I2C_WAKE_INTR_MASK BIT(0)
+
+#define ALL_HIGH_LAYER_INTR \
+ (SMBALERT_INTR_MASK | I2C_BUF_MSTR_INTR_MASK | I2C_INTR_MASK | \
+ SMBALERT_WAKE_INTR_MASK | I2C_BUF_MSTR_WAKE_INTR_MASK | \
+ I2C_WAKE_INTR_MASK)
+
+#define SMBUS_RESET_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x248)
+
+#define PERI_SMBUS_D3_RESET_DIS BIT(16)
+
+#define SMBUS_MST_BUF (SMBUS_MAST_CORE_ADDR_BASE + 0x280)
+
+#define SMBUS_BUF_MAX_SIZE 0x80
+
+#define I2C_FLAGS_DIRECT_MODE BIT(7)
+#define I2C_FLAGS_POLLING_MODE BIT(6)
+#define I2C_FLAGS_STOP BIT(5)
+#define I2C_FLAGS_SMB_BLK_READ BIT(4)
+
+#define PCI1XXXX_I2C_TIMEOUT_MS 1000
+
+/* General Purpose Register. */
+#define SMB_GPR_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x1000 + 0x0c00 + \
+ 0x00)
+
+/* Lock Register. */
+#define SMB_GPR_LOCK_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x1000 + 0x0000 + \
+ 0x00A0)
+
+#define SMBUS_PERI_LOCK BIT(3)
+
+struct pci1xxxx_i2c {
+ struct completion i2c_xfer_done;
+ bool i2c_xfer_in_progress;
+ struct i2c_adapter adap;
+ void __iomem *i2c_base;
+ u32 freq;
+ u32 flags;
+};
+
+static int set_sys_lock(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMB_GPR_LOCK_REG;
+ u8 data;
+
+ writel(SMBUS_PERI_LOCK, p);
+ data = readl(p);
+ if (data != SMBUS_PERI_LOCK)
+ return -EPERM;
+
+ return 0;
+}
+
+static int release_sys_lock(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMB_GPR_LOCK_REG;
+ u8 data;
+
+ data = readl(p);
+ if (data != SMBUS_PERI_LOCK)
+ return 0;
+
+ writel(0, p);
+ data = readl(p);
+ if (data & SMBUS_PERI_LOCK)
+ return -EPERM;
+
+ return 0;
+}
+
+static void pci1xxxx_ack_high_level_intr(struct pci1xxxx_i2c *i2c, u16 intr_msk)
+{
+ writew(intr_msk, i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF);
+}
+
+static void pci1xxxx_i2c_configure_smbalert_pin(struct pci1xxxx_i2c *i2c,
+ bool enable)
+{
+ void __iomem *p = i2c->i2c_base + SMBALERT_MST_PAD_CTRL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+
+ if (enable)
+ regval |= SMBALERT_MST_PU;
+ else
+ regval &= ~SMBALERT_MST_PU;
+
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_send_start_stop(struct pci1xxxx_i2c *i2c, bool start)
+{
+ void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1;
+ u8 regval;
+
+ regval = readb(p);
+
+ if (start)
+ regval |= SMB_CORE_CMD_START;
+ else
+ regval |= SMB_CORE_CMD_STOP;
+
+ writeb(regval, p);
+}
+
+/*
+ * When accessing the core control reg, we should not do a read modified write
+ * as they are write '1' to clear bits. Instead we need to write with the
+ * specific bits that needs to be set.
+ */
+static void pci1xxxx_i2c_set_clear_FW_ACK(struct pci1xxxx_i2c *i2c, bool set)
+{
+ u8 regval;
+
+ if (set)
+ regval = SMB_CORE_CTRL_FW_ACK | SMB_CORE_CTRL_ESO | SMB_CORE_CTRL_ACK;
+ else
+ regval = SMB_CORE_CTRL_ESO | SMB_CORE_CTRL_ACK;
+
+ writeb(regval, i2c->i2c_base + SMB_CORE_CTRL_REG_OFF);
+}
+
+static void pci1xxxx_i2c_buffer_write(struct pci1xxxx_i2c *i2c, u8 slaveaddr,
+ u8 transferlen, unsigned char *buf)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_MST_BUF;
+
+ if (slaveaddr)
+ writeb(slaveaddr, p++);
+
+ if (buf)
+ memcpy_toio(p, buf, transferlen);
+}
+
+/*
+ * When accessing the core control reg, we should not do a read modified write
+ * as there are write '1' to clear bits. Instead we need to write with the
+ * specific bits that needs to be set.
+ */
+static void pci1xxxx_i2c_enable_ESO(struct pci1xxxx_i2c *i2c)
+{
+ writeb(SMB_CORE_CTRL_ESO, i2c->i2c_base + SMB_CORE_CTRL_REG_OFF);
+}
+
+static void pci1xxxx_i2c_reset_counters(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+ regval |= CTL_RESET_COUNTERS;
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_set_transfer_dir(struct pci1xxxx_i2c *i2c, u8 direction)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+ if (direction == I2C_DIRN_WRITE)
+ regval &= ~CTL_TRANSFER_DIR;
+ else
+ regval |= CTL_TRANSFER_DIR;
+
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_set_mcu_count(struct pci1xxxx_i2c *i2c, u8 count)
+{
+ writeb(count, i2c->i2c_base + SMBUS_MCU_COUNTER_REG_OFF);
+}
+
+static void pci1xxxx_i2c_set_read_count(struct pci1xxxx_i2c *i2c, u8 readcount)
+{
+ writeb(readcount, i2c->i2c_base + SMB_CORE_CMD_REG_OFF3);
+}
+
+static void pci1xxxx_i2c_set_write_count(struct pci1xxxx_i2c *i2c, u8 writecount)
+{
+ writeb(writecount, i2c->i2c_base + SMB_CORE_CMD_REG_OFF2);
+}
+
+static void pci1xxxx_i2c_set_DMA_run(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+ regval |= CTL_RUN;
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_set_mrun_proceed(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF0;
+ u8 regval;
+
+ regval = readb(p);
+ regval |= SMB_CORE_CMD_M_RUN;
+ regval |= SMB_CORE_CMD_M_PROCEED;
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_start_DMA(struct pci1xxxx_i2c *i2c)
+{
+ pci1xxxx_i2c_set_DMA_run(i2c);
+ pci1xxxx_i2c_set_mrun_proceed(i2c);
+}
+
+static void pci1xxxx_i2c_config_asr(struct pci1xxxx_i2c *i2c, bool enable)
+{
+ void __iomem *p = i2c->i2c_base + SMB_CORE_CONFIG_REG1;
+ u8 regval;
+
+ regval = readb(p);
+ if (enable)
+ regval |= SMB_CONFIG1_ASR;
+ else
+ regval &= ~SMB_CONFIG1_ASR;
+ writeb(regval, p);
+}
+
+static irqreturn_t pci1xxxx_i2c_isr(int irq, void *dev)
+{
+ struct pci1xxxx_i2c *i2c = dev;
+ void __iomem *p1 = i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF;
+ void __iomem *p2 = i2c->i2c_base + SMBUS_INTR_STAT_REG_OFF;
+ irqreturn_t intr_handled = IRQ_NONE;
+ u16 reg1;
+ u8 reg3;
+
+ /*
+ * Read the SMBus interrupt status register to see if the
+ * DMA_TERM interrupt has caused this callback.
+ */
+ reg1 = readw(p1);
+
+ if (reg1 & I2C_BUF_MSTR_INTR_MASK) {
+ reg3 = readb(p2);
+ if (reg3 & INTR_STAT_DMA_TERM) {
+ complete(&i2c->i2c_xfer_done);
+ intr_handled = IRQ_HANDLED;
+ writeb(INTR_STAT_DMA_TERM, p2);
+ }
+ pci1xxxx_ack_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK);
+ }
+
+ if (reg1 & SMBALERT_INTR_MASK) {
+ intr_handled = IRQ_HANDLED;
+ pci1xxxx_ack_high_level_intr(i2c, SMBALERT_INTR_MASK);
+ }
+
+ return intr_handled;
+}
+
+static void pci1xxxx_i2c_set_count(struct pci1xxxx_i2c *i2c, u8 mcucount,
+ u8 writecount, u8 readcount)
+{
+ pci1xxxx_i2c_set_mcu_count(i2c, mcucount);
+ pci1xxxx_i2c_set_write_count(i2c, writecount);
+ pci1xxxx_i2c_set_read_count(i2c, readcount);
+}
+
+static void pci1xxxx_i2c_set_readm(struct pci1xxxx_i2c *i2c, bool enable)
+{
+ void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1;
+ u8 regval;
+
+ regval = readb(p);
+ if (enable)
+ regval |= SMB_CORE_CMD_READM;
+ else
+ regval &= ~SMB_CORE_CMD_READM;
+
+ writeb(regval, p);
+}
+
+static void pci1xxxx_ack_nw_layer_intr(struct pci1xxxx_i2c *i2c, u8 ack_intr_msk)
+{
+ writeb(ack_intr_msk, i2c->i2c_base + SMBUS_INTR_STAT_REG_OFF);
+}
+
+static void pci1xxxx_config_nw_layer_intr(struct pci1xxxx_i2c *i2c,
+ u8 intr_msk, bool enable)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_INTR_MSK_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+ if (enable)
+ regval &= ~intr_msk;
+ else
+ regval |= intr_msk;
+
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_config_padctrl(struct pci1xxxx_i2c *i2c, bool enable)
+{
+ void __iomem *p1 = i2c->i2c_base + I2C_SCL_PAD_CTRL_REG_OFF;
+ void __iomem *p2 = i2c->i2c_base + I2C_SDA_PAD_CTRL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p1);
+ if (enable)
+ regval |= I2C_INPUT_EN | I2C_OUTPUT_EN;
+ else
+ regval &= ~(I2C_INPUT_EN | I2C_OUTPUT_EN);
+
+ writeb(regval, p1);
+
+ regval = readb(p2);
+ if (enable)
+ regval |= I2C_INPUT_EN | I2C_OUTPUT_EN;
+ else
+ regval &= ~(I2C_INPUT_EN | I2C_OUTPUT_EN);
+
+ writeb(regval, p2);
+}
+
+static void pci1xxxx_i2c_set_mode(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF;
+ u8 regval;
+
+ regval = readb(p);
+ if (i2c->flags & I2C_FLAGS_DIRECT_MODE)
+ regval &= ~CTL_HOST_FIFO_ENTRY;
+ else
+ regval |= CTL_HOST_FIFO_ENTRY;
+
+ writeb(regval, p);
+}
+
+static void pci1xxxx_i2c_config_high_level_intr(struct pci1xxxx_i2c *i2c,
+ u16 intr_msk, bool enable)
+{
+ void __iomem *p = i2c->i2c_base + SMBUS_GEN_INT_MASK_REG_OFF;
+ u16 regval;
+
+ regval = readw(p);
+ if (enable)
+ regval &= ~intr_msk;
+ else
+ regval |= intr_msk;
+ writew(regval, p);
+}
+
+static void pci1xxxx_i2c_configure_core_reg(struct pci1xxxx_i2c *i2c, bool enable)
+{
+ void __iomem *p1 = i2c->i2c_base + SMB_CORE_CONFIG_REG1;
+ void __iomem *p3 = i2c->i2c_base + SMB_CORE_CONFIG_REG3;
+ u8 reg1;
+ u8 reg3;
+
+ reg1 = readb(p1);
+ reg3 = readb(p3);
+ if (enable) {
+ reg1 |= SMB_CONFIG1_ENAB | SMB_CONFIG1_FEN;
+ reg3 |= SMB_CONFIG3_ENMI | SMB_CONFIG3_ENIDI;
+ } else {
+ reg1 &= ~(SMB_CONFIG1_ENAB | SMB_CONFIG1_FEN);
+ reg3 &= ~(SMB_CONFIG3_ENMI | SMB_CONFIG3_ENIDI);
+ }
+
+ writeb(reg1, p1);
+ writeb(reg3, p3);
+}
+
+static void pci1xxxx_i2c_set_freq(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *bp = i2c->i2c_base;
+ void __iomem *p_idle_scaling = bp + SMB_CORE_IDLE_SCALING_REG_OFF;
+ void __iomem *p_data_timing = bp + SMB_CORE_DATA_TIMING_REG_OFF;
+ void __iomem *p_hold_time = bp + SMB_CORE_SR_HOLD_TIME_REG_OFF;
+ void __iomem *p_to_scaling = bp + SMB_CORE_TO_SCALING_REG_OFF;
+ void __iomem *p_clk_sync = bp + SMB_CORE_CLK_SYNC_REG_OFF;
+ void __iomem *p_clk_reg = bp + SMB_CORE_BUS_CLK_REG_OFF;
+
+ switch (i2c->freq) {
+ case I2C_MAX_STANDARD_MODE_FREQ:
+ writeb(SR_HOLD_TIME_100K_TICKS, p_hold_time);
+ writel(SMB_IDLE_SCALING_100K, p_idle_scaling);
+ writew(BUS_CLK_100K, p_clk_reg);
+ writel(CLK_SYNC_100K, p_clk_sync);
+ writel(DATA_TIMING_100K, p_data_timing);
+ writel(TO_SCALING_100K, p_to_scaling);
+ break;
+
+ case I2C_MAX_FAST_MODE_PLUS_FREQ:
+ writeb(SR_HOLD_TIME_1000K_TICKS, p_hold_time);
+ writel(SMB_IDLE_SCALING_1000K, p_idle_scaling);
+ writew(BUS_CLK_1000K, p_clk_reg);
+ writel(CLK_SYNC_1000K, p_clk_sync);
+ writel(DATA_TIMING_1000K, p_data_timing);
+ writel(TO_SCALING_1000K, p_to_scaling);
+ break;
+
+ case I2C_MAX_FAST_MODE_FREQ:
+ default:
+ writeb(SR_HOLD_TIME_400K_TICKS, p_hold_time);
+ writel(SMB_IDLE_SCALING_400K, p_idle_scaling);
+ writew(BUS_CLK_400K, p_clk_reg);
+ writel(CLK_SYNC_400K, p_clk_sync);
+ writel(DATA_TIMING_400K, p_data_timing);
+ writel(TO_SCALING_400K, p_to_scaling);
+ break;
+ }
+}
+
+static void pci1xxxx_i2c_init(struct pci1xxxx_i2c *i2c)
+{
+ void __iomem *p2 = i2c->i2c_base + SMBUS_STATUS_REG_OFF;
+ void __iomem *p1 = i2c->i2c_base + SMB_GPR_REG;
+ u8 regval;
+ u8 ret;
+
+ ret = set_sys_lock(i2c);
+ if (ret == -EPERM) {
+ /*
+ * Configure I2C Fast Mode as default frequency if unable
+ * to acquire sys lock.
+ */
+ regval = 0;
+ } else {
+ regval = readl(p1);
+ release_sys_lock(i2c);
+ }
+
+ switch (regval) {
+ case 0:
+ i2c->freq = I2C_MAX_FAST_MODE_FREQ;
+ pci1xxxx_i2c_set_freq(i2c);
+ break;
+ case 1:
+ i2c->freq = I2C_MAX_STANDARD_MODE_FREQ;
+ pci1xxxx_i2c_set_freq(i2c);
+ break;
+ case 2:
+ i2c->freq = I2C_MAX_FAST_MODE_PLUS_FREQ;
+ pci1xxxx_i2c_set_freq(i2c);
+ break;
+ case 3:
+ default:
+ break;
+ }
+
+ pci1xxxx_i2c_config_padctrl(i2c, true);
+ i2c->flags |= I2C_FLAGS_DIRECT_MODE;
+ pci1xxxx_i2c_set_mode(i2c);
+
+ /*
+ * Added as a precaution since BUF_EMPTY in status register
+ * also trigered an Interrupt.
+ */
+ writeb(STA_BUF_EMPTY, p2);
+
+ /* Configure core I2c control registers. */
+ pci1xxxx_i2c_configure_core_reg(i2c, true);
+
+ /*
+ * Enable pull-up for the SMB alert pin which is just used for
+ * wakeup right now.
+ */
+ pci1xxxx_i2c_configure_smbalert_pin(i2c, true);
+}
+
+static void pci1xxxx_i2c_clear_flags(struct pci1xxxx_i2c *i2c)
+{
+ u8 regval;
+
+ /* Reset the internal buffer counters. */
+ pci1xxxx_i2c_reset_counters(i2c);
+
+ /* Clear low level interrupts. */
+ regval = COMPLETION_MNAKX | COMPLETION_IDLE | COMPLETION_MDONE;
+ writeb(regval, i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3);
+ reinit_completion(&i2c->i2c_xfer_done);
+ pci1xxxx_ack_nw_layer_intr(i2c, ALL_NW_LAYER_INTERRUPTS);
+ pci1xxxx_ack_high_level_intr(i2c, ALL_HIGH_LAYER_INTR);
+}
+
+static int pci1xxxx_i2c_read(struct pci1xxxx_i2c *i2c, u8 slaveaddr,
+ unsigned char *buf, u16 total_len)
+{
+ void __iomem *p2 = i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3;
+ void __iomem *p1 = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1;
+ void __iomem *p3 = i2c->i2c_base + SMBUS_MST_BUF;
+ unsigned long time_left;
+ u16 remainingbytes;
+ u8 transferlen;
+ int retval = 0;
+ u8 read_count;
+ u32 regval;
+ u16 count;
+
+ /* Enable I2C host controller by setting the ESO bit in the CONTROL REG. */
+ pci1xxxx_i2c_enable_ESO(i2c);
+ pci1xxxx_i2c_clear_flags(i2c);
+ pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, true);
+ pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, true);
+
+ /*
+ * The I2C transfer could be more than 128 bytes. Our Core is
+ * capable of only sending 128 at a time.
+ * As far as the I2C read is concerned, initailly send the
+ * read slave address along with the number of bytes to read in
+ * ReadCount. After sending the slave address the interrupt
+ * is generated. On seeing the ACK for the slave address, reverse the
+ * buffer direction and run the DMA to initiate Read from slave.
+ */
+ for (count = 0; count < total_len; count += transferlen) {
+
+ /*
+ * Before start of any transaction clear the existing
+ * START/STOP conditions.
+ */
+ writeb(0, p1);
+ remainingbytes = total_len - count;
+ transferlen = min_t(u16, remainingbytes, SMBUS_BUF_MAX_SIZE);
+
+ /*
+ * Send STOP bit for the last chunk in the transaction.
+ * For I2C read transaction of more than BUF_SIZE, NACK should
+ * only be sent for the last read.
+ * Hence a bit FW_ACK is set for all the read chunks except for
+ * the last chunk. For the last chunk NACK should be sent and
+ * FW_ACK is cleared Send STOP only when I2C_FLAGS_STOP bit is
+ * set in the flags and only for the last transaction.
+ */
+ if ((count + transferlen >= total_len) &&
+ (i2c->flags & I2C_FLAGS_STOP)) {
+ pci1xxxx_i2c_set_clear_FW_ACK(i2c, false);
+ pci1xxxx_i2c_send_start_stop(i2c, 0);
+ } else {
+ pci1xxxx_i2c_set_clear_FW_ACK(i2c, true);
+ }
+
+ /* Send START bit for the first transaction. */
+ if (count == 0) {
+ pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_WRITE);
+ pci1xxxx_i2c_send_start_stop(i2c, 1);
+
+ /* Write I2c buffer with just the slave addr. */
+ pci1xxxx_i2c_buffer_write(i2c, slaveaddr, 0, NULL);
+
+ /* Set the count. Readcount is the transfer bytes. */
+ pci1xxxx_i2c_set_count(i2c, 1, 1, transferlen);
+
+ /*
+ * Set the Auto_start_read bit so that the HW itself
+ * will take care of the read phase.
+ */
+ pci1xxxx_i2c_config_asr(i2c, true);
+ if (i2c->flags & I2C_FLAGS_SMB_BLK_READ)
+ pci1xxxx_i2c_set_readm(i2c, true);
+ } else {
+ pci1xxxx_i2c_set_count(i2c, 0, 0, transferlen);
+ pci1xxxx_i2c_config_asr(i2c, false);
+ pci1xxxx_i2c_clear_flags(i2c);
+ pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_READ);
+ }
+
+ /* Start the DMA. */
+ pci1xxxx_i2c_start_DMA(i2c);
+
+ /* Wait for the DMA_TERM interrupt. */
+ time_left = wait_for_completion_timeout(&i2c->i2c_xfer_done,
+ msecs_to_jiffies(PCI1XXXX_I2C_TIMEOUT_MS));
+ if (time_left == 0) {
+ /* Reset the I2C core to release the bus lock. */
+ pci1xxxx_i2c_init(i2c);
+ retval = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ /* Read the completion reg to know the reason for DMA_TERM. */
+ regval = readb(p2);
+
+ /* Slave did not respond. */
+ if (regval & COMPLETION_MNAKX) {
+ writeb(COMPLETION_MNAKX, p2);
+ retval = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ if (i2c->flags & I2C_FLAGS_SMB_BLK_READ) {
+ buf[0] = readb(p3);
+ read_count = buf[0];
+ memcpy_fromio(&buf[1], p3 + 1, read_count);
+ } else {
+ memcpy_fromio(&buf[count], p3, transferlen);
+ }
+ }
+
+cleanup:
+ /* Disable all the interrupts. */
+ pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, false);
+ pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, false);
+ pci1xxxx_i2c_config_asr(i2c, false);
+ return retval;
+}
+
+static int pci1xxxx_i2c_write(struct pci1xxxx_i2c *i2c, u8 slaveaddr,
+ unsigned char *buf, u16 total_len)
+{
+ void __iomem *p2 = i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3;
+ void __iomem *p1 = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1;
+ unsigned long time_left;
+ u16 remainingbytes;
+ u8 actualwritelen;
+ u8 transferlen;
+ int retval = 0;
+ u32 regval;
+ u16 count;
+
+ /* Enable I2C host controller by setting the ESO bit in the CONTROL REG. */
+ pci1xxxx_i2c_enable_ESO(i2c);
+
+ /* Set the Buffer direction. */
+ pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_WRITE);
+ pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, true);
+ pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, true);
+
+ /*
+ * The i2c transfer could be more than 128 bytes. Our Core is
+ * capable of only sending 128 at a time.
+ */
+ for (count = 0; count < total_len; count += transferlen) {
+ /*
+ * Before start of any transaction clear the existing
+ * START/STOP conditions.
+ */
+ writeb(0, p1);
+ pci1xxxx_i2c_clear_flags(i2c);
+ remainingbytes = total_len - count;
+
+ /* If it is the starting of the transaction send START. */
+ if (count == 0) {
+ pci1xxxx_i2c_send_start_stop(i2c, 1);
+
+ /* -1 for the slave address. */
+ transferlen = min_t(u16, SMBUS_BUF_MAX_SIZE - 1,
+ remainingbytes);
+ pci1xxxx_i2c_buffer_write(i2c, slaveaddr,
+ transferlen, &buf[count]);
+ /*
+ * The actual number of bytes written on the I2C bus
+ * is including the slave address.
+ */
+ actualwritelen = transferlen + 1;
+ } else {
+ transferlen = min_t(u16, SMBUS_BUF_MAX_SIZE, remainingbytes);
+ pci1xxxx_i2c_buffer_write(i2c, 0, transferlen, &buf[count]);
+ actualwritelen = transferlen;
+ }
+
+ pci1xxxx_i2c_set_count(i2c, actualwritelen, actualwritelen, 0);
+
+ /*
+ * Send STOP only when I2C_FLAGS_STOP bit is set in the flags and
+ * only for the last transaction.
+ */
+ if (remainingbytes <= transferlen &&
+ (i2c->flags & I2C_FLAGS_STOP))
+ pci1xxxx_i2c_send_start_stop(i2c, 0);
+
+ pci1xxxx_i2c_start_DMA(i2c);
+
+ /*
+ * Wait for the DMA_TERM interrupt.
+ */
+ time_left = wait_for_completion_timeout(&i2c->i2c_xfer_done,
+ msecs_to_jiffies(PCI1XXXX_I2C_TIMEOUT_MS));
+ if (time_left == 0) {
+ /* Reset the I2C core to release the bus lock. */
+ pci1xxxx_i2c_init(i2c);
+ retval = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ regval = readb(p2);
+ if (regval & COMPLETION_MNAKX) {
+ writeb(COMPLETION_MNAKX, p2);
+ retval = -ETIMEDOUT;
+ goto cleanup;
+ }
+ }
+cleanup:
+ /* Disable all the interrupts. */
+ pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, false);
+ pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, false);
+
+ return retval;
+}
+
+static int pci1xxxx_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct pci1xxxx_i2c *i2c = i2c_get_adapdata(adap);
+ u8 slaveaddr;
+ int retval;
+ u32 i;
+
+ i2c->i2c_xfer_in_progress = true;
+ for (i = 0; i < num; i++) {
+ slaveaddr = i2c_8bit_addr_from_msg(&msgs[i]);
+
+ /*
+ * Send the STOP bit if the transfer is the final one or
+ * if the I2C_M_STOP flag is set.
+ */
+ if ((i == num - 1) || (msgs[i].flags & I2C_M_STOP))
+ i2c->flags |= I2C_FLAGS_STOP;
+ else
+ i2c->flags &= ~I2C_FLAGS_STOP;
+
+ if (msgs[i].flags & I2C_M_RECV_LEN)
+ i2c->flags |= I2C_FLAGS_SMB_BLK_READ;
+ else
+ i2c->flags &= ~I2C_FLAGS_SMB_BLK_READ;
+
+ if (msgs[i].flags & I2C_M_RD)
+ retval = pci1xxxx_i2c_read(i2c, slaveaddr,
+ msgs[i].buf, msgs[i].len);
+ else
+ retval = pci1xxxx_i2c_write(i2c, slaveaddr,
+ msgs[i].buf, msgs[i].len);
+
+ if (retval < 0)
+ break;
+ }
+ i2c->i2c_xfer_in_progress = false;
+
+ if (retval < 0)
+ return retval;
+
+ return num;
+}
+
+/*
+ * List of supported functions by the driver.
+ */
+static u32 pci1xxxx_i2c_get_funcs(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm pci1xxxx_i2c_algo = {
+ .master_xfer = pci1xxxx_i2c_xfer,
+ .functionality = pci1xxxx_i2c_get_funcs,
+};
+
+static const struct i2c_adapter_quirks pci1xxxx_i2c_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN,
+};
+
+static const struct i2c_adapter pci1xxxx_i2c_ops = {
+ .owner = THIS_MODULE,
+ .name = "PCI1xxxx I2C Adapter",
+ .algo = &pci1xxxx_i2c_algo,
+ .quirks = &pci1xxxx_i2c_quirks,
+};
+
+static int pci1xxxx_i2c_suspend(struct device *dev)
+{
+ struct pci1xxxx_i2c *i2c = dev_get_drvdata(dev);
+ void __iomem *p = i2c->i2c_base + SMBUS_RESET_REG;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u32 regval;
+
+ i2c_mark_adapter_suspended(&i2c->adap);
+
+ /*
+ * If the system is put into 'suspend' state when the I2C transfer is in
+ * progress, wait until the transfer completes.
+ */
+ while (i2c->i2c_xfer_in_progress)
+ msleep(20);
+
+ pci1xxxx_i2c_config_high_level_intr(i2c, SMBALERT_WAKE_INTR_MASK, true);
+
+ /*
+ * Enable the PERST_DIS bit to mask the PERST from resetting the core
+ * registers.
+ */
+ regval = readl(p);
+ regval |= PERI_SMBUS_D3_RESET_DIS;
+ writel(regval, p);
+
+ /* Enable PCI wake in the PMCSR register. */
+ device_set_wakeup_enable(dev, true);
+ pci_wake_from_d3(pdev, true);
+
+ return 0;
+}
+
+static int pci1xxxx_i2c_resume(struct device *dev)
+{
+ struct pci1xxxx_i2c *i2c = dev_get_drvdata(dev);
+ void __iomem *p1 = i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF;
+ void __iomem *p2 = i2c->i2c_base + SMBUS_RESET_REG;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u32 regval;
+
+ regval = readw(p1);
+ writew(regval, p1);
+ pci1xxxx_i2c_config_high_level_intr(i2c, SMBALERT_WAKE_INTR_MASK, false);
+ regval = readl(p2);
+ regval &= ~PERI_SMBUS_D3_RESET_DIS;
+ writel(regval, p2);
+ i2c_mark_adapter_resumed(&i2c->adap);
+ pci_wake_from_d3(pdev, false);
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_i2c_pm_ops, pci1xxxx_i2c_suspend,
+ pci1xxxx_i2c_resume);
+
+static void pci1xxxx_i2c_shutdown(struct pci1xxxx_i2c *i2c)
+{
+ pci1xxxx_i2c_config_padctrl(i2c, false);
+ pci1xxxx_i2c_configure_core_reg(i2c, false);
+}
+
+static int pci1xxxx_i2c_probe_pci(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct device *dev = &pdev->dev;
+ struct pci1xxxx_i2c *i2c;
+ int ret;
+
+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, i2c);
+ i2c->i2c_xfer_in_progress = false;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ /*
+ * We are getting the base address of the SMB core. SMB core uses
+ * BAR0 and size is 32K.
+ */
+ ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
+ if (ret < 0)
+ return ret;
+
+ i2c->i2c_base = pcim_iomap_table(pdev)[0];
+ init_completion(&i2c->i2c_xfer_done);
+ pci1xxxx_i2c_init(i2c);
+
+ ret = devm_add_action(dev, (void (*)(void *))pci1xxxx_i2c_shutdown, i2c);
+ if (ret)
+ return ret;
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_irq(dev, pci_irq_vector(pdev, 0), pci1xxxx_i2c_isr,
+ 0, pci_name(pdev), i2c);
+ if (ret)
+ return ret;
+
+ i2c->adap = pci1xxxx_i2c_ops;
+ i2c->adap.dev.parent = dev;
+
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+ "MCHP PCI1xxxx i2c adapter at %s", pci_name(pdev));
+
+ i2c_set_adapdata(&i2c->adap, i2c);
+
+ ret = devm_i2c_add_adapter(dev, &i2c->adap);
+ if (ret)
+ return dev_err_probe(dev, ret, "i2c add adapter failed\n");
+
+ return 0;
+}
+
+static const struct pci_device_id pci1xxxx_i2c_pci_id_table[] = {
+ { PCI_VDEVICE(EFAR, 0xA003) },
+ { PCI_VDEVICE(EFAR, 0xA013) },
+ { PCI_VDEVICE(EFAR, 0xA023) },
+ { PCI_VDEVICE(EFAR, 0xA033) },
+ { PCI_VDEVICE(EFAR, 0xA043) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, pci1xxxx_i2c_pci_id_table);
+
+static struct pci_driver pci1xxxx_i2c_pci_driver = {
+ .name = "i2c-mchp-pci1xxxx",
+ .id_table = pci1xxxx_i2c_pci_id_table,
+ .probe = pci1xxxx_i2c_probe_pci,
+ .driver = {
+ .pm = pm_sleep_ptr(&pci1xxxx_i2c_pm_ops),
+ },
+};
+module_pci_driver(pci1xxxx_i2c_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tharun Kumar P<tharunkumar.pasumarthi@microchip.com>");
+MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
+MODULE_DESCRIPTION("Microchip Technology Inc. pci1xxxx I2C bus driver");
diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c
index 60908c5737f1..e68e775f187e 100644
--- a/drivers/i2c/busses/i2c-mlxbf.c
+++ b/drivers/i2c/busses/i2c-mlxbf.c
@@ -32,8 +32,6 @@
(MLXBF_I2C_FUNC_SMBUS_DEFAULT | MLXBF_I2C_FUNC_SMBUS_BLOCK | \
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SLAVE)
-#define MLXBF_I2C_SMBUS_MAX 3
-
/* Shared resources info in BlueField platforms. */
#define MLXBF_I2C_COALESCE_TYU_ADDR 0x02801300
@@ -48,6 +46,9 @@
#define MLXBF_I2C_COREPLL_YU_ADDR 0x02800c30
#define MLXBF_I2C_COREPLL_YU_SIZE 0x00c
+#define MLXBF_I2C_COREPLL_RSH_YU_ADDR 0x13409824
+#define MLXBF_I2C_COREPLL_RSH_YU_SIZE 0x00c
+
#define MLXBF_I2C_SHARED_RES_MAX 3
/*
@@ -131,14 +132,10 @@
/* Slave busy bit reset. */
#define MLXBF_I2C_CAUSE_S_GW_BUSY_FALL BIT(18)
-#define MLXBF_I2C_CAUSE_SLAVE_ARBITER_BITS_MASK GENMASK(20, 0)
-
/* Cause coalesce registers. */
#define MLXBF_I2C_CAUSE_COALESCE_0 0x00
-#define MLXBF_I2C_CAUSE_COALESCE_1 0x04
-#define MLXBF_I2C_CAUSE_COALESCE_2 0x08
-#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT MLXBF_I2C_SMBUS_MAX
+#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT 3
#define MLXBF_I2C_CAUSE_YU_SLAVE_BIT 1
/* Functional enable register. */
@@ -165,15 +162,6 @@
#define MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(num, val) \
((val) | (0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num)))
-/* SMBus timing parameters. */
-#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00
-#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04
-#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08
-#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c
-#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10
-#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14
-#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18
-
/*
* Defines SMBus operating frequency and core clock frequency.
* According to ADB files, default values are compliant to 100KHz SMBus
@@ -192,26 +180,37 @@
#define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0)
#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26)
+/* SMBus timing parameters. */
+#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00
+#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04
+#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08
+#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c
+#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10
+#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14
+#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18
-/* Core PLL frequency. */
-static u64 mlxbf_i2c_corepll_frequency;
+#define MLXBF_I2C_SHIFT_0 0
+#define MLXBF_I2C_SHIFT_8 8
+#define MLXBF_I2C_SHIFT_16 16
+#define MLXBF_I2C_SHIFT_24 24
+
+#define MLXBF_I2C_MASK_8 GENMASK(7, 0)
+#define MLXBF_I2C_MASK_16 GENMASK(15, 0)
+
+#define MLXBF_I2C_MST_ADDR_OFFSET 0x200
/* SMBus Master GW. */
-#define MLXBF_I2C_SMBUS_MASTER_GW 0x200
+#define MLXBF_I2C_SMBUS_MASTER_GW 0x0
/* Number of bytes received and sent. */
-#define MLXBF_I2C_SMBUS_RS_BYTES 0x300
+#define MLXBF_I2C_YU_SMBUS_RS_BYTES 0x100
+#define MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES 0x10c
/* Packet error check (PEC) value. */
-#define MLXBF_I2C_SMBUS_MASTER_PEC 0x304
+#define MLXBF_I2C_SMBUS_MASTER_PEC 0x104
/* Status bits (ACK/NACK/FW Timeout). */
-#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x308
+#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x108
/* SMbus Master Finite State Machine. */
-#define MLXBF_I2C_SMBUS_MASTER_FSM 0x310
-
-/*
- * When enabled, the master will issue a stop condition in case of
- * timeout while waiting for FW response.
- */
-#define MLXBF_I2C_SMBUS_EN_FW_TIMEOUT 0x31c
+#define MLXBF_I2C_YU_SMBUS_MASTER_FSM 0x110
+#define MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM 0x100
/* SMBus master GW control bits offset in MLXBF_I2C_SMBUS_MASTER_GW[31:3]. */
#define MLXBF_I2C_MASTER_LOCK_BIT BIT(31) /* Lock bit. */
@@ -231,14 +230,14 @@ static u64 mlxbf_i2c_corepll_frequency;
#define MLXBF_I2C_MASTER_ENABLE_READ \
(MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_READ_BIT)
-#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address shift. */
-#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes shift. */
-#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte shift. */
-#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Parse expected bytes shift. */
-#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes shift. */
+#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes */
+#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte when set to 1 */
+#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Control parse expected bytes */
+#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address */
+#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes */
/* SMBus master GW Data descriptor. */
-#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x280
+#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x80
#define MLXBF_I2C_MASTER_DATA_DESC_SIZE 0x80 /* Size in bytes. */
/* Maximum bytes to read/write per SMBus transaction. */
@@ -264,19 +263,21 @@ static u64 mlxbf_i2c_corepll_frequency;
#define MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK BIT(31)
#define MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK BIT(15)
+#define MLXBF_I2C_SLV_ADDR_OFFSET 0x400
+
/* SMBus slave GW. */
-#define MLXBF_I2C_SMBUS_SLAVE_GW 0x400
+#define MLXBF_I2C_SMBUS_SLAVE_GW 0x0
/* Number of bytes received and sent from/to master. */
-#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x500
+#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x100
/* Packet error check (PEC) value. */
-#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x504
+#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x104
/* SMBus slave Finite State Machine (FSM). */
-#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x510
+#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x110
/*
* Should be set when all raised causes handled, and cleared by HW on
* every new cause.
*/
-#define MLXBF_I2C_SMBUS_SLAVE_READY 0x52c
+#define MLXBF_I2C_SMBUS_SLAVE_READY 0x12c
/* SMBus slave GW control bits offset in MLXBF_I2C_SMBUS_SLAVE_GW[31:19]. */
#define MLXBF_I2C_SLAVE_BUSY_BIT BIT(30) /* Busy bit. */
@@ -289,23 +290,74 @@ static u64 mlxbf_i2c_corepll_frequency;
#define MLXBF_I2C_SLAVE_SEND_PEC_SHIFT 21 /* Send PEC byte shift. */
/* SMBus slave GW Data descriptor. */
-#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x480
+#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x80
#define MLXBF_I2C_SLAVE_DATA_DESC_SIZE 0x80 /* Size in bytes. */
/* SMbus slave configuration registers. */
-#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x514
+#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x114
#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT 16
-#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT 7
+#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT BIT(7)
#define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0)
-#define MLXBF_I2C_SLAVE_ADDR_ENABLED(addr) \
- ((addr) & (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT))
-
/*
* Timeout is given in microsends. Note also that timeout handling is not
* exact.
*/
#define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */
+#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */
+
+/* Polling frequency in microseconds. */
+#define MLXBF_I2C_POLL_FREQ_IN_USEC 200
+
+#define MLXBF_I2C_SMBUS_OP_CNT_1 1
+#define MLXBF_I2C_SMBUS_OP_CNT_2 2
+#define MLXBF_I2C_SMBUS_OP_CNT_3 3
+#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3
+
+/* Helper macro to define an I2C resource parameters. */
+#define MLXBF_I2C_RES_PARAMS(addr, size, str) \
+ { \
+ .start = (addr), \
+ .end = (addr) + (size) - 1, \
+ .name = (str) \
+ }
+
+enum {
+ MLXBF_I2C_TIMING_100KHZ = 100000,
+ MLXBF_I2C_TIMING_400KHZ = 400000,
+ MLXBF_I2C_TIMING_1000KHZ = 1000000,
+};
+
+enum {
+ MLXBF_I2C_F_READ = BIT(0),
+ MLXBF_I2C_F_WRITE = BIT(1),
+ MLXBF_I2C_F_NORESTART = BIT(3),
+ MLXBF_I2C_F_SMBUS_OPERATION = BIT(4),
+ MLXBF_I2C_F_SMBUS_BLOCK = BIT(5),
+ MLXBF_I2C_F_SMBUS_PEC = BIT(6),
+ MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7),
+};
+
+/* Mellanox BlueField chip type. */
+enum mlxbf_i2c_chip_type {
+ MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */
+ MLXBF_I2C_CHIP_TYPE_2, /* Mellanox BlueField-2 chip. */
+ MLXBF_I2C_CHIP_TYPE_3 /* Mellanox BlueField-3 chip. */
+};
+
+/* List of chip resources that are being accessed by the driver. */
+enum {
+ MLXBF_I2C_SMBUS_RES,
+ MLXBF_I2C_MST_CAUSE_RES,
+ MLXBF_I2C_SLV_CAUSE_RES,
+ MLXBF_I2C_COALESCE_RES,
+ MLXBF_I2C_SMBUS_TIMER_RES,
+ MLXBF_I2C_SMBUS_MST_RES,
+ MLXBF_I2C_SMBUS_SLV_RES,
+ MLXBF_I2C_COREPLL_RES,
+ MLXBF_I2C_GPIO_RES,
+ MLXBF_I2C_END_RES
+};
/* Encapsulates timing parameters. */
struct mlxbf_i2c_timings {
@@ -326,27 +378,12 @@ struct mlxbf_i2c_timings {
u32 timeout; /* Detect clock low timeout. */
};
-enum {
- MLXBF_I2C_F_READ = BIT(0),
- MLXBF_I2C_F_WRITE = BIT(1),
- MLXBF_I2C_F_NORESTART = BIT(3),
- MLXBF_I2C_F_SMBUS_OPERATION = BIT(4),
- MLXBF_I2C_F_SMBUS_BLOCK = BIT(5),
- MLXBF_I2C_F_SMBUS_PEC = BIT(6),
- MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7),
-};
-
struct mlxbf_i2c_smbus_operation {
u32 flags;
u32 length; /* Buffer length in bytes. */
u8 *buffer;
};
-#define MLXBF_I2C_SMBUS_OP_CNT_1 1
-#define MLXBF_I2C_SMBUS_OP_CNT_2 2
-#define MLXBF_I2C_SMBUS_OP_CNT_3 3
-#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3
-
struct mlxbf_i2c_smbus_request {
u8 slave;
u8 operation_cnt;
@@ -360,24 +397,38 @@ struct mlxbf_i2c_resource {
u8 type;
};
-/* List of chip resources that are being accessed by the driver. */
-enum {
- MLXBF_I2C_SMBUS_RES,
- MLXBF_I2C_MST_CAUSE_RES,
- MLXBF_I2C_SLV_CAUSE_RES,
- MLXBF_I2C_COALESCE_RES,
- MLXBF_I2C_COREPLL_RES,
- MLXBF_I2C_GPIO_RES,
- MLXBF_I2C_END_RES,
+struct mlxbf_i2c_chip_info {
+ enum mlxbf_i2c_chip_type type;
+ /* Chip shared resources that are being used by the I2C controller. */
+ struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX];
+
+ /* Callback to calculate the core PLL frequency. */
+ u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res);
+
+ /* Registers' address offset */
+ u32 smbus_master_rs_bytes_off;
+ u32 smbus_master_fsm_off;
};
-/* Helper macro to define an I2C resource parameters. */
-#define MLXBF_I2C_RES_PARAMS(addr, size, str) \
- { \
- .start = (addr), \
- .end = (addr) + (size) - 1, \
- .name = (str) \
- }
+struct mlxbf_i2c_priv {
+ const struct mlxbf_i2c_chip_info *chip;
+ struct i2c_adapter adap;
+ struct mlxbf_i2c_resource *smbus;
+ struct mlxbf_i2c_resource *timer;
+ struct mlxbf_i2c_resource *mst;
+ struct mlxbf_i2c_resource *slv;
+ struct mlxbf_i2c_resource *mst_cause;
+ struct mlxbf_i2c_resource *slv_cause;
+ struct mlxbf_i2c_resource *coalesce;
+ u64 frequency; /* Core frequency in Hz. */
+ int bus; /* Physical bus identifier. */
+ int irq;
+ struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT];
+ u32 resource_version;
+};
+
+/* Core PLL frequency. */
+static u64 mlxbf_i2c_corepll_frequency;
static struct resource mlxbf_i2c_coalesce_tyu_params =
MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COALESCE_TYU_ADDR,
@@ -391,6 +442,10 @@ static struct resource mlxbf_i2c_corepll_yu_params =
MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_YU_ADDR,
MLXBF_I2C_COREPLL_YU_SIZE,
"COREPLL_MEM");
+static struct resource mlxbf_i2c_corepll_rsh_yu_params =
+ MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_RSH_YU_ADDR,
+ MLXBF_I2C_COREPLL_RSH_YU_SIZE,
+ "COREPLL_MEM");
static struct resource mlxbf_i2c_gpio_tyu_params =
MLXBF_I2C_RES_PARAMS(MLXBF_I2C_GPIO_TYU_ADDR,
MLXBF_I2C_GPIO_TYU_SIZE,
@@ -400,34 +455,6 @@ static struct mutex mlxbf_i2c_coalesce_lock;
static struct mutex mlxbf_i2c_corepll_lock;
static struct mutex mlxbf_i2c_gpio_lock;
-/* Mellanox BlueField chip type. */
-enum mlxbf_i2c_chip_type {
- MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */
- MLXBF_I2C_CHIP_TYPE_2, /* Mallanox BlueField-2 chip. */
-};
-
-struct mlxbf_i2c_chip_info {
- enum mlxbf_i2c_chip_type type;
- /* Chip shared resources that are being used by the I2C controller. */
- struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX];
-
- /* Callback to calculate the core PLL frequency. */
- u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res);
-};
-
-struct mlxbf_i2c_priv {
- const struct mlxbf_i2c_chip_info *chip;
- struct i2c_adapter adap;
- struct mlxbf_i2c_resource *smbus;
- struct mlxbf_i2c_resource *mst_cause;
- struct mlxbf_i2c_resource *slv_cause;
- struct mlxbf_i2c_resource *coalesce;
- u64 frequency; /* Core frequency in Hz. */
- int bus; /* Physical bus identifier. */
- int irq;
- struct i2c_client *slave;
-};
-
static struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = {
[MLXBF_I2C_CHIP_TYPE_1] = {
.params = &mlxbf_i2c_coalesce_tyu_params,
@@ -447,6 +474,11 @@ static struct mlxbf_i2c_resource mlxbf_i2c_corepll_res[] = {
.params = &mlxbf_i2c_corepll_yu_params,
.lock = &mlxbf_i2c_corepll_lock,
.type = MLXBF_I2C_COREPLL_RES,
+ },
+ [MLXBF_I2C_CHIP_TYPE_3] = {
+ .params = &mlxbf_i2c_corepll_rsh_yu_params,
+ .lock = &mlxbf_i2c_corepll_lock,
+ .type = MLXBF_I2C_COREPLL_RES,
}
};
@@ -463,24 +495,13 @@ static u8 mlxbf_i2c_bus_count;
static struct mutex mlxbf_i2c_bus_lock;
-/* Polling frequency in microseconds. */
-#define MLXBF_I2C_POLL_FREQ_IN_USEC 200
-
-#define MLXBF_I2C_SHIFT_0 0
-#define MLXBF_I2C_SHIFT_8 8
-#define MLXBF_I2C_SHIFT_16 16
-#define MLXBF_I2C_SHIFT_24 24
-
-#define MLXBF_I2C_MASK_8 GENMASK(7, 0)
-#define MLXBF_I2C_MASK_16 GENMASK(15, 0)
-
/*
* 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_smbus_poll(void __iomem *io, u32 addr, u32 mask,
+static u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask,
bool eq_zero, u32 timeout)
{
u32 bits;
@@ -502,18 +523,37 @@ static u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask,
* 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_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv)
+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 = MLXBF_I2C_SMBUS_MASTER_FSM;
+ u32 addr = priv->chip->smbus_master_fsm_off;
u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT;
- if (mlxbf_smbus_poll(priv->smbus->io, addr, mask, true, 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)
{
@@ -551,7 +591,7 @@ 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_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW,
+ mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW,
MLXBF_I2C_MASTER_BUSY_BIT, true,
MLXBF_I2C_SMBUS_TIMEOUT);
@@ -564,7 +604,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
* Parse both Cause and Master GW bits, then return transaction status.
*/
- master_status_bits = readl(priv->smbus->io +
+ master_status_bits = readl(priv->mst->io +
MLXBF_I2C_SMBUS_MASTER_STATUS);
master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK;
@@ -589,7 +629,8 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
}
static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv,
- const u8 *data, u8 length, u32 addr)
+ const u8 *data, u8 length, u32 addr,
+ bool is_master)
{
u8 offset, aligned_length;
u32 data32;
@@ -606,12 +647,16 @@ static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv,
*/
for (offset = 0; offset < aligned_length; offset += sizeof(u32)) {
data32 = *((u32 *)(data + offset));
- iowrite32be(data32, priv->smbus->io + addr + offset);
+ if (is_master)
+ iowrite32be(data32, priv->mst->io + addr + offset);
+ else
+ iowrite32be(data32, priv->slv->io + addr + offset);
}
}
static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv,
- u8 *data, u8 length, u32 addr)
+ u8 *data, u8 length, u32 addr,
+ bool is_master)
{
u32 data32, mask;
u8 byte, offset;
@@ -627,14 +672,20 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv,
*/
for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) {
- data32 = ioread32be(priv->smbus->io + addr + offset);
+ if (is_master)
+ data32 = ioread32be(priv->mst->io + addr + offset);
+ else
+ data32 = ioread32be(priv->slv->io + addr + offset);
*((u32 *)(data + offset)) = data32;
}
if (!(length & mask))
return;
- data32 = ioread32be(priv->smbus->io + addr + offset);
+ if (is_master)
+ data32 = ioread32be(priv->mst->io + addr + offset);
+ else
+ data32 = ioread32be(priv->slv->io + addr + offset);
for (byte = 0; byte < (length & mask); byte++) {
data[offset + byte] = data32 & GENMASK(7, 0);
@@ -660,16 +711,16 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave,
command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT);
/* Clear status bits. */
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS);
+ writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_STATUS);
/* Set the cause data. */
writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR);
/* Zero PEC byte. */
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC);
+ writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_PEC);
/* Zero byte count. */
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES);
+ writel(0x0, priv->mst->io + priv->chip->smbus_master_rs_bytes_off);
/* GW activation. */
- writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW);
+ writel(command, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW);
/*
* Poll master status and check status bits. An ACK is sent when
@@ -705,10 +756,19 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
slave = request->slave & GENMASK(6, 0);
addr = slave << 1;
- /* First of all, check whether the HW is idle. */
- if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(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)))
return -EBUSY;
+ /* Check whether the HW is idle */
+ if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
/* Set first byte. */
data_desc[data_idx++] = addr;
@@ -732,8 +792,10 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
write_en = 1;
write_len += operation->length;
if (data_idx + operation->length >
- MLXBF_I2C_MASTER_DATA_DESC_SIZE)
- return -ENOBUFS;
+ MLXBF_I2C_MASTER_DATA_DESC_SIZE) {
+ ret = -ENOBUFS;
+ goto out_unlock;
+ }
memcpy(data_desc + data_idx,
operation->buffer, operation->length);
data_idx += operation->length;
@@ -759,25 +821,25 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
* must be written to the data registers.
*/
mlxbf_i2c_smbus_write_data(priv, (const u8 *)data_desc, data_len,
- MLXBF_I2C_MASTER_DATA_DESC_ADDR);
+ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true);
if (write_en) {
ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en,
pec_en, 0);
if (ret)
- return ret;
+ goto out_unlock;
}
if (read_en) {
/* Write slave address to Master GW data descriptor. */
mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1,
- MLXBF_I2C_MASTER_DATA_DESC_ADDR);
+ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true);
ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en,
pec_en, 1);
if (!ret) {
/* Get Master GW data descriptor. */
mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1,
- MLXBF_I2C_MASTER_DATA_DESC_ADDR);
+ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true);
/* Get data from Master GW data descriptor. */
memcpy(read_buf, data_desc, read_len + 1);
@@ -789,9 +851,12 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
* next tag integration.
*/
writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK,
- priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM);
+ priv->mst->io + priv->chip->smbus_master_fsm_off);
}
+out_unlock:
+ mlxbf_i2c_smbus_master_unlock(priv);
+
return ret;
}
@@ -1078,7 +1143,7 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
timer |= mlxbf_i2c_set_timer(priv, timings->scl_low,
false, MLXBF_I2C_MASK_16,
MLXBF_I2C_SHIFT_16);
- writel(timer, priv->smbus->io +
+ writel(timer, priv->timer->io +
MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH);
timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false,
@@ -1089,34 +1154,34 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16);
timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false,
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24);
- writel(timer, priv->smbus->io +
+ writel(timer, priv->timer->io +
MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE);
timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD);
+ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_THOLD);
timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
- writel(timer, priv->smbus->io +
+ writel(timer, priv->timer->io +
MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP);
timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA);
+ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA);
timer = mlxbf_i2c_set_timer(priv, timings->buf, false,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false,
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF);
+ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF);
timer = timings->timeout;
- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT);
+ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT);
}
enum mlxbf_i2c_timings_config {
@@ -1509,28 +1574,26 @@ static int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev,
return 0;
}
-static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
+static int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv,
+ struct i2c_client *slave)
{
- u32 slave_reg, slave_reg_tmp, slave_reg_avail, slave_addr_mask;
- u8 reg, reg_cnt, byte, addr_tmp, reg_avail, byte_avail;
- bool avail, disabled;
-
- disabled = false;
- avail = false;
+ u8 reg, reg_cnt, byte, addr_tmp;
+ u32 slave_reg, slave_reg_tmp;
if (!priv)
return -EPERM;
reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2;
- slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK;
/*
* Read the slave registers. There are 4 * 32-bit slave registers.
- * Each slave register can hold up to 4 * 8-bit slave configuration
- * (7-bit address, 1 status bit (1 if enabled, 0 if not)).
+ * Each slave register can hold up to 4 * 8-bit slave configuration:
+ * 1) A 7-bit address
+ * 2) And a status bit (1 if enabled, 0 if not).
+ * Look for the next available slave register slot.
*/
for (reg = 0; reg < reg_cnt; reg++) {
- slave_reg = readl(priv->smbus->io +
+ slave_reg = readl(priv->slv->io +
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
/*
* Each register holds 4 slave addresses. So, we have to keep
@@ -1542,121 +1605,87 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
addr_tmp = slave_reg_tmp & GENMASK(7, 0);
/*
- * Mark the first available slave address slot, i.e. its
- * enabled bit should be unset. This slot might be used
- * later on to register our slave.
+ * If an enable bit is not set in the
+ * MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG register, then the
+ * slave address slot associated with that bit is
+ * free. So set the enable bit and write the
+ * slave address bits.
*/
- if (!avail && !MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) {
- avail = true;
- reg_avail = reg;
- byte_avail = byte;
- slave_reg_avail = slave_reg;
- }
-
- /*
- * Parse slave address bytes and check whether the
- * slave address already exists and it's enabled,
- * i.e. most significant bit is set.
- */
- if ((addr_tmp & slave_addr_mask) == addr) {
- if (MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp))
- return 0;
- disabled = true;
- break;
+ if (!(addr_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) {
+ slave_reg &= ~(MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK << (byte * 8));
+ slave_reg |= (slave->addr << (byte * 8));
+ slave_reg |= MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT << (byte * 8);
+ writel(slave_reg, priv->slv->io +
+ MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
+ (reg * 0x4));
+
+ /*
+ * Set the slave at the corresponding index.
+ */
+ priv->slave[(reg * 4) + byte] = slave;
+
+ return 0;
}
/* Parse next byte. */
slave_reg_tmp >>= 8;
}
-
- /* Exit the loop if the slave address is found. */
- if (disabled)
- break;
- }
-
- if (!avail && !disabled)
- return -EINVAL; /* No room for a new slave address. */
-
- if (avail && !disabled) {
- reg = reg_avail;
- byte = byte_avail;
- /* Set the slave address. */
- slave_reg_avail &= ~(slave_addr_mask << (byte * 8));
- slave_reg_avail |= addr << (byte * 8);
- slave_reg = slave_reg_avail;
}
- /* Enable the slave address and update the register. */
- slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8);
- writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
- reg * 0x4);
-
- return 0;
+ return -EBUSY;
}
-static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv)
+static int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr)
{
- u32 slave_reg, slave_reg_tmp, slave_addr_mask;
- u8 addr, addr_tmp, reg, reg_cnt, slave_byte;
- struct i2c_client *client = priv->slave;
- bool exist;
-
- exist = false;
+ u8 addr_tmp, reg, reg_cnt, byte;
+ u32 slave_reg, slave_reg_tmp;
- addr = client->addr;
reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2;
- slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK;
/*
* Read the slave registers. There are 4 * 32-bit slave registers.
- * Each slave register can hold up to 4 * 8-bit slave configuration
- * (7-bit address, 1 status bit (1 if enabled, 0 if not)).
+ * Each slave register can hold up to 4 * 8-bit slave configuration:
+ * 1) A 7-bit address
+ * 2) And a status bit (1 if enabled, 0 if not).
+ * Check if addr is present in the registers.
*/
for (reg = 0; reg < reg_cnt; reg++) {
- slave_reg = readl(priv->smbus->io +
+ slave_reg = readl(priv->slv->io +
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
/* Check whether the address slots are empty. */
- if (slave_reg == 0)
+ if (!slave_reg)
continue;
/*
- * Each register holds 4 slave addresses. So, we have to keep
- * the byte order consistent with the value read in order to
- * update the register correctly, if needed.
+ * Check if addr matches any of the 4 slave addresses
+ * in the register.
*/
slave_reg_tmp = slave_reg;
- slave_byte = 0;
- while (slave_reg_tmp != 0) {
- addr_tmp = slave_reg_tmp & slave_addr_mask;
+ for (byte = 0; byte < 4; byte++) {
+ addr_tmp = slave_reg_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK;
/*
* Parse slave address bytes and check whether the
* slave address already exists.
*/
if (addr_tmp == addr) {
- exist = true;
- break;
+ /* Clear the slave address slot. */
+ slave_reg &= ~(GENMASK(7, 0) << (byte * 8));
+ writel(slave_reg, priv->slv->io +
+ MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
+ (reg * 0x4));
+ /* Free slave at the corresponding index */
+ priv->slave[(reg * 4) + byte] = NULL;
+
+ return 0;
}
/* Parse next byte. */
slave_reg_tmp >>= 8;
- slave_byte += 1;
}
-
- /* Exit the loop if the slave address is found. */
- if (exist)
- break;
}
- if (!exist)
- return 0; /* Slave is not registered, nothing to do. */
-
- /* Cleanup the slave address slot. */
- slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8));
- writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
- reg * 0x4);
-
- return 0;
+ return -ENXIO;
}
static int mlxbf_i2c_init_coalesce(struct platform_device *pdev,
@@ -1746,7 +1775,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
int ret;
/* Reset FSM. */
- writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM);
+ writel(0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_FSM);
/*
* Enable slave cause interrupt bits. Drive
@@ -1761,7 +1790,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0);
/* Finally, set the 'ready' bit to start handling transactions. */
- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
+ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY);
/* Initialize the cause coalesce resource. */
ret = mlxbf_i2c_init_coalesce(pdev, priv);
@@ -1806,84 +1835,93 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read,
return true;
}
-static bool mlxbf_smbus_slave_wait_for_idle(struct mlxbf_i2c_priv *priv,
+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_smbus_poll(priv->slv_cause->io, addr, mask, false, timeout))
+ if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout))
return true;
return false;
}
-/* Send byte to 'external' smbus master. */
-static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
+static struct i2c_client *mlxbf_i2c_get_slave_from_addr(
+ struct mlxbf_i2c_priv *priv, u8 addr)
{
- u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 };
- u8 write_size, pec_en, addr, byte, value, byte_cnt, desc_size;
- struct i2c_client *slave = priv->slave;
- u32 control32, data32;
- int ret;
+ int i;
- if (!slave)
- return -EINVAL;
+ for (i = 0; i < MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT; i++) {
+ if (!priv->slave[i])
+ continue;
- addr = 0;
- byte = 0;
- desc_size = MLXBF_I2C_SLAVE_DATA_DESC_SIZE;
+ if (priv->slave[i]->addr == addr)
+ return priv->slave[i];
+ }
+
+ return NULL;
+}
+
+/*
+ * Send byte to 'external' smbus master. This function is executed when
+ * an external smbus master wants to read data from the BlueField.
+ */
+static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
+{
+ u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 };
+ u8 write_size, pec_en, addr, value, byte_cnt;
+ struct i2c_client *slave;
+ u32 control32, data32;
+ int ret = 0;
/*
- * Read bytes received from the external master. These bytes should
- * be located in the first data descriptor register of the slave GW.
- * These bytes are the slave address byte and the internal register
- * address, if supplied.
+ * Read the first byte received from the external master to
+ * determine the slave address. This byte is located in the
+ * first data descriptor register of the slave GW.
*/
- if (recv_bytes > 0) {
- data32 = ioread32be(priv->smbus->io +
- MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
-
- /* Parse the received bytes. */
- switch (recv_bytes) {
- case 2:
- byte = (data32 >> 8) & GENMASK(7, 0);
- fallthrough;
- case 1:
- addr = (data32 & GENMASK(7, 0)) >> 1;
- }
+ data32 = ioread32be(priv->slv->io +
+ MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
+ addr = (data32 & GENMASK(7, 0)) >> 1;
- /* Check whether it's our slave address. */
- if (slave->addr != addr)
- return -EINVAL;
+ /*
+ * Check if the slave address received in the data descriptor register
+ * matches any of the slave addresses registered. If there is a match,
+ * set the slave.
+ */
+ slave = mlxbf_i2c_get_slave_from_addr(priv, addr);
+ if (!slave) {
+ ret = -ENXIO;
+ goto clear_csr;
}
/*
- * I2C read transactions may start by a WRITE followed by a READ.
- * Indeed, most slave devices would expect the internal address
- * following the slave address byte. So, write that byte first,
- * and then, send the requested data bytes to the master.
+ * An I2C read can consist of a WRITE bit transaction followed by
+ * a READ bit transaction. Indeed, slave devices often expect
+ * the slave address to be followed by the internal address.
+ * So, write the internal address byte first, and then, send the
+ * requested data to the master.
*/
if (recv_bytes > 1) {
i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
- value = byte;
+ value = (data32 >> 8) & GENMASK(7, 0);
ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED,
&value);
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
if (ret < 0)
- return ret;
+ goto clear_csr;
}
/*
- * Now, send data to the master; currently, the driver supports
- * READ_BYTE, READ_WORD and BLOCK READ protocols. Note that the
- * hardware can send up to 128 bytes per transfer. That is the
- * size of its data registers.
+ * Send data to the master. Currently, the driver supports
+ * READ_BYTE, READ_WORD and BLOCK READ protocols. The
+ * hardware can send up to 128 bytes per transfer which is
+ * the total size of the data registers.
*/
i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
- for (byte_cnt = 0; byte_cnt < desc_size; byte_cnt++) {
+ for (byte_cnt = 0; byte_cnt < MLXBF_I2C_SLAVE_DATA_DESC_SIZE; byte_cnt++) {
data_desc[byte_cnt] = value;
i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
}
@@ -1891,14 +1929,12 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
/* Send a stop condition to the backend. */
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
- /* Handle the actual transfer. */
-
/* Set the number of bytes to write to master. */
write_size = (byte_cnt - 1) & 0x7f;
/* Write data to Slave GW data descriptor. */
mlxbf_i2c_smbus_write_data(priv, data_desc, byte_cnt,
- MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
+ MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false);
pec_en = 0; /* Disable PEC since it is not supported. */
@@ -1907,46 +1943,52 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT);
control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT);
- writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW);
+ writel(control32, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_GW);
/*
* 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_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
+ mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
+clear_csr:
/* Release the Slave GW. */
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
+ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
+ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
+ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY);
- return 0;
+ return ret;
}
-/* Receive bytes from 'external' smbus master. */
-static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
+/*
+ * Receive bytes from 'external' smbus master. This function is executed when
+ * an external smbus master wants to write data to the BlueField.
+ */
+static int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
{
u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 };
- struct i2c_client *slave = priv->slave;
+ struct i2c_client *slave;
u8 value, byte, addr;
int ret = 0;
- if (!slave)
- return -EINVAL;
-
/* Read data from Slave GW data descriptor. */
mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes,
- MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
-
- /* Check whether its our slave address. */
+ MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false);
addr = data_desc[0] >> 1;
- if (slave->addr != addr)
- return -EINVAL;
/*
- * Notify the slave backend; another I2C master wants to write data
- * to us. This event is sent once the slave address and the write bit
- * is detected.
+ * Check if the slave address received in the data descriptor register
+ * matches any of the slave addresses registered.
+ */
+ slave = mlxbf_i2c_get_slave_from_addr(priv, addr);
+ if (!slave) {
+ ret = -EINVAL;
+ goto clear_csr;
+ }
+
+ /*
+ * Notify the slave backend that an smbus master wants to write data
+ * to the BlueField.
*/
i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
@@ -1959,18 +2001,22 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
break;
}
- /* Send a stop condition to the backend. */
+ /*
+ * Send a stop event to the slave backend, to signal
+ * the end of the write transactions.
+ */
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+clear_csr:
/* Release the Slave GW. */
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
+ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
+ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
+ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY);
return ret;
}
-static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr)
+static irqreturn_t mlxbf_i2c_irq(int irq, void *ptr)
{
struct mlxbf_i2c_priv *priv = ptr;
bool read, write, irq_is_set;
@@ -2000,7 +2046,7 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr)
* slave, if the higher 8 bits are sent then the slave expect N bytes
* from the master.
*/
- rw_bytes_reg = readl(priv->smbus->io +
+ rw_bytes_reg = readl(priv->slv->io +
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0);
@@ -2018,9 +2064,9 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr)
MLXBF_I2C_SLAVE_DATA_DESC_SIZE : recv_bytes;
if (read)
- mlxbf_smbus_irq_send(priv, recv_bytes);
+ mlxbf_i2c_irq_send(priv, recv_bytes);
else
- mlxbf_smbus_irq_recv(priv, recv_bytes);
+ mlxbf_i2c_irq_recv(priv, recv_bytes);
return IRQ_HANDLED;
}
@@ -2115,23 +2161,21 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
static int mlxbf_i2c_reg_slave(struct i2c_client *slave)
{
struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
+ struct device *dev = &slave->dev;
int ret;
- if (priv->slave)
- return -EBUSY;
-
/*
* Do not support ten bit chip address and do not use Packet Error
* Checking (PEC).
*/
- if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC))
+ if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) {
+ dev_err(dev, "SMBus PEC and 10 bit address not supported\n");
return -EAFNOSUPPORT;
+ }
- ret = mlxbf_slave_enable(priv, slave->addr);
- if (ret < 0)
- return ret;
-
- priv->slave = slave;
+ ret = mlxbf_i2c_slave_enable(priv, slave);
+ if (ret)
+ dev_err(dev, "Surpassed max number of registered slaves allowed\n");
return 0;
}
@@ -2139,18 +2183,19 @@ static int mlxbf_i2c_reg_slave(struct i2c_client *slave)
static int mlxbf_i2c_unreg_slave(struct i2c_client *slave)
{
struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
+ struct device *dev = &slave->dev;
int ret;
- WARN_ON(!priv->slave);
-
- /* Unregister slave, i.e. disable the slave address in hardware. */
- ret = mlxbf_slave_disable(priv);
- if (ret < 0)
- return ret;
-
- priv->slave = NULL;
+ /*
+ * Unregister slave by:
+ * 1) Disabling the slave address in hardware
+ * 2) Freeing priv->slave at the corresponding index
+ */
+ ret = mlxbf_i2c_slave_disable(priv, slave->addr);
+ if (ret)
+ dev_err(dev, "Unable to find slave 0x%x\n", slave->addr);
- return 0;
+ return ret;
}
static u32 mlxbf_i2c_functionality(struct i2c_adapter *adap)
@@ -2166,14 +2211,27 @@ static struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = {
[1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1],
[2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1]
},
- .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu
+ .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu,
+ .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES,
+ .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM
},
[MLXBF_I2C_CHIP_TYPE_2] = {
.type = MLXBF_I2C_CHIP_TYPE_2,
.shared_res = {
[0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2]
},
- .calculate_freq = mlxbf_i2c_calculate_freq_from_yu
+ .calculate_freq = mlxbf_i2c_calculate_freq_from_yu,
+ .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES,
+ .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM
+ },
+ [MLXBF_I2C_CHIP_TYPE_3] = {
+ .type = MLXBF_I2C_CHIP_TYPE_3,
+ .shared_res = {
+ [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_3]
+ },
+ .calculate_freq = mlxbf_i2c_calculate_freq_from_yu,
+ .smbus_master_rs_bytes_off = MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES,
+ .smbus_master_fsm_off = MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM
}
};
@@ -2189,24 +2247,11 @@ static struct i2c_adapter_quirks mlxbf_i2c_quirks = {
.max_write_len = MLXBF_I2C_MASTER_DATA_W_LENGTH,
};
-static const struct of_device_id mlxbf_i2c_dt_ids[] = {
- {
- .compatible = "mellanox,i2c-mlxbf1",
- .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1]
- },
- {
- .compatible = "mellanox,i2c-mlxbf2",
- .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2]
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids);
-
#ifdef CONFIG_ACPI
static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = {
{ "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] },
{ "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] },
+ { "MLNXBF31", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] },
{},
};
@@ -2244,36 +2289,12 @@ static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
}
#endif /* CONFIG_ACPI */
-static int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
-{
- const struct of_device_id *oid;
- int bus_id = -1;
-
- if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
- oid = of_match_node(mlxbf_i2c_dt_ids, dev->of_node);
- if (!oid)
- return -ENODEV;
-
- priv->chip = oid->data;
-
- bus_id = of_alias_get_id(dev->of_node, "i2c");
- if (bus_id >= 0)
- priv->bus = bus_id;
- }
-
- if (bus_id < 0) {
- dev_err(dev, "Cannot get bus id");
- return bus_id;
- }
-
- return 0;
-}
-
static int mlxbf_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mlxbf_i2c_priv *priv;
struct i2c_adapter *adap;
+ u32 resource_version;
int irq, ret;
priv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_priv), GFP_KERNEL);
@@ -2281,17 +2302,63 @@ static int mlxbf_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
ret = mlxbf_i2c_acpi_probe(dev, priv);
- if (ret < 0 && ret != -ENOENT && ret != -ENXIO)
- ret = mlxbf_i2c_of_probe(dev, priv);
-
if (ret < 0)
return ret;
- ret = mlxbf_i2c_init_resource(pdev, &priv->smbus,
- MLXBF_I2C_SMBUS_RES);
- if (ret < 0) {
- dev_err(dev, "Cannot fetch smbus resource info");
- return ret;
+ /* This property allows the driver to stay backward compatible with older
+ * ACPI tables.
+ * Starting BlueField-3 SoC, the "smbus" resource was broken down into 3
+ * separate resources "timer", "master" and "slave".
+ */
+ if (device_property_read_u32(dev, "resource_version", &resource_version))
+ resource_version = 0;
+
+ priv->resource_version = resource_version;
+
+ if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && resource_version == 0) {
+ priv->timer = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL);
+ if (!priv->timer)
+ return -ENOMEM;
+
+ priv->mst = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL);
+ if (!priv->mst)
+ return -ENOMEM;
+
+ priv->slv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL);
+ if (!priv->slv)
+ return -ENOMEM;
+
+ ret = mlxbf_i2c_init_resource(pdev, &priv->smbus,
+ MLXBF_I2C_SMBUS_RES);
+ if (ret < 0) {
+ dev_err(dev, "Cannot fetch smbus resource info");
+ return ret;
+ }
+
+ priv->timer->io = priv->smbus->io;
+ priv->mst->io = priv->smbus->io + MLXBF_I2C_MST_ADDR_OFFSET;
+ priv->slv->io = priv->smbus->io + MLXBF_I2C_SLV_ADDR_OFFSET;
+ } else {
+ ret = mlxbf_i2c_init_resource(pdev, &priv->timer,
+ MLXBF_I2C_SMBUS_TIMER_RES);
+ if (ret < 0) {
+ dev_err(dev, "Cannot fetch timer resource info");
+ return ret;
+ }
+
+ ret = mlxbf_i2c_init_resource(pdev, &priv->mst,
+ MLXBF_I2C_SMBUS_MST_RES);
+ if (ret < 0) {
+ dev_err(dev, "Cannot fetch master resource info");
+ return ret;
+ }
+
+ ret = mlxbf_i2c_init_resource(pdev, &priv->slv,
+ MLXBF_I2C_SMBUS_SLV_RES);
+ if (ret < 0) {
+ dev_err(dev, "Cannot fetch slave resource info");
+ return ret;
+ }
}
ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause,
@@ -2350,8 +2417,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, mlxbf_smbus_irq,
- IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED,
+ ret = devm_request_irq(dev, irq, mlxbf_i2c_irq,
+ IRQF_SHARED | IRQF_PROBE_SHARED,
dev_name(dev), priv);
if (ret < 0) {
dev_err(dev, "Cannot get irq %d\n", irq);
@@ -2379,8 +2446,19 @@ static int mlxbf_i2c_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *params;
- params = priv->smbus->params;
- devm_release_mem_region(dev, params->start, resource_size(params));
+ if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && priv->resource_version == 0) {
+ params = priv->smbus->params;
+ devm_release_mem_region(dev, params->start, resource_size(params));
+ } else {
+ params = priv->timer->params;
+ devm_release_mem_region(dev, params->start, resource_size(params));
+
+ params = priv->mst->params;
+ devm_release_mem_region(dev, params->start, resource_size(params));
+
+ params = priv->slv->params;
+ devm_release_mem_region(dev, params->start, resource_size(params));
+ }
params = priv->mst_cause->params;
devm_release_mem_region(dev, params->start, resource_size(params));
@@ -2412,7 +2490,6 @@ static struct platform_driver mlxbf_i2c_driver = {
.remove = mlxbf_i2c_remove,
.driver = {
.name = "i2c-mlxbf",
- .of_match_table = mlxbf_i2c_dt_ids,
#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids),
#endif /* CONFIG_ACPI */
@@ -2445,4 +2522,5 @@ module_exit(mlxbf_i2c_exit);
MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver");
MODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>");
+MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index ecba1dfc1278..849848ccb080 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -400,7 +400,6 @@ static int riic_i2c_probe(struct platform_device *pdev)
{
struct riic_dev *riic;
struct i2c_adapter *adap;
- struct resource *res;
struct i2c_timings i2c_t;
struct reset_control *rstc;
int i, ret;
@@ -409,8 +408,7 @@ static int riic_i2c_probe(struct platform_device *pdev)
if (!riic)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- riic->base = devm_ioremap_resource(&pdev->dev, res);
+ riic->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(riic->base))
return PTR_ERR(riic->base);
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 2e98e7793bba..d1658ed76562 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -1165,6 +1165,11 @@ static const struct rk3x_i2c_soc_data rv1108_soc_data = {
.calc_timings = rk3x_i2c_v1_calc_timings,
};
+static const struct rk3x_i2c_soc_data rv1126_soc_data = {
+ .grf_offset = 0x118,
+ .calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
static const struct rk3x_i2c_soc_data rk3066_soc_data = {
.grf_offset = 0x154,
.calc_timings = rk3x_i2c_v0_calc_timings,
@@ -1196,6 +1201,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
.data = &rv1108_soc_data
},
{
+ .compatible = "rockchip,rv1126-i2c",
+ .data = &rv1126_soc_data
+ },
+ {
.compatible = "rockchip,rk3066-i2c",
.data = &rk3066_soc_data
},
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index 6746aa46d96c..0239e134b90f 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -6,15 +6,13 @@
*/
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
-#define ACPI_SMBUS_HC_CLASS "smbus"
-#define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
-
/* SMBUS HID definition as supported by Microsoft Windows */
#define ACPI_SMBUS_MS_HID "SMB0001"
@@ -30,7 +28,7 @@ struct acpi_smbus_cmi {
u8 cap_info:1;
u8 cap_read:1;
u8 cap_write:1;
- struct smbus_methods_t *methods;
+ const struct smbus_methods_t *methods;
};
static const struct smbus_methods_t smbus_methods = {
@@ -358,29 +356,25 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
return AE_OK;
}
-static int acpi_smbus_cmi_add(struct acpi_device *device)
+static int smbus_cmi_probe(struct platform_device *device)
{
+ struct device *dev = &device->dev;
struct acpi_smbus_cmi *smbus_cmi;
- const struct acpi_device_id *id;
int ret;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi)
return -ENOMEM;
- smbus_cmi->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
- device->driver_data = smbus_cmi;
+ smbus_cmi->handle = ACPI_HANDLE(dev);
+ smbus_cmi->methods = device_get_match_data(dev);
+
+ platform_set_drvdata(device, smbus_cmi);
+
smbus_cmi->cap_info = 0;
smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 0;
- for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
- if (!strcmp(id->id, acpi_device_hid(device)))
- smbus_cmi->methods =
- (struct smbus_methods_t *) id->driver_data;
-
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
@@ -390,8 +384,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
}
snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
- "SMBus CMI adapter %s",
- acpi_device_name(device));
+ "SMBus CMI adapter %s", dev_name(dev));
smbus_cmi->adapter.owner = THIS_MODULE;
smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
smbus_cmi->adapter.algo_data = smbus_cmi;
@@ -408,31 +401,28 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
err:
kfree(smbus_cmi);
- device->driver_data = NULL;
return ret;
}
-static int acpi_smbus_cmi_remove(struct acpi_device *device)
+static int smbus_cmi_remove(struct platform_device *device)
{
- struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
+ struct acpi_smbus_cmi *smbus_cmi = platform_get_drvdata(device);
i2c_del_adapter(&smbus_cmi->adapter);
kfree(smbus_cmi);
- device->driver_data = NULL;
return 0;
}
-static struct acpi_driver acpi_smbus_cmi_driver = {
- .name = ACPI_SMBUS_HC_DEVICE_NAME,
- .class = ACPI_SMBUS_HC_CLASS,
- .ids = acpi_smbus_cmi_ids,
- .ops = {
- .add = acpi_smbus_cmi_add,
- .remove = acpi_smbus_cmi_remove,
+static struct platform_driver smbus_cmi_driver = {
+ .probe = smbus_cmi_probe,
+ .remove = smbus_cmi_remove,
+ .driver = {
+ .name = "smbus_cmi",
+ .acpi_match_table = acpi_smbus_cmi_ids,
},
};
-module_acpi_driver(acpi_smbus_cmi_driver);
+module_platform_driver(smbus_cmi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 031c78ac42e6..954022c04cc4 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -443,11 +443,16 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
u32 *dma_buf;
int err;
- if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi)
+ if (i2c_dev->is_vi)
return 0;
- if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
- dev_dbg(i2c_dev->dev, "DMA support not enabled\n");
+ if (!i2c_dev->hw->has_apb_dma) {
+ if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
+ dev_dbg(i2c_dev->dev, "APB DMA support not enabled\n");
+ return 0;
+ }
+ } else if (!IS_ENABLED(CONFIG_TEGRA186_GPC_DMA)) {
+ dev_dbg(i2c_dev->dev, "GPC DMA support not enabled\n");
return 0;
}