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:
Linus Torvalds 2020-10-21 10:54:05 -07:00
commit b5df4b5c28
41 changed files with 4020 additions and 931 deletions

View File

@ -114,6 +114,9 @@ properties:
- const: renesas,r1ex24128
- const: atmel,24c128
label:
description: Descriptive name of the EEPROM.
reg:
maxItems: 1

View File

@ -9,12 +9,18 @@ title: Freescale Low Power Inter IC (LPI2C) for i.MX
maintainers:
- Anson Huang <Anson.Huang@nxp.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
enum:
- fsl,imx7ulp-lpi2c
- fsl,imx8qxp-lpi2c
- fsl,imx8qm-lpi2c
oneOf:
- enum:
- fsl,imx7ulp-lpi2c
- fsl,imx8qm-lpi2c
- items:
- const: fsl,imx8qxp-lpi2c
- const: fsl,imx7ulp-lpi2c
reg:
maxItems: 1
@ -22,23 +28,34 @@ properties:
interrupts:
maxItems: 1
assigned-clock-parents: true
assigned-clock-rates: true
assigned-clocks: true
clock-frequency: true
clock-names:
maxItems: 1
clocks:
maxItems: 1
power-domains:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
additionalProperties: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/imx7ulp-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
lpi2c7@40a50000 {
i2c@40a50000 {
compatible = "fsl,imx7ulp-lpi2c";
reg = <0x40A50000 0x10000>;
interrupt-parent = <&intc>;

View File

@ -9,6 +9,9 @@ title: Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX
maintainers:
- Wolfram Sang <wolfram@the-dreams.de>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
oneOf:
@ -18,6 +21,9 @@ properties:
- items:
- const: fsl,imx35-i2c
- const: fsl,imx1-i2c
- items:
- const: fsl,imx7d-i2c
- const: fsl,imx21-i2c
- items:
- enum:
- fsl,imx25-i2c
@ -75,7 +81,7 @@ required:
- interrupts
- clocks
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View File

@ -87,6 +87,11 @@ wants to support one of the below features, it should adapt these bindings.
this information to detect a stalled bus more reliably, for example.
Can not be combined with 'multi-master'.
- smbus
states that additional SMBus restrictions and features apply to this bus.
Examples of features are SMBusHostNotify and SMBusAlert. Examples of
restrictions are more reserved addresses and timeout definitions.
Required properties (per child device)
--------------------------------------

View File

@ -17,9 +17,13 @@ properties:
pattern: "^i2c@[0-9a-f]+$"
compatible:
enum:
- ingenic,jz4780-i2c
- ingenic,x1000-i2c
oneOf:
- enum:
- ingenic,jz4770-i2c
- ingenic,x1000-i2c
- items:
- const: ingenic,jz4780-i2c
- const: ingenic,jz4770-i2c
reg:
maxItems: 1
@ -60,7 +64,7 @@ examples:
#include <dt-bindings/dma/jz4780-dma.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c@10054000 {
compatible = "ingenic,jz4780-i2c";
compatible = "ingenic,jz4780-i2c", "ingenic,jz4770-i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10054000 0x1000>;

View File

@ -0,0 +1,42 @@
Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs
Required Properties:
- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2".
- reg : address offset and length of the device registers. The
registers consist of the following set of resources:
1) Smbus block registers.
2) Cause master registers.
3) Cause slave registers.
4) Cause coalesce registers (if compatible isn't set
to "mellanox,i2c-mlxbf1").
- interrupts : interrupt number.
Optional Properties:
- clock-frequency : bus frequency used to configure timing registers;
allowed values are 100000, 400000 and 1000000;
those are expressed in Hz. Default is 100000.
Example:
i2c@2804000 {
compatible = "mellanox,i2c-mlxbf1";
reg = <0x02804000 0x800>,
<0x02801200 0x020>,
<0x02801260 0x020>;
interrupts = <57>;
clock-frequency = <100000>;
};
i2c@2808800 {
compatible = "mellanox,i2c-mlxbf2";
reg = <0x02808800 0x600>,
<0x02808e00 0x020>,
<0x02808e20 0x020>,
<0x02808e40 0x010>;
interrupts = <57>;
clock-frequency = <400000>;
};

View File

@ -44,6 +44,7 @@ Supported adapters:
* Intel Tiger Lake (PCH)
* Intel Jasper Lake (SOC)
* Intel Emmitsburg (PCH)
* Intel Alder Lake (PCH)
Datasheets: Publicly available at the Intel website

View File

@ -47,6 +47,7 @@ Slave I2C
slave-interface
slave-eeprom-backend
slave-testunit-backend
Advanced topics
===============

View File

@ -0,0 +1,69 @@
.. SPDX-License-Identifier: GPL-2.0
================================
Linux I2C slave testunit backend
================================
by Wolfram Sang <wsa@sang-engineering.com> in 2020
This backend can be used to trigger test cases for I2C bus masters which
require a remote device with certain capabilities (and which are usually not so
easy to obtain). Examples include multi-master testing, and SMBus Host Notify
testing. For some tests, the I2C slave controller must be able to switch
between master and slave mode because it needs to send data, too.
Note that this is a device for testing and debugging. It should not be enabled
in a production build. And while there is some versioning and we try hard to
keep backward compatibility, there is no stable ABI guaranteed!
Instantiating the device is regular. Example for bus 0, address 0x30:
# echo "slave-testunit 0x1030" > /sys/bus/i2c/devices/i2c-0/new_device
After that, you will have a write-only device listening. Reads will just return
an 8-bit version number of the testunit. When writing, the device consists of 4
8-bit registers and all must be written to start a testcase, i.e. you must
always write 4 bytes to the device. The registers are:
0x00 CMD - which test to trigger
0x01 DATAL - configuration byte 1 for the test
0x02 DATAH - configuration byte 2 for the test
0x03 DELAY - delay in n * 10ms until test is started
Using 'i2cset' from the i2c-tools package, the generic command looks like:
# i2cset -y <bus_num> <testunit_address> <CMD> <DATAL> <DATAH> <DELAY> i
DELAY is a generic parameter which will delay the execution of the test in CMD.
While a command is running (including the delay), new commands will not be
acknowledged. You need to wait until the old one is completed.
The commands are described in the following section. An invalid command will
result in the transfer not being acknowledged.
Commands
--------
0x00 NOOP (reserved for future use)
0x01 READ_BYTES (also needs master mode)
DATAL - address to read data from (lower 7 bits, highest bit currently unused)
DATAH - number of bytes to read
This is useful to test if your bus master driver is handling multi-master
correctly. You can trigger the testunit to read bytes from another device on
the bus. If the bus master under test also wants to access the bus at the same
time, the bus will be busy. Example to read 128 bytes from device 0x50 after
50ms of delay:
# i2cset -y 0 0x30 0x01 0x50 0x80 0x05 i
0x02 SMBUS_HOST_NOTIFY (also needs master mode)
DATAL - low byte of the status word to send
DATAH - high byte of the status word to send
This test will send an SMBUS_HOST_NOTIFY message to the host. Note that the
status word is currently ignored in the Linux Kernel. Example to send a
notification after 10ms:
# i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i

View File

@ -11159,6 +11159,12 @@ W: http://www.melfas.com
F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
F: drivers/input/touchscreen/melfas_mip4.c
MELLANOX BLUEFIELD I2C DRIVER
M: Khalil Blaiech <kblaiech@mellanox.com>
L: linux-i2c@vger.kernel.org
S: Supported
F: drivers/i2c/busses/i2c-mlxbf.c
MELLANOX ETHERNET DRIVER (mlx4_en)
M: Tariq Toukan <tariqt@nvidia.com>
L: netdev@vger.kernel.org

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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,
},
};

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View 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");

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/capability.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
@ -89,6 +90,7 @@ struct at24_data {
struct nvmem_device *nvmem;
struct regulator *vcc_reg;
void (*read_post)(unsigned int off, char *buf, size_t count);
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
@ -121,6 +123,7 @@ MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
struct at24_chip_data {
u32 byte_len;
u8 flags;
void (*read_post)(unsigned int off, char *buf, size_t count);
};
#define AT24_CHIP_DATA(_name, _len, _flags) \
@ -128,6 +131,32 @@ struct at24_chip_data {
.byte_len = _len, .flags = _flags, \
}
#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post) \
static const struct at24_chip_data _name = { \
.byte_len = _len, .flags = _flags, \
.read_post = _read_post, \
}
static void at24_read_post_vaio(unsigned int off, char *buf, size_t count)
{
int i;
if (capable(CAP_SYS_ADMIN))
return;
/*
* Hide VAIO private settings to regular users:
* - BIOS passwords: bytes 0x00 to 0x0f
* - UUID: bytes 0x10 to 0x1f
* - Serial number: 0xc0 to 0xdf
*/
for (i = 0; i < count; i++) {
if ((off + i <= 0x1f) ||
(off + i >= 0xc0 && off + i <= 0xdf))
buf[i] = 0;
}
}
/* needs 8 addresses as A0-A2 are ignored */
AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR);
/* old variants can't be handled with this generic entry! */
@ -144,6 +173,10 @@ AT24_CHIP_DATA(at24_data_24mac602, 64 / 8,
/* spd is a 24c02 in memory DIMMs */
AT24_CHIP_DATA(at24_data_spd, 2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO);
/* 24c02_vaio is a 24c02 on some Sony laptops */
AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
at24_read_post_vaio);
AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0);
AT24_CHIP_DATA(at24_data_24cs04, 16,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
@ -177,6 +210,7 @@ static const struct i2c_device_id at24_ids[] = {
{ "24mac402", (kernel_ulong_t)&at24_data_24mac402 },
{ "24mac602", (kernel_ulong_t)&at24_data_24mac602 },
{ "spd", (kernel_ulong_t)&at24_data_spd },
{ "24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio },
{ "24c04", (kernel_ulong_t)&at24_data_24c04 },
{ "24cs04", (kernel_ulong_t)&at24_data_24cs04 },
{ "24c08", (kernel_ulong_t)&at24_data_24c08 },
@ -388,7 +422,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
struct at24_data *at24;
struct device *dev;
char *buf = val;
int ret;
int i, ret;
at24 = priv;
dev = at24_base_client_dev(at24);
@ -411,22 +445,22 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
*/
mutex_lock(&at24->lock);
while (count) {
ret = at24_regmap_read(at24, buf, off, count);
for (i = 0; count; i += ret, count -= ret) {
ret = at24_regmap_read(at24, buf + i, off + i, count);
if (ret < 0) {
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
return ret;
}
buf += ret;
off += ret;
count -= ret;
}
mutex_unlock(&at24->lock);
pm_runtime_put(dev);
if (unlikely(at24->read_post))
at24->read_post(off, buf, i);
return 0;
}
@ -654,6 +688,7 @@ static int at24_probe(struct i2c_client *client)
at24->byte_len = byte_len;
at24->page_size = page_size;
at24->flags = flags;
at24->read_post = cdata->read_post;
at24->num_addresses = num_addresses;
at24->offset_adj = at24_get_offset_adj(flags, byte_len);
at24->client[0].client = client;
@ -678,8 +713,30 @@ static int at24_probe(struct i2c_client *client)
return err;
}
nvmem_config.name = dev_name(dev);
/*
* If the 'label' property is not present for the AT24 EEPROM,
* then nvmem_config.id is initialised to NVMEM_DEVID_AUTO,
* and this will append the 'devid' to the name of the NVMEM
* device. This is purely legacy and the AT24 driver has always
* defaulted to this. However, if the 'label' property is
* present then this means that the name is specified by the
* firmware and this name should be used verbatim and so it is
* not necessary to append the 'devid'.
*/
if (device_property_present(dev, "label")) {
nvmem_config.id = NVMEM_DEVID_NONE;
err = device_property_read_string(dev, "label",
&nvmem_config.name);
if (err)
return err;
} else {
nvmem_config.id = NVMEM_DEVID_AUTO;
nvmem_config.name = dev_name(dev);
}
nvmem_config.type = NVMEM_TYPE_EEPROM;
nvmem_config.dev = dev;
nvmem_config.id = NVMEM_DEVID_AUTO;
nvmem_config.read_only = !writable;
nvmem_config.root_only = !(flags & AT24_FLAG_IRUGO);
nvmem_config.owner = THIS_MODULE;

View File

@ -76,7 +76,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj));
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct eeprom_data *data = i2c_get_clientdata(client);
u8 slice;

View File

@ -38,6 +38,18 @@ static inline int of_i2c_setup_smbus_alert(struct i2c_adapter *adap)
return 0;
}
#endif
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_I2C_SLAVE)
struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter);
void i2c_free_slave_host_notify_device(struct i2c_client *client);
#else
static inline struct i2c_client *i2c_new_slave_host_notify_device(struct i2c_adapter *adapter)
{
return ERR_PTR(-ENOSYS);
}
static inline void i2c_free_slave_host_notify_device(struct i2c_client *client)
{
}
#endif
#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_DMI)
void i2c_register_spd(struct i2c_adapter *adap);

View File

@ -344,7 +344,7 @@ const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
{
struct device * const dev = container_of(kobj, struct device, kobj);
struct device * const dev = kobj_to_dev(kobj);
return to_i2c_client(dev);
}