diff options
Diffstat (limited to 'drivers/i2c')
24 files changed, 1840 insertions, 495 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7284206b278b..264e780ae32e 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -488,8 +488,8 @@ config I2C_BCM_KONA config I2C_BRCMSTB tristate "BRCM Settop/DSL I2C controller" - depends on ARCH_BCM2835 || ARCH_BCM4908 || ARCH_BCMBCA || \ - ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST + depends on ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || \ + BMIPS_GENERIC || COMPILE_TEST default y help If you say yes to this option, support will be included for the @@ -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; } diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index f88386d732d2..4dd777cc0c89 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -26,7 +26,7 @@ struct gsb_buffer { union { u16 wdata; u8 bdata; - u8 data[0]; + DECLARE_FLEX_ARRAY(u8, data); }; } __packed; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index fc4b85fb90b1..b4edf10e8fd0 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -603,13 +603,9 @@ static void i2c_device_remove(struct device *dev) driver = to_i2c_driver(dev->driver); if (driver->remove) { - int status; - dev_dbg(dev, "remove\n"); - status = driver->remove(client); - if (status) - dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status)); + driver->remove(client); } devres_release_group(&client->dev, client->devres_group_id); diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 5c7ae421cacf..4abc2d919881 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -181,14 +181,12 @@ static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_de return 0; }; -static int i2c_slave_eeprom_remove(struct i2c_client *client) +static void i2c_slave_eeprom_remove(struct i2c_client *client) { struct eeprom_data *eeprom = i2c_get_clientdata(client); i2c_slave_unregister(client); sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin); - - return 0; } static const struct i2c_device_id i2c_slave_eeprom_id[] = { diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index 56dae08dfd48..75ee7ebdb614 100644 --- a/drivers/i2c/i2c-slave-testunit.c +++ b/drivers/i2c/i2c-slave-testunit.c @@ -153,13 +153,12 @@ static int i2c_slave_testunit_probe(struct i2c_client *client) return i2c_slave_register(client, i2c_slave_testunit_slave_cb); }; -static int i2c_slave_testunit_remove(struct i2c_client *client) +static void i2c_slave_testunit_remove(struct i2c_client *client) { struct testunit_data *tu = i2c_get_clientdata(client); cancel_delayed_work_sync(&tu->worker); i2c_slave_unregister(client); - return 0; } static const struct i2c_device_id i2c_slave_testunit_id[] = { diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 8ba9b59a3c40..07c92c8495a3 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -153,12 +153,11 @@ static int smbalert_probe(struct i2c_client *ara, } /* IRQ and memory resources are managed so they are freed automatically */ -static int smbalert_remove(struct i2c_client *ara) +static void smbalert_remove(struct i2c_client *ara) { struct i2c_smbus_alert *alert = i2c_get_clientdata(ara); cancel_work_sync(&alert->alert); - return 0; } static const struct i2c_device_id smbalert_ids[] = { diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 1708b1a82da2..ea838dbae32e 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -9,7 +9,7 @@ menu "Multiplexer I2C Chip support" config I2C_ARB_GPIO_CHALLENGE tristate "GPIO-based I2C arbitration" depends on GPIOLIB || COMPILE_TEST - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for an I2C multimaster arbitration scheme using GPIOs and a challenge & @@ -34,7 +34,7 @@ config I2C_MUX_GPIO config I2C_MUX_GPMUX tristate "General Purpose I2C multiplexer" select MULTIPLEXER - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for a general purpose I2C multiplexer. This driver provides access to @@ -77,7 +77,7 @@ config I2C_MUX_PCA954x config I2C_MUX_PINCTRL tristate "pinctrl-based I2C multiplexer" depends on PINCTRL - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for an I2C multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing. diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 704f1e50f6f4..70835825083f 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -294,13 +294,11 @@ static int ltc4306_probe(struct i2c_client *client) return 0; } -static int ltc4306_remove(struct i2c_client *client) +static void ltc4306_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); i2c_mux_del_adapters(muxc); - - return 0; } static struct i2c_driver ltc4306_driver = { diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 6daec8d3d331..ea83de78f52d 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -325,12 +325,11 @@ static int pca9541_probe(struct i2c_client *client, return 0; } -static int pca9541_remove(struct i2c_client *client) +static void pca9541_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); i2c_mux_del_adapters(muxc); - return 0; } static struct i2c_driver pca9541_driver = { diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 4ad665757dd8..a5f458b635df 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -521,14 +521,13 @@ fail_cleanup: return ret; } -static int pca954x_remove(struct i2c_client *client) +static void pca954x_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); device_remove_file(&client->dev, &dev_attr_idle_state); pca954x_cleanup(muxc); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index f1bb00a11ad6..d5ad904756fd 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -185,7 +185,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match); static struct platform_driver i2c_mux_pinctrl_driver = { .driver = { .name = "i2c-mux-pinctrl", - .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match), + .of_match_table = i2c_mux_pinctrl_of_match, }, .probe = i2c_mux_pinctrl_probe, .remove = i2c_mux_pinctrl_remove, |