Merge branch 'i2c/for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - if a host can be a client, too, the I2C core can now use it to emulate SMBus HostNotify support (STM32 and R-Car added this so far) - also for client mode, a testunit has been added. It can create rare situations on the bus, so host controllers can be tested - a binding has been added to mark the bus as "single-master". This allows for better timeout detections - new driver for Mellanox Bluefield - massive refactoring of the Tegra driver - EEPROMs recognized by the at24 driver can now have custom names - rest is driver updates * 'i2c/for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (80 commits) Documentation: i2c: add testunit docs to index i2c: tegra: Improve driver module description i2c: tegra: Clean up whitespaces, newlines and indentation i2c: tegra: Clean up and improve comments i2c: tegra: Clean up printk messages i2c: tegra: Clean up variable names i2c: tegra: Improve formatting of variables i2c: tegra: Check errors for both positive and negative values i2c: tegra: Factor out hardware initialization into separate function i2c: tegra: Factor out register polling into separate function i2c: tegra: Factor out packet header setup from tegra_i2c_xfer_msg() i2c: tegra: Factor out error recovery from tegra_i2c_xfer_msg() i2c: tegra: Rename wait/poll functions i2c: tegra: Remove "dma" variable from tegra_i2c_xfer_msg() i2c: tegra: Remove redundant check in tegra_i2c_issue_bus_clear() i2c: tegra: Remove likely/unlikely from the code i2c: tegra: Remove outdated barrier() i2c: tegra: Clean up variable types i2c: tegra: Reorder location of functions in the code i2c: tegra: Clean up probe function ...
This commit is contained in:
@@ -101,7 +101,6 @@ source "drivers/i2c/busses/Kconfig"
|
||||
config I2C_STUB
|
||||
tristate "I2C/SMBus Test Stub"
|
||||
depends on m
|
||||
default 'n'
|
||||
help
|
||||
This module may be useful to developers of SMBus client drivers,
|
||||
especially for certain kinds of sensor chips.
|
||||
@@ -126,6 +125,14 @@ config I2C_SLAVE_EEPROM
|
||||
This backend makes Linux behave like an I2C EEPROM. Please read
|
||||
Documentation/i2c/slave-eeprom-backend.rst for further details.
|
||||
|
||||
config I2C_SLAVE_TESTUNIT
|
||||
tristate "I2C eeprom testunit driver"
|
||||
help
|
||||
This backend can be used to trigger test cases for I2C bus masters
|
||||
which require a remote device with certain capabilities, e.g.
|
||||
multi-master, SMBus Host Notify, etc. Please read
|
||||
Documentation/i2c/slave-testunit-backend.rst for further details.
|
||||
|
||||
endif
|
||||
|
||||
config I2C_DEBUG_CORE
|
||||
|
@@ -16,5 +16,6 @@ obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
||||
obj-y += algos/ busses/ muxes/
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
|
||||
obj-$(CONFIG_I2C_SLAVE_TESTUNIT) += i2c-slave-testunit.o
|
||||
|
||||
ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
|
||||
|
@@ -147,6 +147,7 @@ config I2C_I801
|
||||
Tiger Lake (PCH)
|
||||
Jasper Lake (SOC)
|
||||
Emmitsburg (PCH)
|
||||
Alder Lake (PCH)
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
@@ -730,6 +731,19 @@ config I2C_LPC2K
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-lpc2k.
|
||||
|
||||
config I2C_MLXBF
|
||||
tristate "Mellanox BlueField I2C controller"
|
||||
depends on ARM64
|
||||
help
|
||||
Enabling this option will add I2C SMBus support for Mellanox BlueField
|
||||
system.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called i2c-mlxbf.
|
||||
|
||||
This driver implements an I2C SMBus host controller and enables both
|
||||
master and slave functions.
|
||||
|
||||
config I2C_MESON
|
||||
tristate "Amlogic Meson I2C controller"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
@@ -840,7 +854,6 @@ config I2C_PASEMI
|
||||
config I2C_PCA_PLATFORM
|
||||
tristate "PCA9564/PCA9665 as platform device"
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports a memory mapped Philips PCA9564/PCA9665
|
||||
parallel bus to I2C bus controller.
|
||||
@@ -1026,6 +1039,7 @@ config I2C_STM32F7
|
||||
tristate "STMicroelectronics STM32F7 I2C support"
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
select I2C_SLAVE
|
||||
select I2C_SMBUS
|
||||
help
|
||||
Enable this option to add support for STM32 I2C controller embedded
|
||||
in STM32F7 SoCs.
|
||||
@@ -1181,6 +1195,8 @@ config I2C_RCAR
|
||||
tristate "Renesas R-Car I2C Controller"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select I2C_SLAVE
|
||||
select I2C_SMBUS
|
||||
select RESET_CONTROLLER if ARCH_RCAR_GEN3
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
R-Car I2C controller.
|
||||
@@ -1240,7 +1256,6 @@ config I2C_TAOS_EVM
|
||||
depends on TTY
|
||||
select SERIO
|
||||
select SERIO_SERPORT
|
||||
default n
|
||||
help
|
||||
This supports TAOS evaluation modules on serial port. In order to
|
||||
use this driver, you will need the inputattach tool, which is part
|
||||
@@ -1324,7 +1339,6 @@ config I2C_PCA_ISA
|
||||
tristate "PCA9564/PCA9665 on an ISA bus"
|
||||
depends on ISA
|
||||
select I2C_ALGOPCA
|
||||
default n
|
||||
help
|
||||
This driver supports ISA boards using the Philips PCA9564/PCA9665
|
||||
parallel bus to I2C bus controller.
|
||||
|
@@ -140,6 +140,7 @@ obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o
|
||||
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_ICY) += i2c-icy.o
|
||||
obj-$(CONFIG_I2C_MLXBF) += i2c-mlxbf.o
|
||||
obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
|
||||
obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
|
@@ -155,7 +155,7 @@ static int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
struct amd_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
struct i2c_msg *pmsg;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
/* the adapter might have been deleted while waiting for the bus lock */
|
||||
if (unlikely(!i2c_dev->common.mp2_dev))
|
||||
|
@@ -421,11 +421,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(i2c_dev->regs);
|
||||
|
||||
mclk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(mclk)) {
|
||||
if (PTR_ERR(mclk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Could not get clock\n");
|
||||
return PTR_ERR(mclk);
|
||||
}
|
||||
if (IS_ERR(mclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mclk),
|
||||
"Could not get clock\n");
|
||||
|
||||
i2c_dev->bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
|
||||
|
||||
|
@@ -332,21 +332,15 @@ static int efm32_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to determine base address\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ddata->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(ddata->base))
|
||||
return PTR_ERR(ddata->base);
|
||||
|
||||
if (resource_size(res) < 0x42) {
|
||||
dev_err(&pdev->dev, "memory resource too small\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ddata->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(ddata->base))
|
||||
return PTR_ERR(ddata->base);
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
if (!ret)
|
||||
|
@@ -71,6 +71,7 @@
|
||||
* Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes
|
||||
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
||||
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
|
||||
* Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
@@ -228,6 +229,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
|
||||
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
|
||||
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
|
||||
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
|
||||
@@ -1081,6 +1083,7 @@ static const struct pci_device_id i801_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
@@ -1274,6 +1277,7 @@ static const struct {
|
||||
/*
|
||||
* Additional individual entries were added after verification.
|
||||
*/
|
||||
{ "Latitude 5480", 0x29 },
|
||||
{ "Vostro V131", 0x1d },
|
||||
};
|
||||
|
||||
@@ -1767,6 +1771,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_EBG_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
|
@@ -1159,11 +1159,9 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
|
||||
/* Get I2C clock */
|
||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_imx->clk)) {
|
||||
if (PTR_ERR(i2c_imx->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "can't get I2C clock\n");
|
||||
return PTR_ERR(i2c_imx->clk);
|
||||
}
|
||||
if (IS_ERR(i2c_imx->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c_imx->clk),
|
||||
"can't get I2C clock\n");
|
||||
|
||||
ret = clk_prepare_enable(i2c_imx->clk);
|
||||
if (ret) {
|
||||
@@ -1171,14 +1169,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Request IRQ */
|
||||
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED,
|
||||
pdev->name, i2c_imx);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
/* Init queue */
|
||||
init_waitqueue_head(&i2c_imx->queue);
|
||||
|
||||
@@ -1197,6 +1187,14 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
goto rpm_disable;
|
||||
|
||||
/* Request IRQ */
|
||||
ret = request_threaded_irq(irq, i2c_imx_isr, NULL, IRQF_SHARED,
|
||||
pdev->name, i2c_imx);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
|
||||
goto rpm_disable;
|
||||
}
|
||||
|
||||
/* Set up clock divider */
|
||||
i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
@@ -1239,13 +1237,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
|
||||
clk_notifier_unregister:
|
||||
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
|
||||
free_irq(irq, i2c_imx);
|
||||
rpm_disable:
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
clk_disable:
|
||||
clk_disable_unprepare(i2c_imx->clk);
|
||||
return ret;
|
||||
}
|
||||
@@ -1253,7 +1250,7 @@ clk_disable:
|
||||
static int i2c_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
int irq, ret;
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret < 0)
|
||||
@@ -1273,6 +1270,9 @@ static int i2c_imx_remove(struct platform_device *pdev)
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
|
||||
|
||||
clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq >= 0)
|
||||
free_irq(irq, i2c_imx);
|
||||
clk_disable_unprepare(i2c_imx->clk);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
@@ -77,6 +77,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a
|
||||
#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac
|
||||
#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac
|
||||
#define PCI_DEVICE_ID_INTEL_EBG_SMT 0x1bff
|
||||
#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15
|
||||
|
||||
#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */
|
||||
@@ -176,14 +177,12 @@ struct ismt_priv {
|
||||
u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */
|
||||
};
|
||||
|
||||
/**
|
||||
* ismt_ids - PCI device IDs supported by this driver
|
||||
*/
|
||||
static const struct pci_device_id ismt_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
|
||||
{ 0, }
|
||||
};
|
||||
@@ -197,6 +196,8 @@ MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (0 = BIOS default)");
|
||||
|
||||
/**
|
||||
* __ismt_desc_dump() - dump the contents of a specific descriptor
|
||||
* @dev: the iSMT device
|
||||
* @desc: the iSMT hardware descriptor
|
||||
*/
|
||||
static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc)
|
||||
{
|
||||
@@ -628,11 +629,6 @@ static u32 ismt_func(struct i2c_adapter *adap)
|
||||
I2C_FUNC_SMBUS_PEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* smbus_algorithm - the adapter algorithm and supported functionality
|
||||
* @smbus_xfer: the adapter algorithm
|
||||
* @functionality: functionality supported by the adapter
|
||||
*/
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = ismt_access,
|
||||
.functionality = ismt_func,
|
||||
|
@@ -752,6 +752,7 @@ static const struct ingenic_i2c_config x1000_i2c_config = {
|
||||
};
|
||||
|
||||
static const struct of_device_id jz4780_i2c_of_matches[] = {
|
||||
{ .compatible = "ingenic,jz4770-i2c", .data = &jz4780_i2c_config },
|
||||
{ .compatible = "ingenic,jz4780-i2c", .data = &jz4780_i2c_config },
|
||||
{ .compatible = "ingenic,x1000-i2c", .data = &x1000_i2c_config },
|
||||
{ /* sentinel */ }
|
||||
@@ -856,7 +857,7 @@ static struct platform_driver jz4780_i2c_driver = {
|
||||
.remove = jz4780_i2c_remove,
|
||||
.driver = {
|
||||
.name = "jz4780-i2c",
|
||||
.of_match_table = of_match_ptr(jz4780_i2c_of_matches),
|
||||
.of_match_table = jz4780_i2c_of_matches,
|
||||
},
|
||||
};
|
||||
|
||||
|
2506
drivers/i2c/busses/i2c-mlxbf.c
Normal file
2506
drivers/i2c/busses/i2c-mlxbf.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -496,11 +496,10 @@ static irqreturn_t
|
||||
mv64xxx_i2c_intr(int irq, void *dev_id)
|
||||
{
|
||||
struct mv64xxx_i2c_data *drv_data = dev_id;
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
irqreturn_t rc = IRQ_NONE;
|
||||
|
||||
spin_lock_irqsave(&drv_data->lock, flags);
|
||||
spin_lock(&drv_data->lock);
|
||||
|
||||
if (drv_data->offload_enabled)
|
||||
rc = mv64xxx_i2c_intr_offload(drv_data);
|
||||
@@ -517,7 +516,7 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
|
||||
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&drv_data->lock, flags);
|
||||
spin_unlock(&drv_data->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@@ -125,8 +125,7 @@ static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len)
|
||||
put_unaligned_be16(val, data);
|
||||
break;
|
||||
case 3:
|
||||
put_unaligned_be16(val >> 8, data);
|
||||
data[2] = val;
|
||||
put_unaligned_be24(val, data);
|
||||
break;
|
||||
case 4:
|
||||
put_unaligned_be32(val, data);
|
||||
|
@@ -165,10 +165,9 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = _dev;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
unsigned long flags;
|
||||
unsigned int stat, fifostat;
|
||||
|
||||
spin_lock_irqsave(&i2c_dev->lock, flags);
|
||||
spin_lock(&i2c_dev->lock);
|
||||
|
||||
i2c_dev->err = 0;
|
||||
|
||||
@@ -214,7 +213,7 @@ stop:
|
||||
OWL_I2C_STAT_IRQP, true);
|
||||
|
||||
complete_all(&i2c_dev->msg_complete);
|
||||
spin_unlock_irqrestore(&i2c_dev->lock, flags);
|
||||
spin_unlock(&i2c_dev->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -210,9 +210,8 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
|
||||
u32 dma;
|
||||
u32 val;
|
||||
struct i2c_msg *cur;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gi2c->lock, flags);
|
||||
spin_lock(&gi2c->lock);
|
||||
m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS);
|
||||
rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS);
|
||||
dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT);
|
||||
@@ -294,7 +293,7 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
|
||||
dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
|
||||
complete(&gi2c->done);
|
||||
|
||||
spin_unlock_irqrestore(&gi2c->lock, flags);
|
||||
spin_unlock(&gi2c->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -19,7 +19,9 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -105,10 +107,11 @@
|
||||
#define ID_ARBLOST (1 << 3)
|
||||
#define ID_NACK (1 << 4)
|
||||
/* persistent flags */
|
||||
#define ID_P_HOST_NOTIFY BIT(28)
|
||||
#define ID_P_REP_AFTER_RD BIT(29)
|
||||
#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
|
||||
#define ID_P_PM_BLOCKED BIT(31)
|
||||
#define ID_P_MASK GENMASK(31, 29)
|
||||
#define ID_P_MASK GENMASK(31, 28)
|
||||
|
||||
enum rcar_i2c_type {
|
||||
I2C_RCAR_GEN1,
|
||||
@@ -140,14 +143,13 @@ struct rcar_i2c_priv {
|
||||
|
||||
struct reset_control *rstc;
|
||||
int irq;
|
||||
|
||||
struct i2c_client *host_notify_client;
|
||||
};
|
||||
|
||||
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
|
||||
#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD)
|
||||
|
||||
#define LOOP_TIMEOUT 1024
|
||||
|
||||
|
||||
static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
|
||||
{
|
||||
writel(val, priv->io + reg);
|
||||
@@ -221,18 +223,18 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
|
||||
|
||||
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
for (i = 0; i < LOOP_TIMEOUT; i++) {
|
||||
/* make sure that bus is not busy */
|
||||
if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
|
||||
return 0;
|
||||
udelay(1);
|
||||
ret = readl_poll_timeout(priv->io + ICMCR, val, !(val & FSDA), 10,
|
||||
priv->adap.timeout);
|
||||
if (ret) {
|
||||
/* Waiting did not help, try to recover */
|
||||
priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
|
||||
ret = i2c_recover_bus(&priv->adap);
|
||||
}
|
||||
|
||||
/* Waiting did not help, try to recover */
|
||||
priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL;
|
||||
return i2c_recover_bus(&priv->adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv)
|
||||
@@ -760,20 +762,14 @@ static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
|
||||
/* I2C is a special case, we need to poll the status of a reset */
|
||||
static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
int i, ret;
|
||||
int ret;
|
||||
|
||||
ret = reset_control_reset(priv->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < LOOP_TIMEOUT; i++) {
|
||||
ret = reset_control_status(priv->rstc);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, 1,
|
||||
100, false, priv->rstc);
|
||||
}
|
||||
|
||||
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
@@ -884,14 +880,21 @@ static int rcar_unreg_slave(struct i2c_client *slave)
|
||||
|
||||
static u32 rcar_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
|
||||
|
||||
/*
|
||||
* This HW can't do:
|
||||
* I2C_SMBUS_QUICK (setting FSB during START didn't work)
|
||||
* I2C_M_NOSTART (automatically sends address after START)
|
||||
* I2C_M_IGNORE_NAK (automatically sends STOP after NAK)
|
||||
*/
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SLAVE |
|
||||
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE |
|
||||
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
|
||||
if (priv->flags & ID_P_HOST_NOTIFY)
|
||||
func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm rcar_i2c_algo = {
|
||||
@@ -991,6 +994,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
else
|
||||
pm_runtime_put(dev);
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "smbus"))
|
||||
priv->flags |= ID_P_HOST_NOTIFY;
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv);
|
||||
@@ -1005,10 +1010,20 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
goto out_pm_disable;
|
||||
|
||||
if (priv->flags & ID_P_HOST_NOTIFY) {
|
||||
priv->host_notify_client = i2c_new_slave_host_notify_device(adap);
|
||||
if (IS_ERR(priv->host_notify_client)) {
|
||||
ret = PTR_ERR(priv->host_notify_client);
|
||||
goto out_del_device;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "probed\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_del_device:
|
||||
i2c_del_adapter(&priv->adap);
|
||||
out_pm_put:
|
||||
pm_runtime_put(dev);
|
||||
out_pm_disable:
|
||||
@@ -1021,6 +1036,8 @@ static int rcar_i2c_remove(struct platform_device *pdev)
|
||||
struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
if (priv->host_notify_client)
|
||||
i2c_free_slave_host_notify_device(priv->host_notify_client);
|
||||
i2c_del_adapter(&priv->adap);
|
||||
rcar_i2c_release_dma(priv);
|
||||
if (priv->flags & ID_P_PM_BLOCKED)
|
||||
|
@@ -1312,18 +1312,13 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
|
||||
i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
}
|
||||
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
ret = PTR_ERR(i2c->clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(i2c->pclk)) {
|
||||
ret = PTR_ERR(i2c->pclk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(i2c->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk),
|
||||
"Can't get bus clk\n");
|
||||
|
||||
if (IS_ERR(i2c->pclk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk),
|
||||
"Can't get periph clk\n");
|
||||
|
||||
ret = clk_prepare(i2c->clk);
|
||||
if (ret < 0) {
|
||||
|
@@ -26,8 +26,9 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
||||
dma->chan_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA tx channel\n");
|
||||
if (ret != -ENODEV)
|
||||
ret = dev_err_probe(dev, ret,
|
||||
"can't request DMA tx channel\n");
|
||||
goto fail_al;
|
||||
}
|
||||
|
||||
@@ -46,8 +47,9 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
||||
dma->chan_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "can't request DMA rx channel\n");
|
||||
if (ret != -ENODEV)
|
||||
ret = dev_err_probe(dev, ret,
|
||||
"can't request DMA rx channel\n");
|
||||
|
||||
goto fail_tx;
|
||||
}
|
||||
@@ -76,8 +78,6 @@ fail_tx:
|
||||
dma_release_channel(dma->chan_tx);
|
||||
fail_al:
|
||||
devm_kfree(dev, dma);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_info(dev, "can't use DMA\n");
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
@@ -797,10 +797,8 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
ret = PTR_ERR(rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Error: Missing reset ctrl\n");
|
||||
|
||||
ret = dev_err_probe(&pdev->dev, PTR_ERR(rst),
|
||||
"Error: Missing reset ctrl\n");
|
||||
goto clk_free;
|
||||
}
|
||||
reset_control_assert(rst);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
@@ -50,6 +51,7 @@
|
||||
|
||||
/* STM32F7 I2C control 1 */
|
||||
#define STM32F7_I2C_CR1_PECEN BIT(23)
|
||||
#define STM32F7_I2C_CR1_SMBHEN BIT(20)
|
||||
#define STM32F7_I2C_CR1_WUPEN BIT(18)
|
||||
#define STM32F7_I2C_CR1_SBC BIT(16)
|
||||
#define STM32F7_I2C_CR1_RXDMAEN BIT(15)
|
||||
@@ -150,7 +152,12 @@
|
||||
|
||||
#define STM32F7_I2C_MAX_LEN 0xff
|
||||
#define STM32F7_I2C_DMA_LEN_MIN 0x16
|
||||
#define STM32F7_I2C_MAX_SLAVE 0x2
|
||||
enum {
|
||||
STM32F7_SLAVE_HOSTNOTIFY,
|
||||
STM32F7_SLAVE_7_10_BITS_ADDR,
|
||||
STM32F7_SLAVE_7_BITS_ADDR,
|
||||
STM32F7_I2C_MAX_SLAVE
|
||||
};
|
||||
|
||||
#define STM32F7_I2C_DNF_DEFAULT 0
|
||||
#define STM32F7_I2C_DNF_MAX 16
|
||||
@@ -301,6 +308,8 @@ struct stm32f7_i2c_msg {
|
||||
* @fmp_creg: register address for clearing Fast Mode Plus bits
|
||||
* @fmp_mask: mask for Fast Mode Plus bits in set register
|
||||
* @wakeup_src: boolean to know if the device is a wakeup source
|
||||
* @smbus_mode: states that the controller is configured in SMBus mode
|
||||
* @host_notify_client: SMBus host-notify client
|
||||
*/
|
||||
struct stm32f7_i2c_dev {
|
||||
struct i2c_adapter adap;
|
||||
@@ -327,6 +336,8 @@ struct stm32f7_i2c_dev {
|
||||
u32 fmp_creg;
|
||||
u32 fmp_mask;
|
||||
bool wakeup_src;
|
||||
bool smbus_mode;
|
||||
struct i2c_client *host_notify_client;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1321,11 +1332,20 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
|
||||
int i;
|
||||
|
||||
/*
|
||||
* slave[0] supports 7-bit and 10-bit slave address
|
||||
* slave[1] supports 7-bit slave address only
|
||||
* slave[STM32F7_SLAVE_HOSTNOTIFY] support only SMBus Host address (0x8)
|
||||
* slave[STM32F7_SLAVE_7_10_BITS_ADDR] supports 7-bit and 10-bit slave address
|
||||
* slave[STM32F7_SLAVE_7_BITS_ADDR] supports 7-bit slave address only
|
||||
*/
|
||||
for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) {
|
||||
if (i == 1 && (slave->flags & I2C_CLIENT_TEN))
|
||||
if (i2c_dev->smbus_mode && (slave->addr == 0x08)) {
|
||||
if (i2c_dev->slave[STM32F7_SLAVE_HOSTNOTIFY])
|
||||
goto fail;
|
||||
*id = STM32F7_SLAVE_HOSTNOTIFY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = STM32F7_I2C_MAX_SLAVE - 1; i > STM32F7_SLAVE_HOSTNOTIFY; i--) {
|
||||
if ((i == STM32F7_SLAVE_7_BITS_ADDR) &&
|
||||
(slave->flags & I2C_CLIENT_TEN))
|
||||
continue;
|
||||
if (!i2c_dev->slave[i]) {
|
||||
*id = i;
|
||||
@@ -1333,6 +1353,7 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr);
|
||||
|
||||
return -EINVAL;
|
||||
@@ -1776,7 +1797,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||
if (!stm32f7_i2c_is_slave_registered(i2c_dev))
|
||||
stm32f7_i2c_enable_wakeup(i2c_dev, true);
|
||||
|
||||
if (id == 0) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
/* Slave SMBus Host */
|
||||
i2c_dev->slave[id] = slave;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Configure Own Address 1 */
|
||||
oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
oar1 &= ~STM32F7_I2C_OAR1_MASK;
|
||||
@@ -1789,7 +1816,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||
oar1 |= STM32F7_I2C_OAR1_OA1EN;
|
||||
i2c_dev->slave[id] = slave;
|
||||
writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
} else if (id == 1) {
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Configure Own Address 2 */
|
||||
oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
oar2 &= ~STM32F7_I2C_OAR2_MASK;
|
||||
@@ -1802,7 +1831,10 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||
oar2 |= STM32F7_I2C_OAR2_OA2EN;
|
||||
i2c_dev->slave[id] = slave;
|
||||
writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev, "I2C slave id not supported\n");
|
||||
ret = -ENODEV;
|
||||
goto pm_free;
|
||||
}
|
||||
@@ -1843,10 +1875,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (id == 0) {
|
||||
if (id == 1) {
|
||||
mask = STM32F7_I2C_OAR1_OA1EN;
|
||||
stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
|
||||
} else {
|
||||
} else if (id == 2) {
|
||||
mask = STM32F7_I2C_OAR2_OA2EN;
|
||||
stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask);
|
||||
}
|
||||
@@ -1911,14 +1943,51 @@ static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
|
||||
&i2c_dev->fmp_mask);
|
||||
}
|
||||
|
||||
static int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &i2c_dev->adap;
|
||||
void __iomem *base = i2c_dev->base;
|
||||
struct i2c_client *client;
|
||||
|
||||
client = i2c_new_slave_host_notify_device(adap);
|
||||
if (IS_ERR(client))
|
||||
return PTR_ERR(client);
|
||||
|
||||
i2c_dev->host_notify_client = client;
|
||||
|
||||
/* Enable SMBus Host address */
|
||||
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
void __iomem *base = i2c_dev->base;
|
||||
|
||||
if (i2c_dev->host_notify_client) {
|
||||
/* Disable SMBus Host address */
|
||||
stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_SMBHEN);
|
||||
i2c_free_slave_host_notify_device(i2c_dev->host_notify_client);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
|
||||
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
|
||||
u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
|
||||
I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
|
||||
if (i2c_dev->smbus_mode)
|
||||
func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm stm32f7_i2c_algo = {
|
||||
@@ -1968,11 +2037,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||
"wakeup-source");
|
||||
|
||||
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Failed to get controller clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
if (IS_ERR(i2c_dev->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
|
||||
"Failed to get controller clock\n");
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
@@ -1982,10 +2049,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
rst = devm_reset_control_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
ret = PTR_ERR(rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Error: Missing reset ctrl\n");
|
||||
|
||||
ret = dev_err_probe(&pdev->dev, PTR_ERR(rst),
|
||||
"Error: Missing reset ctrl\n");
|
||||
goto clk_free;
|
||||
}
|
||||
reset_control_assert(rst);
|
||||
@@ -2052,14 +2117,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||
i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
|
||||
STM32F7_I2C_TXDR,
|
||||
STM32F7_I2C_RXDR);
|
||||
if (PTR_ERR(i2c_dev->dma) == -ENODEV)
|
||||
i2c_dev->dma = NULL;
|
||||
else if (IS_ERR(i2c_dev->dma)) {
|
||||
if (IS_ERR(i2c_dev->dma)) {
|
||||
ret = PTR_ERR(i2c_dev->dma);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to request dma error %i\n", ret);
|
||||
goto fmp_clear;
|
||||
/* DMA support is optional, only report other errors */
|
||||
if (ret != -ENODEV)
|
||||
goto fmp_clear;
|
||||
dev_dbg(i2c_dev->dev, "No DMA option: fallback using interrupts\n");
|
||||
i2c_dev->dma = NULL;
|
||||
}
|
||||
|
||||
if (i2c_dev->wakeup_src) {
|
||||
@@ -2084,10 +2148,22 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
stm32f7_i2c_hw_config(i2c_dev);
|
||||
|
||||
i2c_dev->smbus_mode = of_property_read_bool(pdev->dev.of_node, "smbus");
|
||||
|
||||
ret = i2c_add_adapter(adap);
|
||||
if (ret)
|
||||
goto pm_disable;
|
||||
|
||||
if (i2c_dev->smbus_mode) {
|
||||
ret = stm32f7_i2c_enable_smbus_host(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to enable SMBus Host-Notify protocol (%d)\n",
|
||||
ret);
|
||||
goto i2c_adapter_remove;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
|
||||
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
@@ -2095,6 +2171,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
i2c_adapter_remove:
|
||||
i2c_del_adapter(adap);
|
||||
|
||||
pm_disable:
|
||||
pm_runtime_put_noidle(i2c_dev->dev);
|
||||
pm_runtime_disable(i2c_dev->dev);
|
||||
@@ -2126,6 +2205,8 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
stm32f7_i2c_disable_smbus_host(i2c_dev);
|
||||
|
||||
i2c_del_adapter(&i2c_dev->adap);
|
||||
pm_runtime_get_sync(i2c_dev->dev);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -46,34 +46,36 @@ enum xiic_endian {
|
||||
|
||||
/**
|
||||
* struct xiic_i2c - Internal representation of the XIIC I2C bus
|
||||
* @dev: Pointer to device structure
|
||||
* @base: Memory base of the HW registers
|
||||
* @wait: Wait queue for callers
|
||||
* @adap: Kernel adapter representation
|
||||
* @tx_msg: Messages from above to be sent
|
||||
* @lock: Mutual exclusion
|
||||
* @tx_pos: Current pos in TX message
|
||||
* @nmsgs: Number of messages in tx_msg
|
||||
* @state: See STATE_
|
||||
* @rx_msg: Current RX message
|
||||
* @rx_pos: Position within current RX message
|
||||
* @dev: Pointer to device structure
|
||||
* @base: Memory base of the HW registers
|
||||
* @wait: Wait queue for callers
|
||||
* @adap: Kernel adapter representation
|
||||
* @tx_msg: Messages from above to be sent
|
||||
* @lock: Mutual exclusion
|
||||
* @tx_pos: Current pos in TX message
|
||||
* @nmsgs: Number of messages in tx_msg
|
||||
* @rx_msg: Current RX message
|
||||
* @rx_pos: Position within current RX message
|
||||
* @endianness: big/little-endian byte order
|
||||
* @clk: Pointer to AXI4-lite input clock
|
||||
* @clk: Pointer to AXI4-lite input clock
|
||||
* @state: See STATE_
|
||||
* @singlemaster: Indicates bus is single master
|
||||
*/
|
||||
struct xiic_i2c {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *tx_msg;
|
||||
struct mutex lock;
|
||||
unsigned int tx_pos;
|
||||
unsigned int nmsgs;
|
||||
enum xilinx_i2c_state state;
|
||||
struct i2c_msg *rx_msg;
|
||||
int rx_pos;
|
||||
enum xiic_endian endianness;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *tx_msg;
|
||||
struct mutex lock;
|
||||
unsigned int tx_pos;
|
||||
unsigned int nmsgs;
|
||||
struct i2c_msg *rx_msg;
|
||||
int rx_pos;
|
||||
enum xiic_endian endianness;
|
||||
struct clk *clk;
|
||||
enum xilinx_i2c_state state;
|
||||
bool singlemaster;
|
||||
};
|
||||
|
||||
|
||||
@@ -526,6 +528,15 @@ static int xiic_busy(struct xiic_i2c *i2c)
|
||||
if (i2c->tx_msg)
|
||||
return -EBUSY;
|
||||
|
||||
/* In single master mode bus can only be busy, when in use by this
|
||||
* driver. If the register indicates bus being busy for some reason we
|
||||
* should ignore it, since bus will never be released and i2c will be
|
||||
* stuck forever.
|
||||
*/
|
||||
if (i2c->singlemaster) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for instance if previous transfer was terminated due to TX error
|
||||
* it might be that the bus is on it's way to become available
|
||||
* give it at most 3 ms to wake
|
||||
@@ -811,6 +822,9 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
goto err_clk_dis;
|
||||
}
|
||||
|
||||
i2c->singlemaster =
|
||||
of_property_read_bool(pdev->dev.of_node, "single-master");
|
||||
|
||||
/*
|
||||
* Detect endianness
|
||||
* Try to reset the TX FIFO. Then check the EMPTY flag. If it is not
|
||||
|
175
drivers/i2c/i2c-slave-testunit.c
Normal file
175
drivers/i2c/i2c-slave-testunit.c
Normal file
@@ -0,0 +1,175 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* I2C slave mode testunit
|
||||
*
|
||||
* Copyright (C) 2020 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
|
||||
* Copyright (C) 2020 by Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
|
||||
|
||||
#define TU_CUR_VERSION 0x01
|
||||
|
||||
enum testunit_cmds {
|
||||
TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */
|
||||
TU_CMD_HOST_NOTIFY,
|
||||
TU_NUM_CMDS
|
||||
};
|
||||
|
||||
enum testunit_regs {
|
||||
TU_REG_CMD,
|
||||
TU_REG_DATAL,
|
||||
TU_REG_DATAH,
|
||||
TU_REG_DELAY,
|
||||
TU_NUM_REGS
|
||||
};
|
||||
|
||||
enum testunit_flags {
|
||||
TU_FLAG_IN_PROCESS,
|
||||
};
|
||||
|
||||
struct testunit_data {
|
||||
unsigned long flags;
|
||||
u8 regs[TU_NUM_REGS];
|
||||
u8 reg_idx;
|
||||
struct i2c_client *client;
|
||||
struct delayed_work worker;
|
||||
};
|
||||
|
||||
static void i2c_slave_testunit_work(struct work_struct *work)
|
||||
{
|
||||
struct testunit_data *tu = container_of(work, struct testunit_data, worker.work);
|
||||
struct i2c_msg msg;
|
||||
u8 msgbuf[256];
|
||||
int ret = 0;
|
||||
|
||||
msg.addr = I2C_CLIENT_END;
|
||||
msg.buf = msgbuf;
|
||||
|
||||
switch (tu->regs[TU_REG_CMD]) {
|
||||
case TU_CMD_READ_BYTES:
|
||||
msg.addr = tu->regs[TU_REG_DATAL];
|
||||
msg.flags = I2C_M_RD;
|
||||
msg.len = tu->regs[TU_REG_DATAH];
|
||||
break;
|
||||
|
||||
case TU_CMD_HOST_NOTIFY:
|
||||
msg.addr = 0x08;
|
||||
msg.flags = 0;
|
||||
msg.len = 3;
|
||||
msgbuf[0] = tu->client->addr;
|
||||
msgbuf[1] = tu->regs[TU_REG_DATAL];
|
||||
msgbuf[2] = tu->regs[TU_REG_DATAH];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.addr != I2C_CLIENT_END) {
|
||||
ret = i2c_transfer(tu->client->adapter, &msg, 1);
|
||||
/* convert '0 msgs transferred' to errno */
|
||||
ret = (ret == 0) ? -EIO : ret;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret);
|
||||
|
||||
clear_bit(TU_FLAG_IN_PROCESS, &tu->flags);
|
||||
}
|
||||
|
||||
static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
{
|
||||
struct testunit_data *tu = i2c_get_clientdata(client);
|
||||
int ret = 0;
|
||||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_WRITE_RECEIVED:
|
||||
if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
|
||||
return -EBUSY;
|
||||
|
||||
if (tu->reg_idx < TU_NUM_REGS)
|
||||
tu->regs[tu->reg_idx] = *val;
|
||||
else
|
||||
ret = -EMSGSIZE;
|
||||
|
||||
if (tu->reg_idx <= TU_NUM_REGS)
|
||||
tu->reg_idx++;
|
||||
|
||||
/* TU_REG_CMD always written at this point */
|
||||
if (tu->regs[TU_REG_CMD] >= TU_NUM_CMDS)
|
||||
ret = -EINVAL;
|
||||
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_STOP:
|
||||
if (tu->reg_idx == TU_NUM_REGS) {
|
||||
set_bit(TU_FLAG_IN_PROCESS, &tu->flags);
|
||||
queue_delayed_work(system_long_wq, &tu->worker,
|
||||
msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY]));
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case I2C_SLAVE_WRITE_REQUESTED:
|
||||
tu->reg_idx = 0;
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_READ_REQUESTED:
|
||||
case I2C_SLAVE_READ_PROCESSED:
|
||||
*val = TU_CUR_VERSION;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_slave_testunit_probe(struct i2c_client *client)
|
||||
{
|
||||
struct testunit_data *tu;
|
||||
|
||||
tu = devm_kzalloc(&client->dev, sizeof(struct testunit_data), GFP_KERNEL);
|
||||
if (!tu)
|
||||
return -ENOMEM;
|
||||
|
||||
tu->client = client;
|
||||
i2c_set_clientdata(client, tu);
|
||||
INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work);
|
||||
|
||||
return i2c_slave_register(client, i2c_slave_testunit_slave_cb);
|
||||
};
|
||||
|
||||
static int 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[] = {
|
||||
{ "slave-testunit", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
|
||||
|
||||
static struct i2c_driver i2c_slave_testunit_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-slave-testunit",
|
||||
},
|
||||
.probe_new = i2c_slave_testunit_probe,
|
||||
.remove = i2c_slave_testunit_remove,
|
||||
.id_table = i2c_slave_testunit_id,
|
||||
};
|
||||
module_i2c_driver(i2c_slave_testunit_driver);
|
||||
|
||||
MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
|
||||
MODULE_DESCRIPTION("I2C slave mode test unit");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -197,6 +197,113 @@ EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
|
||||
|
||||
module_i2c_driver(smbalert_driver);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
#define SMBUS_HOST_NOTIFY_LEN 3
|
||||
struct i2c_slave_host_notify_status {
|
||||
u8 index;
|
||||
u8 addr;
|
||||
};
|
||||
|
||||
static int i2c_slave_host_notify_cb(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
{
|
||||
struct i2c_slave_host_notify_status *status = client->dev.platform_data;
|
||||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_WRITE_RECEIVED:
|
||||
/* We only retrieve the first byte received (addr)
|
||||
* since there is currently no support to retrieve the data
|
||||
* parameter from the client.
|
||||
*/
|
||||
if (status->index == 0)
|
||||
status->addr = *val;
|
||||
if (status->index < U8_MAX)
|
||||
status->index++;
|
||||
break;
|
||||
case I2C_SLAVE_STOP:
|
||||
if (status->index == SMBUS_HOST_NOTIFY_LEN)
|
||||
i2c_handle_smbus_host_notify(client->adapter,
|
||||
status->addr);
|
||||
fallthrough;
|
||||
case I2C_SLAVE_WRITE_REQUESTED:
|
||||
status->index = 0;
|
||||
break;
|
||||
case I2C_SLAVE_READ_REQUESTED:
|
||||
case I2C_SLAVE_READ_PROCESSED:
|
||||
*val = 0xff;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_new_slave_host_notify_device - get a client for SMBus host-notify support
|
||||
* @adapter: the target adapter
|
||||
* Context: can sleep
|
||||
*
|
||||
* Setup handling of the SMBus host-notify protocol on a given I2C bus segment.
|
||||
*
|
||||
* Handling is done by creating a device and its callback and handling data
|
||||
* received via the SMBus host-notify address (0x8)
|
||||
*
|
||||
* This returns the client, which should be ultimately freed using
|
||||
* i2c_free_slave_host_notify_device(); or an ERRPTR to indicate an error.
|
||||
*/
|
||||
struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
|
||||
{
|
||||
struct i2c_board_info host_notify_board_info = {
|
||||
I2C_BOARD_INFO("smbus_host_notify", 0x08),
|
||||
.flags = I2C_CLIENT_SLAVE,
|
||||
};
|
||||
struct i2c_slave_host_notify_status *status;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
status = kzalloc(sizeof(struct i2c_slave_host_notify_status),
|
||||
GFP_KERNEL);
|
||||
if (!status)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
host_notify_board_info.platform_data = status;
|
||||
|
||||
client = i2c_new_client_device(adapter, &host_notify_board_info);
|
||||
if (IS_ERR(client)) {
|
||||
kfree(status);
|
||||
return client;
|
||||
}
|
||||
|
||||
ret = i2c_slave_register(client, i2c_slave_host_notify_cb);
|
||||
if (ret) {
|
||||
i2c_unregister_device(client);
|
||||
kfree(status);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_new_slave_host_notify_device);
|
||||
|
||||
/**
|
||||
* i2c_free_slave_host_notify_device - free the client for SMBus host-notify
|
||||
* support
|
||||
* @client: the client to free
|
||||
* Context: can sleep
|
||||
*
|
||||
* Free the i2c_client allocated via i2c_new_slave_host_notify_device
|
||||
*/
|
||||
void i2c_free_slave_host_notify_device(struct i2c_client *client)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(client))
|
||||
return;
|
||||
|
||||
i2c_slave_unregister(client);
|
||||
kfree(client->dev.platform_data);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SPD is not part of SMBus but we include it here for convenience as the
|
||||
* target systems are the same.
|
||||
|
@@ -85,18 +85,14 @@ static int i2c_mux_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
mux->control = devm_mux_control_get(dev, NULL);
|
||||
if (IS_ERR(mux->control)) {
|
||||
if (PTR_ERR(mux->control) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get control-mux\n");
|
||||
return PTR_ERR(mux->control);
|
||||
}
|
||||
if (IS_ERR(mux->control))
|
||||
return dev_err_probe(dev, PTR_ERR(mux->control),
|
||||
"failed to get control-mux\n");
|
||||
|
||||
parent = mux_parent_adapter(dev);
|
||||
if (IS_ERR(parent)) {
|
||||
if (PTR_ERR(parent) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get i2c-parent adapter\n");
|
||||
return PTR_ERR(parent);
|
||||
}
|
||||
if (IS_ERR(parent))
|
||||
return dev_err_probe(dev, PTR_ERR(parent),
|
||||
"failed to get i2c-parent adapter\n");
|
||||
|
||||
children = of_get_child_count(np);
|
||||
|
||||
|
@@ -171,13 +171,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
sizeof(mux->data));
|
||||
} else {
|
||||
ret = i2c_mux_reg_probe_dt(mux, pdev);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Error parsing device tree");
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Error parsing device tree");
|
||||
}
|
||||
|
||||
parent = i2c_get_adapter(mux->data.parent);
|
||||
|
Reference in New Issue
Block a user