Merge branch 'i2c/for-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:

 - mostly driver updates. Bigger ones for mlxcpld and iproc. But most of
   them are all over the place.

 - removal of the efm32, sirf, u300, and zte zx bus drivers because of
   platform removal. So, we have a pleasant diffstat this time.

 - first set of cleanups in the I2C core as preparation to increase
   maximum length of SMBus transfers to 255 (as specified in the new
   standard). Better documentation of struct i2c_msg and its flags stand
   out here.

 - the testunit can now respond to SMBus block process calls which is
   the testcase when implementing the above new maximum length.

* 'i2c/for-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (62 commits)
  i2c: remove redundant error print in stm32f7_i2c_probe
  i2c: testunit: add support for block process calls
  i2c: busses: Replace spin_lock_irqsave with spin_lock in hard IRQ
  dt-bindings: eeprom: at24: Document ROHM BR24G01
  i2c: i801: Add support for Intel Alder Lake PCH-P
  i2c: mv64xxx: Fix check for missing clock after adding RPM
  i2c: mux: mlxcpld: Add callback to notify mux creation completion
  i2c: mux: mlxcpld: Extend supported mux number
  i2c: mux: mlxcpld: Extend driver to support word address space devices
  i2c: mux: mlxcpld: Get rid of adapter numbers enforcement
  i2c: mux: mlxcpld: Prepare mux selection infrastructure for two-byte support
  i2c: mux: mlxcpld: Convert driver to platform driver
  i2c: imx: Synthesize end of transaction events without idle interrupts
  i2c: i2c-qcom-geni: Add shutdown callback for i2c
  i2c: mv64xxx: Add runtime PM support
  i2c: amd-mp2: Remove unused macro
  i2c: amd-mp2: convert to PCI logging functions
  i2c: mux: mlxcpld: Move header file out of x86 realm
  platform/x86: mlxcpld: Update module license
  i2c: mux: mlxcpld: Update module license
  ...
This commit is contained in:
Linus Torvalds 2021-02-22 09:02:24 -08:00
commit 32c080c4b5
44 changed files with 908 additions and 3203 deletions

View File

@ -95,9 +95,6 @@ properties:
pattern: spd$
# These are special cases that don't conform to the above pattern.
# Each requires a standard at24 model as fallback.
- items:
- const: rohm,br24t01
- const: atmel,24c01
- items:
- const: nxp,se97b
- const: atmel,24c02
@ -113,6 +110,12 @@ properties:
- items:
- const: renesas,r1ex24128
- const: atmel,24c128
- items:
- const: rohm,br24g01
- const: atmel,24c01
- items:
- const: rohm,br24t01
- const: atmel,24c01
label:
description: Descriptive name of the EEPROM.

View File

@ -1,19 +0,0 @@
I2C for SiRFprimaII platforms
Required properties :
- compatible : Must be "sirf,prima2-i2c"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
The absence of the property indicates the default frequency 100 kHz.
Examples :
i2c0: i2c@b00e0000 {
compatible = "sirf,prima2-i2c";
reg = <0xb00e0000 0x10000>;
interrupts = <24>;
};

View File

@ -1,15 +0,0 @@
ST Microelectronics DDC I2C
Required properties :
- compatible : Must be "st,ddci2c"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties:
- Child nodes conforming to i2c bus binding
Examples :

View File

@ -1,22 +0,0 @@
ZTE zx2967 I2C controller
Required properties:
- compatible: must be "zte,zx296718-i2c"
- reg: physical address and length of the device registers
- interrupts: a single interrupt specifier
- clocks: clock for the device
- #address-cells: should be <1>
- #size-cells: should be <0>
- clock-frequency: the desired I2C bus clock frequency.
Examples:
i2c@112000 {
compatible = "zte,zx296718-i2c";
reg = <0x00112000 0x1000>;
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&osc24m>;
#address-cells = <1>
#size-cells = <0>;
clock-frequency = <1600000>;
};

View File

@ -18,21 +18,14 @@ properties:
- const: allwinner,sun4i-a10-i2c
- const: allwinner,sun6i-a31-i2c
- items:
- const: allwinner,sun8i-a23-i2c
- enum:
- allwinner,sun8i-a23-i2c
- allwinner,sun8i-a83t-i2c
- allwinner,sun50i-a64-i2c
- allwinner,sun50i-a100-i2c
- allwinner,sun50i-h6-i2c
- allwinner,sun50i-h616-i2c
- const: allwinner,sun6i-a31-i2c
- items:
- const: allwinner,sun8i-a83t-i2c
- const: allwinner,sun6i-a31-i2c
- items:
- const: allwinner,sun50i-a64-i2c
- const: allwinner,sun6i-a31-i2c
- items:
- const: allwinner,sun50i-a100-i2c
- const: allwinner,sun6i-a31-i2c
- items:
- const: allwinner,sun50i-h6-i2c
- const: allwinner,sun6i-a31-i2c
- const: marvell,mv64xxx-i2c
- const: marvell,mv78230-i2c
- const: marvell,mv78230-a0-i2c

View File

@ -26,6 +26,7 @@ Required properties:
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
"renesas,i2c-r8a77990" if the device is a part of a R8A77990 SoC.
"renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC.
"renesas,i2c-r8a779a0" if the device is a part of a R8A779A0 SoC.
"renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
"renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible
device.

View File

@ -22,8 +22,9 @@ Instantiating the device is regular. Example for bus 0, address 0x30:
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:
8-bit registers and, except for some "partial" commands, all registers must be
written to start a testcase, i.e. you usually write 4 bytes to the device. The
registers are:
0x00 CMD - which test to trigger
0x01 DATAL - configuration byte 1 for the test
@ -67,3 +68,21 @@ 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
0x03 SMBUS_BLOCK_PROC_CALL (partial command)
DATAL - must be '1', i.e. one further byte will be written
DATAH - number of bytes to be sent back
DELAY - not applicable, partial command!
This test will respond to a block process call as defined by the SMBus
specification. The one data byte written specifies how many bytes will be sent
back in the following read transfer. Note that in this read transfer, the
testunit will prefix the length of the bytes to follow. So, if your host bus
driver emulates SMBus calls like the majority does, it needs to support the
I2C_M_RECV_LEN flag of an i2c_msg. This is a good testcase for it. The returned
data consists of the length first, and then of an array of bytes from length-1
to 0. Here is an example which emulates i2c_smbus_block_process_call() using
i2ctransfer (you need i2c-tools v4.2 or later):
# i2ctransfer -y 0 w3@0x30 0x03 0x01 0x10 r?
0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00

View File

@ -3469,6 +3469,10 @@ EXPORT_SYMBOL_GPL(gpiod_add_lookup_table);
*/
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
{
/* Nothing to remove */
if (!table)
return;
mutex_lock(&gpio_lookup_lock);
list_del(&table->list);

View File

@ -622,9 +622,7 @@ static int bit_xfer_atomic(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
static u32 bit_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_SMBUS_READ_BLOCK_DATA |
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL_ALL |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
}

View File

@ -586,13 +586,6 @@ config I2C_DIGICOLOR
This driver can also be built as a module. If so, the module
will be called i2c-digicolor.
config I2C_EFM32
tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST
help
This driver supports the i2c block found in Energy Micro's EFM32
SoCs.
config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
@ -1000,16 +993,6 @@ config I2C_SIMTEC
This driver can also be built as a module. If so, the module
will be called i2c-simtec.
config I2C_SIRF
tristate "CSR SiRFprimaII I2C interface"
depends on ARCH_SIRF || COMPILE_TEST
help
If you say yes to this option, support will be included for the
CSR SiRFprimaII I2C interface.
This driver can also be built as a module. If so, the module
will be called i2c-sirf.
config I2C_SPRD
tristate "Spreadtrum I2C interface"
depends on I2C=y && (ARCH_SPRD || COMPILE_TEST)
@ -1050,19 +1033,6 @@ config I2C_STM32F7
This driver can also be built as module. If so, the module
will be called i2c-stm32f7.
config I2C_STU300
tristate "ST Microelectronics DDC I2C interface"
depends on MACH_U300 || COMPILE_TEST
default y if MACH_U300
help
If you say yes to this option, support will be included for the
I2C interface from ST Microelectronics simply called "DDC I2C"
supporting both I2C and DDC, used in e.g. the U300 series
mobile platforms.
This driver can also be built as a module. If so, the module
will be called i2c-stu300.
config I2C_SUN6I_P2WI
tristate "Allwinner sun6i internal P2WI controller"
depends on RESET_CONTROLLER
@ -1401,15 +1371,6 @@ config I2C_OPAL
This driver can also be built as a module. If so, the module will be
called as i2c-opal.
config I2C_ZX2967
tristate "ZTE ZX2967 I2C support"
depends on ARCH_ZX
default y
help
Selecting this option will add ZX2967 I2C driver.
This driver can also be built as a module. If so, the module will be
called i2c-zx2967.
config I2C_FSI
tristate "FSI I2C driver"
depends on FSI

View File

@ -58,7 +58,6 @@ i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-bayt
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-y := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
@ -99,13 +98,11 @@ obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o
obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o
obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
@ -122,7 +119,6 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o

View File

@ -30,7 +30,7 @@ static void amd_mp2_c2p_mutex_unlock(struct amd_i2c_common *i2c_common)
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
if (unlikely(privdata->c2p_lock_busid != i2c_common->bus_id)) {
dev_warn(ndev_dev(privdata),
pci_warn(privdata->pci_dev,
"bus %d attempting to unlock C2P locked by bus %d\n",
i2c_common->bus_id, privdata->c2p_lock_busid);
return;
@ -59,8 +59,7 @@ int amd_mp2_bus_enable_set(struct amd_i2c_common *i2c_common, bool enable)
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
union i2c_cmd_base i2c_cmd_base;
dev_dbg(ndev_dev(privdata), "%s id: %d\n", __func__,
i2c_common->bus_id);
pci_dbg(privdata->pci_dev, "id: %d\n", i2c_common->bus_id);
i2c_cmd_base.ul = 0;
i2c_cmd_base.s.i2c_cmd = enable ? i2c_enable : i2c_disable;
@ -111,20 +110,19 @@ EXPORT_SYMBOL_GPL(amd_mp2_rw);
static void amd_mp2_pci_check_rw_event(struct amd_i2c_common *i2c_common)
{
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
struct pci_dev *pdev = privdata->pci_dev;
int len = i2c_common->eventval.r.length;
u32 slave_addr = i2c_common->eventval.r.slave_addr;
bool err = false;
if (unlikely(len != i2c_common->msg->len)) {
dev_err(ndev_dev(privdata),
"length %d in event doesn't match buffer length %d!\n",
pci_err(pdev, "length %d in event doesn't match buffer length %d!\n",
len, i2c_common->msg->len);
err = true;
}
if (unlikely(slave_addr != i2c_common->msg->addr)) {
dev_err(ndev_dev(privdata),
"unexpected slave address %x (expected: %x)!\n",
pci_err(pdev, "unexpected slave address %x (expected: %x)!\n",
slave_addr, i2c_common->msg->addr);
err = true;
}
@ -136,13 +134,14 @@ static void amd_mp2_pci_check_rw_event(struct amd_i2c_common *i2c_common)
static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common)
{
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
struct pci_dev *pdev = privdata->pci_dev;
enum status_type sts = i2c_common->eventval.r.status;
enum response_type res = i2c_common->eventval.r.response;
int len = i2c_common->eventval.r.length;
if (res != command_success) {
if (res != command_failed)
dev_err(ndev_dev(privdata), "invalid response to i2c command!\n");
pci_err(pdev, "invalid response to i2c command!\n");
return;
}
@ -155,32 +154,26 @@ static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common)
privdata->mmio + AMD_C2P_MSG2,
len);
} else if (sts != i2c_readfail_event) {
dev_err(ndev_dev(privdata),
"invalid i2c status after read (%d)!\n", sts);
pci_err(pdev, "invalid i2c status after read (%d)!\n", sts);
}
break;
case i2c_write:
if (sts == i2c_writecomplete_event)
amd_mp2_pci_check_rw_event(i2c_common);
else if (sts != i2c_writefail_event)
dev_err(ndev_dev(privdata),
"invalid i2c status after write (%d)!\n", sts);
pci_err(pdev, "invalid i2c status after write (%d)!\n", sts);
break;
case i2c_enable:
if (sts == i2c_busenable_complete)
i2c_common->cmd_success = true;
else if (sts != i2c_busenable_failed)
dev_err(ndev_dev(privdata),
"invalid i2c status after bus enable (%d)!\n",
sts);
pci_err(pdev, "invalid i2c status after bus enable (%d)!\n", sts);
break;
case i2c_disable:
if (sts == i2c_busdisable_complete)
i2c_common->cmd_success = true;
else if (sts != i2c_busdisable_failed)
dev_err(ndev_dev(privdata),
"invalid i2c status after bus disable (%d)!\n",
sts);
pci_err(pdev, "invalid i2c status after bus disable (%d)!\n", sts);
break;
default:
break;
@ -190,10 +183,10 @@ static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common)
void amd_mp2_process_event(struct amd_i2c_common *i2c_common)
{
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
struct pci_dev *pdev = privdata->pci_dev;
if (unlikely(i2c_common->reqcmd == i2c_none)) {
dev_warn(ndev_dev(privdata),
"received msg but no cmd was sent (bus = %d)!\n",
pci_warn(pdev, "received msg but no cmd was sent (bus = %d)!\n",
i2c_common->bus_id);
return;
}
@ -208,6 +201,7 @@ EXPORT_SYMBOL_GPL(amd_mp2_process_event);
static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
{
struct amd_mp2_dev *privdata = dev;
struct pci_dev *pdev = privdata->pci_dev;
struct amd_i2c_common *i2c_common;
u32 val;
unsigned int bus_id;
@ -236,8 +230,7 @@ static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
val = readl(privdata->mmio + AMD_P2C_MSG_INTEN);
if (val != 0) {
writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
dev_warn(ndev_dev(privdata),
"received irq without message\n");
pci_warn(pdev, "received irq without message\n");
ret = IRQ_HANDLED;
}
}
@ -255,13 +248,13 @@ EXPORT_SYMBOL_GPL(amd_mp2_rw_timeout);
int amd_mp2_register_cb(struct amd_i2c_common *i2c_common)
{
struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
struct pci_dev *pdev = privdata->pci_dev;
if (i2c_common->bus_id > 1)
return -EINVAL;
if (privdata->busses[i2c_common->bus_id]) {
dev_err(ndev_dev(privdata),
"Bus %d already taken!\n", i2c_common->bus_id);
pci_err(pdev, "Bus %d already taken!\n", i2c_common->bus_id);
return -EINVAL;
}
@ -301,13 +294,13 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
rc = pcim_enable_device(pci_dev);
if (rc) {
dev_err(ndev_dev(privdata), "Failed to enable MP2 PCI device\n");
pci_err(pci_dev, "Failed to enable MP2 PCI device\n");
goto err_pci_enable;
}
rc = pcim_iomap_regions(pci_dev, 1 << 2, pci_name(pci_dev));
if (rc) {
dev_err(ndev_dev(privdata), "I/O memory remapping failed\n");
pci_err(pci_dev, "I/O memory remapping failed\n");
goto err_pci_enable;
}
privdata->mmio = pcim_iomap_table(pci_dev)[2];
@ -327,7 +320,7 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
rc = devm_request_irq(&pci_dev->dev, pci_dev->irq, amd_mp2_irq_isr,
IRQF_SHARED, dev_name(&pci_dev->dev), privdata);
if (rc)
dev_err(&pci_dev->dev, "Failure requesting irq %i: %d\n",
pci_err(pci_dev, "Failure requesting irq %i: %d\n",
pci_dev->irq, rc);
return rc;
@ -363,7 +356,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
privdata->probed = true;
dev_info(&pci_dev->dev, "MP2 device registered.\n");
pci_info(pci_dev, "MP2 device registered.\n");
return 0;
}
@ -397,8 +390,7 @@ static int amd_mp2_pci_suspend(struct device *dev)
ret = pci_save_state(pci_dev);
if (ret) {
dev_err(ndev_dev(privdata),
"pci_save_state failed = %d\n", ret);
pci_err(pci_dev, "pci_save_state failed = %d\n", ret);
return ret;
}
@ -417,8 +409,7 @@ static int amd_mp2_pci_resume(struct device *dev)
pci_restore_state(pci_dev);
ret = pci_enable_device(pci_dev);
if (ret < 0) {
dev_err(ndev_dev(privdata),
"pci_enable_device failed = %d\n", ret);
pci_err(pci_dev, "pci_enable_device failed = %d\n", ret);
return ret;
}

View File

@ -88,8 +88,7 @@ static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common)
union i2c_event *event = &i2c_common->eventval;
if (event->r.status == i2c_readcomplete_event)
dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
__func__, event->r.length,
dev_dbg(&i2c_dev->pdev->dev, "readdata:%*ph\n", event->r.length,
i2c_common->msg->buf);
complete(&i2c_dev->cmd_complete);

View File

@ -185,12 +185,6 @@ struct amd_mp2_dev {
unsigned int probed;
};
#define ndev_pdev(ndev) ((ndev)->pci_dev)
#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
#define work_amd_i2c_common(__work) \
container_of(__work, struct amd_i2c_common, work.work)
/* PCIe communication driver */
int amd_mp2_rw(struct amd_i2c_common *i2c_common, enum i2c_cmd reqcmd);

View File

@ -93,6 +93,7 @@
#define S_CMD_STATUS_MASK 0x07
#define S_CMD_STATUS_SUCCESS 0x0
#define S_CMD_STATUS_TIMEOUT 0x5
#define S_CMD_STATUS_MASTER_ABORT 0x7
#define IE_OFFSET 0x38
#define IE_M_RX_FIFO_FULL_SHIFT 31
@ -159,6 +160,11 @@
#define IE_S_ALL_INTERRUPT_SHIFT 21
#define IE_S_ALL_INTERRUPT_MASK 0x3f
/*
* It takes ~18us to reading 10bytes of data, hence to keep tasklet
* running for less time, max slave read per tasklet is set to 10 bytes.
*/
#define MAX_SLAVE_RX_PER_INT 10
enum i2c_slave_read_status {
I2C_SLAVE_RX_FIFO_EMPTY = 0,
@ -205,8 +211,18 @@ struct bcm_iproc_i2c_dev {
/* bytes that have been read */
unsigned int rx_bytes;
unsigned int thld_bytes;
bool slave_rx_only;
bool rx_start_rcvd;
bool slave_read_complete;
u32 tx_underrun;
u32 slave_int_mask;
struct tasklet_struct slave_rx_tasklet;
};
/* tasklet to process slave rx data */
static void slave_rx_tasklet_fn(unsigned long);
/*
* Can be expanded in the future if more interrupt status bits are utilized
*/
@ -215,7 +231,8 @@ struct bcm_iproc_i2c_dev {
#define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
| BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
| BIT(IS_S_TX_UNDERRUN_SHIFT))
| BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\
| BIT(IS_S_RX_THLD_SHIFT))
static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave);
static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave);
@ -259,6 +276,7 @@ static void bcm_iproc_i2c_slave_init(
{
u32 val;
iproc_i2c->tx_underrun = 0;
if (need_reset) {
/* put controller in reset */
val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET);
@ -295,8 +313,13 @@ static void bcm_iproc_i2c_slave_init(
/* Enable interrupt register to indicate a valid byte in receive fifo */
val = BIT(IE_S_RX_EVENT_SHIFT);
/* Enable interrupt register to indicate Slave Rx FIFO Full */
val |= BIT(IE_S_RX_FIFO_FULL_SHIFT);
/* Enable interrupt register to indicate a Master read transaction */
val |= BIT(IE_S_RD_EVENT_SHIFT);
/* Enable interrupt register for the Slave BUSY command */
val |= BIT(IE_S_START_BUSY_SHIFT);
iproc_i2c->slave_int_mask = val;
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
}
@ -311,9 +334,10 @@ static void bcm_iproc_i2c_check_slave_status(
return;
val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
if (val == S_CMD_STATUS_TIMEOUT) {
dev_err(iproc_i2c->device, "slave random stretch time timeout\n");
if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) {
dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ?
"slave random stretch time timeout\n" :
"Master aborted read transaction\n");
/* re-initialize i2c for recovery */
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
bcm_iproc_i2c_slave_init(iproc_i2c, true);
@ -321,76 +345,187 @@ static void bcm_iproc_i2c_check_slave_status(
}
}
static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c)
{
u8 rx_data, rx_status;
u32 rx_bytes = 0;
u32 val;
while (rx_bytes < MAX_SLAVE_RX_PER_INT) {
val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
rx_data = ((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
if (rx_status == I2C_SLAVE_RX_START) {
/* Start of SMBUS Master write */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_REQUESTED, &rx_data);
iproc_i2c->rx_start_rcvd = true;
iproc_i2c->slave_read_complete = false;
} else if (rx_status == I2C_SLAVE_RX_DATA &&
iproc_i2c->rx_start_rcvd) {
/* Middle of SMBUS Master write */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED, &rx_data);
} else if (rx_status == I2C_SLAVE_RX_END &&
iproc_i2c->rx_start_rcvd) {
/* End of SMBUS Master write */
if (iproc_i2c->slave_rx_only)
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED,
&rx_data);
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP,
&rx_data);
} else if (rx_status == I2C_SLAVE_RX_FIFO_EMPTY) {
iproc_i2c->rx_start_rcvd = false;
iproc_i2c->slave_read_complete = true;
break;
}
rx_bytes++;
}
}
static void slave_rx_tasklet_fn(unsigned long data)
{
struct bcm_iproc_i2c_dev *iproc_i2c = (struct bcm_iproc_i2c_dev *)data;
u32 int_clr;
bcm_iproc_i2c_slave_read(iproc_i2c);
/* clear pending IS_S_RX_EVENT_SHIFT interrupt */
int_clr = BIT(IS_S_RX_EVENT_SHIFT);
if (!iproc_i2c->slave_rx_only && iproc_i2c->slave_read_complete) {
/*
* In case of single byte master-read request,
* IS_S_TX_UNDERRUN_SHIFT event is generated before
* IS_S_START_BUSY_SHIFT event. Hence start slave data send
* from first IS_S_TX_UNDERRUN_SHIFT event.
*
* This means don't send any data from slave when
* IS_S_RD_EVENT_SHIFT event is generated else it will increment
* eeprom or other backend slave driver read pointer twice.
*/
iproc_i2c->tx_underrun = 0;
iproc_i2c->slave_int_mask |= BIT(IE_S_TX_UNDERRUN_SHIFT);
/* clear IS_S_RD_EVENT_SHIFT interrupt */
int_clr |= BIT(IS_S_RD_EVENT_SHIFT);
}
/* clear slave interrupt */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, int_clr);
/* enable slave interrupts */
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, iproc_i2c->slave_int_mask);
}
static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
u32 status)
{
u32 val;
u8 value, rx_status;
u8 value;
/* Slave RX byte receive */
if (status & BIT(IS_S_RX_EVENT_SHIFT)) {
val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
if (rx_status == I2C_SLAVE_RX_START) {
/* Start of SMBUS for Master write */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_REQUESTED, &value);
/*
* Slave events in case of master-write, master-write-read and,
* master-read
*
* Master-write : only IS_S_RX_EVENT_SHIFT event
* Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events
* Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
* events or only IS_S_RD_EVENT_SHIFT
*
* iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
* (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
* full. This can happen if Master issues write requests of more than
* 64 bytes.
*/
if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
status & BIT(IS_S_RD_EVENT_SHIFT) ||
status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
/* disable slave interrupts */
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
val &= ~iproc_i2c->slave_int_mask;
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED, &value);
} else if (status & BIT(IS_S_RD_EVENT_SHIFT)) {
if (status & BIT(IS_S_RD_EVENT_SHIFT))
/* Master-write-read request */
iproc_i2c->slave_rx_only = false;
else
/* Master-write request only */
iproc_i2c->slave_rx_only = true;
/* schedule tasklet to read data later */
tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
/*
* clear only IS_S_RX_EVENT_SHIFT and
* IS_S_RX_FIFO_FULL_SHIFT interrupt.
*/
val = BIT(IS_S_RX_EVENT_SHIFT);
if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT))
val |= BIT(IS_S_RX_FIFO_FULL_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
}
if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
iproc_i2c->tx_underrun++;
if (iproc_i2c->tx_underrun == 1)
/* Start of SMBUS for Master Read */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_READ_REQUESTED, &value);
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
val = BIT(S_CMD_START_BUSY_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
/*
* Enable interrupt for TX FIFO becomes empty and
* less than PKT_LENGTH bytes were output on the SMBUS
*/
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
val |= BIT(IE_S_TX_UNDERRUN_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
} else {
/* Master write other than start */
value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
I2C_SLAVE_READ_REQUESTED,
&value);
else
/* Master read other than start */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_WRITE_RECEIVED, &value);
if (rx_status == I2C_SLAVE_RX_END)
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_STOP, &value);
}
} else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
/* Master read other than start */
i2c_slave_event(iproc_i2c->slave,
I2C_SLAVE_READ_PROCESSED, &value);
I2C_SLAVE_READ_PROCESSED,
&value);
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
/* start transfer */
val = BIT(S_CMD_START_BUSY_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
/* clear interrupt */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
BIT(IS_S_TX_UNDERRUN_SHIFT));
}
/* Stop */
/* Stop received from master in case of master read transaction */
if (status & BIT(IS_S_START_BUSY_SHIFT)) {
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
/*
* Enable interrupt for TX FIFO becomes empty and
* Disable interrupt for TX FIFO becomes empty and
* less than PKT_LENGTH bytes were output on the SMBUS
*/
val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET,
iproc_i2c->slave_int_mask);
/* End of SMBUS for Master Read */
val = BIT(S_TX_WR_STATUS_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val);
val = BIT(S_CMD_START_BUSY_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
/* flush TX FIFOs */
val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET);
val |= (BIT(S_FIFO_TX_FLUSH_SHIFT));
iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
/* clear interrupt */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
BIT(IS_S_START_BUSY_SHIFT));
}
/* clear interrupt status */
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status);
/* check slave transmit status only if slave is transmitting */
if (!iproc_i2c->slave_rx_only)
bcm_iproc_i2c_check_slave_status(iproc_i2c);
bcm_iproc_i2c_check_slave_status(iproc_i2c);
return true;
}
@ -505,12 +640,17 @@ static void bcm_iproc_i2c_process_m_event(struct bcm_iproc_i2c_dev *iproc_i2c,
static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
{
struct bcm_iproc_i2c_dev *iproc_i2c = data;
u32 status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET);
u32 slave_status;
u32 status;
bool ret;
u32 sl_status = status & ISR_MASK_SLAVE;
if (sl_status) {
ret = bcm_iproc_i2c_slave_isr(iproc_i2c, sl_status);
status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET);
/* process only slave interrupt which are enabled */
slave_status = status & iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET) &
ISR_MASK_SLAVE;
if (slave_status) {
ret = bcm_iproc_i2c_slave_isr(iproc_i2c, slave_status);
if (ret)
return IRQ_HANDLED;
else
@ -1066,6 +1206,10 @@ static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave)
return -EAFNOSUPPORT;
iproc_i2c->slave = slave;
tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn,
(unsigned long)iproc_i2c);
bcm_iproc_i2c_slave_init(iproc_i2c, false);
return 0;
}
@ -1086,6 +1230,8 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave)
IE_S_ALL_INTERRUPT_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp);
tasklet_kill(&iproc_i2c->slave_rx_tasklet);
/* Erase the slave address programmed */
tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET);
tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);

View File

@ -160,12 +160,11 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
{
struct dc_i2c *i2c = dev_id;
int cmd_status = dc_i2c_cmd_status(i2c);
unsigned long flags;
u8 addr_cmd;
writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
spin_lock_irqsave(&i2c->lock, flags);
spin_lock(&i2c->lock);
if (cmd_status == II_CMD_STATUS_ACK_BAD
|| cmd_status == II_CMD_STATUS_ABORT) {
@ -207,7 +206,7 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
}
out:
spin_unlock_irqrestore(&i2c->lock, flags);
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}

View File

@ -1,469 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/clk.h>
#define DRIVER_NAME "efm32-i2c"
#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
#define REG_CTRL 0x00
#define REG_CTRL_EN 0x00001
#define REG_CTRL_SLAVE 0x00002
#define REG_CTRL_AUTOACK 0x00004
#define REG_CTRL_AUTOSE 0x00008
#define REG_CTRL_AUTOSN 0x00010
#define REG_CTRL_ARBDIS 0x00020
#define REG_CTRL_GCAMEN 0x00040
#define REG_CTRL_CLHR__MASK 0x00300
#define REG_CTRL_BITO__MASK 0x03000
#define REG_CTRL_BITO_OFF 0x00000
#define REG_CTRL_BITO_40PCC 0x01000
#define REG_CTRL_BITO_80PCC 0x02000
#define REG_CTRL_BITO_160PCC 0x03000
#define REG_CTRL_GIBITO 0x08000
#define REG_CTRL_CLTO__MASK 0x70000
#define REG_CTRL_CLTO_OFF 0x00000
#define REG_CMD 0x04
#define REG_CMD_START 0x00001
#define REG_CMD_STOP 0x00002
#define REG_CMD_ACK 0x00004
#define REG_CMD_NACK 0x00008
#define REG_CMD_CONT 0x00010
#define REG_CMD_ABORT 0x00020
#define REG_CMD_CLEARTX 0x00040
#define REG_CMD_CLEARPC 0x00080
#define REG_STATE 0x08
#define REG_STATE_BUSY 0x00001
#define REG_STATE_MASTER 0x00002
#define REG_STATE_TRANSMITTER 0x00004
#define REG_STATE_NACKED 0x00008
#define REG_STATE_BUSHOLD 0x00010
#define REG_STATE_STATE__MASK 0x000e0
#define REG_STATE_STATE_IDLE 0x00000
#define REG_STATE_STATE_WAIT 0x00020
#define REG_STATE_STATE_START 0x00040
#define REG_STATE_STATE_ADDR 0x00060
#define REG_STATE_STATE_ADDRACK 0x00080
#define REG_STATE_STATE_DATA 0x000a0
#define REG_STATE_STATE_DATAACK 0x000c0
#define REG_STATUS 0x0c
#define REG_STATUS_PSTART 0x00001
#define REG_STATUS_PSTOP 0x00002
#define REG_STATUS_PACK 0x00004
#define REG_STATUS_PNACK 0x00008
#define REG_STATUS_PCONT 0x00010
#define REG_STATUS_PABORT 0x00020
#define REG_STATUS_TXC 0x00040
#define REG_STATUS_TXBL 0x00080
#define REG_STATUS_RXDATAV 0x00100
#define REG_CLKDIV 0x10
#define REG_CLKDIV_DIV__MASK 0x001ff
#define REG_CLKDIV_DIV(div) MASK_VAL(REG_CLKDIV_DIV__MASK, (div))
#define REG_SADDR 0x14
#define REG_SADDRMASK 0x18
#define REG_RXDATA 0x1c
#define REG_RXDATAP 0x20
#define REG_TXDATA 0x24
#define REG_IF 0x28
#define REG_IF_START 0x00001
#define REG_IF_RSTART 0x00002
#define REG_IF_ADDR 0x00004
#define REG_IF_TXC 0x00008
#define REG_IF_TXBL 0x00010
#define REG_IF_RXDATAV 0x00020
#define REG_IF_ACK 0x00040
#define REG_IF_NACK 0x00080
#define REG_IF_MSTOP 0x00100
#define REG_IF_ARBLOST 0x00200
#define REG_IF_BUSERR 0x00400
#define REG_IF_BUSHOLD 0x00800
#define REG_IF_TXOF 0x01000
#define REG_IF_RXUF 0x02000
#define REG_IF_BITO 0x04000
#define REG_IF_CLTO 0x08000
#define REG_IF_SSTOP 0x10000
#define REG_IFS 0x2c
#define REG_IFC 0x30
#define REG_IFC__MASK 0x1ffcf
#define REG_IEN 0x34
#define REG_ROUTE 0x38
#define REG_ROUTE_SDAPEN 0x00001
#define REG_ROUTE_SCLPEN 0x00002
#define REG_ROUTE_LOCATION__MASK 0x00700
#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
struct efm32_i2c_ddata {
struct i2c_adapter adapter;
struct clk *clk;
void __iomem *base;
unsigned int irq;
u8 location;
unsigned long frequency;
/* transfer data */
struct completion done;
struct i2c_msg *msgs;
size_t num_msgs;
size_t current_word, current_msg;
int retval;
};
static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset)
{
return readl(ddata->base + offset);
}
static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata,
unsigned offset, u32 value)
{
writel(value, ddata->base + offset);
}
static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg));
}
static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
if (ddata->current_word >= cur_msg->len) {
/* cur_msg completely transferred */
ddata->current_word = 0;
ddata->current_msg += 1;
if (ddata->current_msg >= ddata->num_msgs) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_msg(ddata);
}
} else {
efm32_i2c_write32(ddata, REG_TXDATA,
cur_msg->buf[ddata->current_word++]);
}
}
static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata)
{
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA);
ddata->current_word += 1;
if (ddata->current_word >= cur_msg->len) {
/* cur_msg completely transferred */
ddata->current_word = 0;
ddata->current_msg += 1;
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK);
if (ddata->current_msg >= ddata->num_msgs) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_msg(ddata);
}
} else {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK);
}
}
static irqreturn_t efm32_i2c_irq(int irq, void *dev_id)
{
struct efm32_i2c_ddata *ddata = dev_id;
struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
u32 irqflag = efm32_i2c_read32(ddata, REG_IF);
u32 state = efm32_i2c_read32(ddata, REG_STATE);
efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK);
switch (state & REG_STATE_STATE__MASK) {
case REG_STATE_STATE_IDLE:
/* arbitration lost? */
ddata->retval = -EAGAIN;
complete(&ddata->done);
break;
case REG_STATE_STATE_WAIT:
/*
* huh, this shouldn't happen.
* Reset hardware state and get out
*/
ddata->retval = -EIO;
efm32_i2c_write32(ddata, REG_CMD,
REG_CMD_STOP | REG_CMD_ABORT |
REG_CMD_CLEARTX | REG_CMD_CLEARPC);
complete(&ddata->done);
break;
case REG_STATE_STATE_START:
/* "caller" is expected to send an address */
break;
case REG_STATE_STATE_ADDR:
/* wait for Ack or NAck of slave */
break;
case REG_STATE_STATE_ADDRACK:
if (state & REG_STATE_NACKED) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
ddata->retval = -ENXIO;
complete(&ddata->done);
} else if (cur_msg->flags & I2C_M_RD) {
/* wait for slave to send first data byte */
} else {
efm32_i2c_send_next_byte(ddata);
}
break;
case REG_STATE_STATE_DATA:
if (cur_msg->flags & I2C_M_RD) {
efm32_i2c_recv_next_byte(ddata);
} else {
/* wait for Ack or Nack of slave */
}
break;
case REG_STATE_STATE_DATAACK:
if (state & REG_STATE_NACKED) {
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
complete(&ddata->done);
} else {
efm32_i2c_send_next_byte(ddata);
}
}
return IRQ_HANDLED;
}
static int efm32_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap);
int ret;
if (ddata->msgs)
return -EBUSY;
ddata->msgs = msgs;
ddata->num_msgs = num;
ddata->current_word = 0;
ddata->current_msg = 0;
ddata->retval = -EIO;
reinit_completion(&ddata->done);
dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n",
efm32_i2c_read32(ddata, REG_STATE),
efm32_i2c_read32(ddata, REG_STATUS));
efm32_i2c_send_next_msg(ddata);
wait_for_completion(&ddata->done);
if (ddata->current_msg >= ddata->num_msgs)
ret = ddata->num_msgs;
else
ret = ddata->retval;
return ret;
}
static u32 efm32_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm efm32_i2c_algo = {
.master_xfer = efm32_i2c_master_xfer,
.functionality = efm32_i2c_functionality,
};
static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata)
{
u32 reg = efm32_i2c_read32(ddata, REG_ROUTE);
return (reg & REG_ROUTE_LOCATION__MASK) >>
__ffs(REG_ROUTE_LOCATION__MASK);
}
static int efm32_i2c_probe(struct platform_device *pdev)
{
struct efm32_i2c_ddata *ddata;
struct resource *res;
unsigned long rate;
struct device_node *np = pdev->dev.of_node;
u32 location, frequency;
int ret;
u32 clkdiv;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
platform_set_drvdata(pdev, ddata);
init_completion(&ddata->done);
strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name));
ddata->adapter.owner = THIS_MODULE;
ddata->adapter.algo = &efm32_i2c_algo;
ddata->adapter.dev.parent = &pdev->dev;
ddata->adapter.dev.of_node = pdev->dev.of_node;
i2c_set_adapdata(&ddata->adapter, ddata);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
ret = PTR_ERR(ddata->clk);
dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
return ret;
}
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;
}
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
if (!ret)
ret = -EINVAL;
return ret;
}
ddata->irq = ret;
ret = clk_prepare_enable(ddata->clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
return ret;
}
ret = of_property_read_u32(np, "energymicro,location", &location);
if (ret)
/* fall back to wrongly namespaced property */
ret = of_property_read_u32(np, "efm32,location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
/* default to location configured in hardware */
location = efm32_i2c_get_configured_location(ddata);
dev_info(&pdev->dev, "fall back to location %u\n", location);
}
ddata->location = location;
ret = of_property_read_u32(np, "clock-frequency", &frequency);
if (!ret) {
dev_dbg(&pdev->dev, "using frequency %u\n", frequency);
} else {
frequency = I2C_MAX_STANDARD_MODE_FREQ;
dev_info(&pdev->dev, "defaulting to 100 kHz\n");
}
ddata->frequency = frequency;
rate = clk_get_rate(ddata->clk);
if (!rate) {
dev_err(&pdev->dev, "there is no input clock available\n");
ret = -EINVAL;
goto err_disable_clk;
}
clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1;
if (clkdiv >= 0x200) {
dev_err(&pdev->dev,
"input clock too fast (%lu) to divide down to bus freq (%lu)",
rate, ddata->frequency);
ret = -EINVAL;
goto err_disable_clk;
}
dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n",
rate, ddata->frequency, (unsigned long)clkdiv);
efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv));
efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN |
REG_ROUTE_SCLPEN |
REG_ROUTE_LOCATION(ddata->location));
efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN |
REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO);
efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK);
efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK
| REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV);
/* to make bus idle */
efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT);
ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
goto err_disable_clk;
}
ret = i2c_add_adapter(&ddata->adapter);
if (ret) {
free_irq(ddata->irq, ddata);
err_disable_clk:
clk_disable_unprepare(ddata->clk);
}
return ret;
}
static int efm32_i2c_remove(struct platform_device *pdev)
{
struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev);
i2c_del_adapter(&ddata->adapter);
free_irq(ddata->irq, ddata);
clk_disable_unprepare(ddata->clk);
return 0;
}
static const struct of_device_id efm32_i2c_dt_ids[] = {
{
.compatible = "energymicro,efm32-i2c",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids);
static struct platform_driver efm32_i2c_driver = {
.probe = efm32_i2c_probe,
.remove = efm32_i2c_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = efm32_i2c_dt_ids,
},
};
module_platform_driver(efm32_i2c_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 i2c driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View File

@ -49,7 +49,7 @@ static int mmapped;
static wait_queue_head_t pcf_wait;
static int pcf_pending;
static spinlock_t lock;
static DEFINE_SPINLOCK(lock);
static struct i2c_adapter pcf_isa_ops;
@ -132,7 +132,6 @@ static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
static int pcf_isa_init(void)
{
spin_lock_init(&lock);
if (!mmapped) {
if (!request_region(base, 2, pcf_isa_ops.name)) {
printk(KERN_ERR "%s: requested I/O region (%#x:2) is "

View File

@ -520,5 +520,5 @@ module_exit(i2c_gpio_exit);
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-gpio");

View File

@ -413,10 +413,8 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
if (irq <= 0)
return irq;
}
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {

View File

@ -72,6 +72,7 @@
* 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
* Alder Lake-P (PCH) 0x51a3 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@ -228,6 +229,7 @@
#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3
#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
@ -1084,6 +1086,7 @@ static const struct pci_device_id i801_ids[] = {
{ 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) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS) },
{ 0, }
};
@ -1433,7 +1436,7 @@ static int i801_add_mux(struct i801_priv *priv)
const struct i801_mux_config *mux_config;
struct i2c_mux_gpio_platform_data gpio_data;
struct gpiod_lookup_table *lookup;
int err, i;
int i;
if (!priv->mux_drvdata)
return 0;
@ -1473,22 +1476,17 @@ static int i801_add_mux(struct i801_priv *priv)
PLATFORM_DEVID_NONE, &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);
gpiod_remove_lookup_table(lookup);
priv->mux_pdev = NULL;
dev_err(dev, "Failed to register i2c-mux-gpio device\n");
return err;
}
return 0;
return PTR_ERR_OR_ZERO(priv->mux_pdev);
}
static void i801_del_mux(struct i801_priv *priv)
{
if (priv->mux_pdev)
platform_device_unregister(priv->mux_pdev);
if (priv->lookup)
gpiod_remove_lookup_table(priv->lookup);
platform_device_unregister(priv->mux_pdev);
gpiod_remove_lookup_table(priv->lookup);
}
static unsigned int i801_get_adapter_class(struct i801_priv *priv)
@ -1772,6 +1770,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS:
case PCI_DEVICE_ID_INTEL_EBG_SMBUS:
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS:
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS:
priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;

View File

@ -209,6 +209,7 @@ struct imx_i2c_struct {
struct imx_i2c_dma *dma;
struct i2c_client *slave;
enum i2c_slave_event last_slave_event;
};
static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
@ -550,7 +551,7 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
i2c_imx->cur_clk = i2c_clk_rate;
div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
div = DIV_ROUND_UP(i2c_clk_rate, i2c_imx->bitrate);
if (div < i2c_clk_div[0].div)
i = 0;
else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
@ -568,8 +569,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
* This delay is used in I2C bus disable function
* to fix chip hardware bug.
*/
i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div
+ (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
i2c_imx->disable_delay = DIV_ROUND_UP(500000U * i2c_clk_div[i].div,
i2c_clk_rate / 2);
#ifdef CONFIG_I2C_DEBUG_BUS
dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n",
@ -675,6 +676,36 @@ static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx)
}
}
static void i2c_imx_slave_event(struct imx_i2c_struct *i2c_imx,
enum i2c_slave_event event, u8 *val)
{
i2c_slave_event(i2c_imx->slave, event, val);
i2c_imx->last_slave_event = event;
}
static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx)
{
u8 val;
while (i2c_imx->last_slave_event != I2C_SLAVE_STOP) {
switch (i2c_imx->last_slave_event) {
case I2C_SLAVE_READ_REQUESTED:
i2c_imx_slave_event(i2c_imx, I2C_SLAVE_READ_PROCESSED,
&val);
break;
case I2C_SLAVE_WRITE_REQUESTED:
case I2C_SLAVE_READ_PROCESSED:
case I2C_SLAVE_WRITE_RECEIVED:
i2c_imx_slave_event(i2c_imx, I2C_SLAVE_STOP, &val);
break;
case I2C_SLAVE_STOP:
break;
}
}
}
static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
unsigned int status, unsigned int ctl)
{
@ -687,9 +718,11 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
}
if (status & I2SR_IAAS) { /* Addressed as a slave */
i2c_imx_slave_finish_op(i2c_imx);
if (status & I2SR_SRW) { /* Master wants to read from us*/
dev_dbg(&i2c_imx->adapter.dev, "read requested");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
i2c_imx_slave_event(i2c_imx,
I2C_SLAVE_READ_REQUESTED, &value);
/* Slave transmit */
ctl |= I2CR_MTX;
@ -699,7 +732,8 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
} else { /* Master wants to write to us */
dev_dbg(&i2c_imx->adapter.dev, "write requested");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
i2c_imx_slave_event(i2c_imx,
I2C_SLAVE_WRITE_REQUESTED, &value);
/* Slave receive */
ctl &= ~I2CR_MTX;
@ -710,17 +744,20 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
} else if (!(ctl & I2CR_MTX)) { /* Receive mode */
if (status & I2SR_IBB) { /* No STOP signal detected */
value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
i2c_imx_slave_event(i2c_imx,
I2C_SLAVE_WRITE_RECEIVED, &value);
} else { /* STOP signal is detected */
dev_dbg(&i2c_imx->adapter.dev,
"STOP signal detected");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
i2c_imx_slave_event(i2c_imx,
I2C_SLAVE_STOP, &value);
}
} else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */
ctl |= I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value);
i2c_imx_slave_event(i2c_imx,
I2C_SLAVE_READ_PROCESSED, &value);
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
} else { /* Transmit mode received NAK */
@ -761,6 +798,7 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
return -EBUSY;
i2c_imx->slave = client;
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
/* Resume */
ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
@ -813,10 +851,17 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (status & I2SR_IIF) {
i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
if (i2c_imx->slave && !(ctl & I2CR_MSTA))
return i2c_imx_slave_isr(i2c_imx, status, ctl);
if (i2c_imx->slave) {
if (!(ctl & I2CR_MSTA)) {
return i2c_imx_slave_isr(i2c_imx, status, ctl);
} else if (i2c_imx->last_slave_event !=
I2C_SLAVE_STOP) {
i2c_imx_slave_finish_op(i2c_imx);
}
}
return i2c_imx_master_isr(i2c_imx, status);
}

View File

@ -437,9 +437,8 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
unsigned short intst;
unsigned short intmsk;
struct jz4780_i2c *i2c = dev_id;
unsigned long flags;
spin_lock_irqsave(&i2c->lock, flags);
spin_lock(&i2c->lock);
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
@ -551,7 +550,7 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
}
done:
spin_unlock_irqrestore(&i2c->lock, flags);
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}

View File

@ -1,34 +1,8 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/*
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
* Mellanox i2c driver
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* Copyright (C) 2016-2020 Mellanox Technologies
*/
#include <linux/delay.h>
@ -37,7 +11,9 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_data/mlxreg.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* General defines */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000
@ -51,7 +27,7 @@
#define MLXCPLD_I2C_MAX_ADDR_LEN 4
#define MLXCPLD_I2C_RETR_NUM 2
#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */
#define MLXCPLD_I2C_POLL_TIME 400 /* usec */
/* LPC I2C registers */
#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0
@ -72,6 +48,16 @@
#define MLXCPLD_LPCI2C_ACK_IND 1
#define MLXCPLD_LPCI2C_NACK_IND 2
#define MLXCPLD_I2C_FREQ_1000KHZ_SET 0x04
#define MLXCPLD_I2C_FREQ_400KHZ_SET 0x0f
#define MLXCPLD_I2C_FREQ_100KHZ_SET 0x42
enum mlxcpld_i2c_frequency {
MLXCPLD_I2C_FREQ_1000KHZ = 1,
MLXCPLD_I2C_FREQ_400KHZ = 2,
MLXCPLD_I2C_FREQ_100KHZ = 3,
};
struct mlxcpld_i2c_curr_xfer {
u8 cmd;
u8 addr_width;
@ -489,8 +475,45 @@ static struct i2c_adapter mlxcpld_i2c_adapter = {
.nr = MLXCPLD_I2C_BUS_NUM,
};
static int
mlxcpld_i2c_set_frequency(struct mlxcpld_i2c_priv *priv,
struct mlxreg_core_hotplug_platform_data *pdata)
{
struct mlxreg_core_item *item = pdata->items;
struct mlxreg_core_data *data;
u32 regval;
u8 freq;
int err;
if (!item)
return 0;
/* Read frequency setting. */
data = item->data;
err = regmap_read(pdata->regmap, data->reg, &regval);
if (err)
return err;
/* Set frequency only if it is not 100KHz, which is default. */
switch ((data->reg & data->mask) >> data->bit) {
case MLXCPLD_I2C_FREQ_1000KHZ:
freq = MLXCPLD_I2C_FREQ_1000KHZ_SET;
break;
case MLXCPLD_I2C_FREQ_400KHZ:
freq = MLXCPLD_I2C_FREQ_400KHZ_SET;
break;
default:
return 0;
}
mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_HALF_CYC_REG, &freq, 1);
return 0;
}
static int mlxcpld_i2c_probe(struct platform_device *pdev)
{
struct mlxreg_core_hotplug_platform_data *pdata;
struct mlxcpld_i2c_priv *priv;
int err;
u8 val;
@ -505,6 +528,14 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
/* Set I2C bus frequency if platform data provides this info. */
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
err = mlxcpld_i2c_set_frequency(priv, pdata);
if (err)
goto mlxcpld_i2_probe_failed;
}
/* Register with i2c layer */
mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
/* Read capability register */
@ -523,8 +554,12 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
err = i2c_add_numbered_adapter(&priv->adap);
if (err)
mutex_destroy(&priv->lock);
goto mlxcpld_i2_probe_failed;
return 0;
mlxcpld_i2_probe_failed:
mutex_destroy(&priv->lock);
return err;
}

View File

@ -18,6 +18,7 @@
#include <linux/mv643xx_i2c.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/io.h>
#include <linux/of.h>
@ -717,6 +718,10 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
int rc, ret = num;
rc = pm_runtime_resume_and_get(&adap->dev);
if (rc)
return rc;
BUG_ON(drv_data->msgs != NULL);
drv_data->msgs = msgs;
drv_data->num_msgs = num;
@ -732,6 +737,9 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
drv_data->num_msgs = 0;
drv_data->msgs = NULL;
pm_runtime_mark_last_busy(&adap->dev);
pm_runtime_put_autosuspend(&adap->dev);
return ret;
}
@ -805,7 +813,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
* need to know tclk in order to calculate bus clock
* factors.
*/
if (IS_ERR(drv_data->clk)) {
if (!drv_data->clk) {
rc = -ENODEV;
goto out;
}
@ -828,7 +836,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
rc = PTR_ERR(drv_data->rstc);
goto out;
}
reset_control_deassert(drv_data->rstc);
/* Its not yet defined how timeouts will be specified in device tree.
* So hard code the value to 1 second.
@ -893,6 +900,32 @@ static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
return 0;
}
static int
mv64xxx_i2c_runtime_suspend(struct device *dev)
{
struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev);
reset_control_assert(drv_data->rstc);
clk_disable_unprepare(drv_data->reg_clk);
clk_disable_unprepare(drv_data->clk);
return 0;
}
static int
mv64xxx_i2c_runtime_resume(struct device *dev)
{
struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev);
clk_prepare_enable(drv_data->clk);
clk_prepare_enable(drv_data->reg_clk);
reset_control_reset(drv_data->rstc);
mv64xxx_i2c_hw_init(drv_data);
return 0;
}
static int
mv64xxx_i2c_probe(struct platform_device *pd)
{
@ -920,18 +953,22 @@ mv64xxx_i2c_probe(struct platform_device *pd)
/* Not all platforms have clocks */
drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->clk))
clk_prepare_enable(drv_data->clk);
if (IS_ERR(drv_data->clk)) {
if (PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
drv_data->clk = NULL;
}
drv_data->reg_clk = devm_clk_get(&pd->dev, "reg");
if (PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->reg_clk))
clk_prepare_enable(drv_data->reg_clk);
if (IS_ERR(drv_data->reg_clk)) {
if (PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
drv_data->reg_clk = NULL;
}
drv_data->irq = platform_get_irq(pd, 0);
if (drv_data->irq < 0)
return drv_data->irq;
if (pdata) {
drv_data->freq_m = pdata->freq_m;
@ -942,16 +979,12 @@ mv64xxx_i2c_probe(struct platform_device *pd)
} else if (pd->dev.of_node) {
rc = mv64xxx_of_config(drv_data, &pd->dev);
if (rc)
goto exit_clk;
}
if (drv_data->irq < 0) {
rc = drv_data->irq;
goto exit_reset;
return rc;
}
rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
if (rc == -EPROBE_DEFER)
goto exit_reset;
return rc;
drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
@ -962,7 +995,14 @@ mv64xxx_i2c_probe(struct platform_device *pd)
platform_set_drvdata(pd, drv_data);
i2c_set_adapdata(&drv_data->adapter, drv_data);
mv64xxx_i2c_hw_init(drv_data);
pm_runtime_set_autosuspend_delay(&pd->dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(&pd->dev);
pm_runtime_enable(&pd->dev);
if (!pm_runtime_enabled(&pd->dev)) {
rc = mv64xxx_i2c_runtime_resume(&pd->dev);
if (rc)
goto exit_disable_pm;
}
rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
MV64XXX_I2C_CTLR_NAME, drv_data);
@ -970,7 +1010,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't register intr handler irq%d: %d\n",
drv_data->irq, rc);
goto exit_reset;
goto exit_disable_pm;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
@ -981,54 +1021,50 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_free_irq:
free_irq(drv_data->irq, drv_data);
exit_reset:
reset_control_assert(drv_data->rstc);
exit_clk:
clk_disable_unprepare(drv_data->reg_clk);
clk_disable_unprepare(drv_data->clk);
exit_disable_pm:
pm_runtime_disable(&pd->dev);
if (!pm_runtime_status_suspended(&pd->dev))
mv64xxx_i2c_runtime_suspend(&pd->dev);
return rc;
}
static int
mv64xxx_i2c_remove(struct platform_device *dev)
mv64xxx_i2c_remove(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(dev);
struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(pd);
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
reset_control_assert(drv_data->rstc);
clk_disable_unprepare(drv_data->reg_clk);
clk_disable_unprepare(drv_data->clk);
pm_runtime_disable(&pd->dev);
if (!pm_runtime_status_suspended(&pd->dev))
mv64xxx_i2c_runtime_suspend(&pd->dev);
return 0;
}
#ifdef CONFIG_PM
static int mv64xxx_i2c_resume(struct device *dev)
static void
mv64xxx_i2c_shutdown(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data = dev_get_drvdata(dev);
mv64xxx_i2c_hw_init(drv_data);
return 0;
pm_runtime_disable(&pd->dev);
if (!pm_runtime_status_suspended(&pd->dev))
mv64xxx_i2c_runtime_suspend(&pd->dev);
}
static const struct dev_pm_ops mv64xxx_i2c_pm = {
.resume = mv64xxx_i2c_resume,
static const struct dev_pm_ops mv64xxx_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend,
mv64xxx_i2c_runtime_resume, NULL)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
#define mv64xxx_i2c_pm_ops (&mv64xxx_i2c_pm)
#else
#define mv64xxx_i2c_pm_ops NULL
#endif
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove = mv64xxx_i2c_remove,
.shutdown = mv64xxx_i2c_shutdown,
.driver = {
.name = MV64XXX_I2C_CTLR_NAME,
.pm = mv64xxx_i2c_pm_ops,
.pm = &mv64xxx_i2c_pm_ops,
.of_match_table = mv64xxx_i2c_of_match_table,
},
};

View File

@ -86,6 +86,9 @@ struct geni_i2c_dev {
u32 clk_freq_out;
const struct geni_i2c_clk_fld *clk_fld;
int suspended;
void *dma_buf;
size_t xfer_len;
dma_addr_t dma_addr;
};
struct geni_i2c_err_log {
@ -348,14 +351,65 @@ static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
}
static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c,
struct i2c_msg *cur)
{
gi2c->cur_rd = 0;
if (gi2c->dma_buf) {
if (gi2c->err)
geni_i2c_rx_fsm_rst(gi2c);
geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
}
}
static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
struct i2c_msg *cur)
{
gi2c->cur_wr = 0;
if (gi2c->dma_buf) {
if (gi2c->err)
geni_i2c_tx_fsm_rst(gi2c);
geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
}
}
static void geni_i2c_stop_xfer(struct geni_i2c_dev *gi2c)
{
int ret;
u32 geni_status;
struct i2c_msg *cur;
/* Resume device, as runtime suspend can happen anytime during transfer */
ret = pm_runtime_get_sync(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "Failed to resume device: %d\n", ret);
return;
}
geni_status = readl_relaxed(gi2c->se.base + SE_GENI_STATUS);
if (geni_status & M_GENI_CMD_ACTIVE) {
cur = gi2c->cur;
geni_i2c_abort_xfer(gi2c);
if (cur->flags & I2C_M_RD)
geni_i2c_rx_msg_cleanup(gi2c, cur);
else
geni_i2c_tx_msg_cleanup(gi2c, cur);
}
pm_runtime_put_sync_suspend(gi2c->se.dev);
}
static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
dma_addr_t rx_dma;
dma_addr_t rx_dma = 0;
unsigned long time_left;
void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
struct i2c_msg *cur;
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
@ -370,19 +424,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_se_select_mode(se, GENI_SE_FIFO);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
dma_buf = NULL;
} else {
gi2c->xfer_len = len;
gi2c->dma_addr = rx_dma;
gi2c->dma_buf = dma_buf;
}
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
gi2c->cur_rd = 0;
if (dma_buf) {
if (gi2c->err)
geni_i2c_rx_fsm_rst(gi2c);
geni_se_rx_dma_unprep(se, rx_dma, len);
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
}
geni_i2c_rx_msg_cleanup(gi2c, cur);
return gi2c->err;
}
@ -390,11 +443,12 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
dma_addr_t tx_dma;
dma_addr_t tx_dma = 0;
unsigned long time_left;
void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
struct i2c_msg *cur;
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
@ -409,22 +463,21 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_se_select_mode(se, GENI_SE_FIFO);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
dma_buf = NULL;
} else {
gi2c->xfer_len = len;
gi2c->dma_addr = tx_dma;
gi2c->dma_buf = dma_buf;
}
if (!dma_buf) /* Get FIFO IRQ */
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
gi2c->cur_wr = 0;
if (dma_buf) {
if (gi2c->err)
geni_i2c_tx_fsm_rst(gi2c);
geni_se_tx_dma_unprep(se, tx_dma, len);
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
}
geni_i2c_tx_msg_cleanup(gi2c, cur);
return gi2c->err;
}
@ -623,6 +676,13 @@ static int geni_i2c_remove(struct platform_device *pdev)
return 0;
}
static void geni_i2c_shutdown(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
geni_i2c_stop_xfer(gi2c);
}
static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
{
int ret;
@ -687,6 +747,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
static struct platform_driver geni_i2c_driver = {
.probe = geni_i2c_probe,
.remove = geni_i2c_remove,
.shutdown = geni_i2c_shutdown,
.driver = {
.name = "geni_i2c",
.pm = &geni_i2c_pm_ops,

View File

@ -1603,7 +1603,7 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
static u32 qup_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL_ALL & ~I2C_FUNC_SMBUS_QUICK);
}
static const struct i2c_algorithm qup_i2c_algo = {

View File

@ -91,7 +91,6 @@
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF)
#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
@ -120,6 +119,7 @@ enum rcar_i2c_type {
};
struct rcar_i2c_priv {
u32 flags;
void __iomem *io;
struct i2c_adapter adap;
struct i2c_msg *msg;
@ -130,7 +130,6 @@ struct rcar_i2c_priv {
int pos;
u32 icccr;
u32 flags;
u8 recovery_icmcr; /* protected by adapter lock */
enum rcar_i2c_type devtype;
struct i2c_client *slave;
@ -621,27 +620,16 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
/*
* This driver has a lock-free design because there are IP cores (at least
* R-Car Gen2) which have an inherent race condition in their hardware design.
* There, we need to clear RCAR_BUS_MASK_DATA bits as soon as possible after
* There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after
* the interrupt was generated, otherwise an unwanted repeated message gets
* generated. It turned out that taking a spinlock at the beginning of the ISR
* was already causing repeated messages. Thus, this driver was converted to
* the now lockless behaviour. Please keep this in mind when hacking the driver.
* R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are
* likely affected. Therefore, we have different interrupt handler entries.
*/
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
{
struct rcar_i2c_priv *priv = ptr;
u32 msr, val;
/* Clear START or STOP immediately, except for REPSTART after read */
if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) {
val = rcar_i2c_read(priv, ICMCR);
rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
}
msr = rcar_i2c_read(priv, ICMSR);
/* Only handle interrupts that are currently enabled */
msr &= rcar_i2c_read(priv, ICMIER);
if (!msr) {
if (rcar_i2c_slave_irq(priv))
return IRQ_HANDLED;
@ -685,6 +673,41 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
return IRQ_HANDLED;
}
static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr)
{
struct rcar_i2c_priv *priv = ptr;
u32 msr;
/* Clear START or STOP immediately, except for REPSTART after read */
if (likely(!(priv->flags & ID_P_REP_AFTER_RD)))
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR);
msr &= rcar_i2c_read(priv, ICMIER);
return rcar_i2c_irq(irq, priv, msr);
}
static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr)
{
struct rcar_i2c_priv *priv = ptr;
u32 msr;
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR);
msr &= rcar_i2c_read(priv, ICMIER);
/*
* Clear START or STOP immediately, except for REPSTART after read or
* if a spurious interrupt was detected.
*/
if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr))
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
return rcar_i2c_irq(irq, priv, msr);
}
static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
enum dma_transfer_direction dir,
dma_addr_t port_addr)
@ -931,6 +954,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
struct rcar_i2c_priv *priv;
struct i2c_adapter *adap;
struct device *dev = &pdev->dev;
unsigned long irqflags = 0;
irqreturn_t (*irqhandler)(int irq, void *ptr) = rcar_i2c_gen3_irq;
int ret;
/* Otherwise logic will break because some bytes must always use PIO */
@ -979,6 +1004,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
if (priv->devtype < I2C_RCAR_GEN3) {
irqflags |= IRQF_NO_THREAD;
irqhandler = rcar_i2c_gen2_irq;
}
if (priv->devtype == I2C_RCAR_GEN3) {
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(priv->rstc)) {
@ -998,7 +1028,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
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);
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv);
if (ret < 0) {
dev_err(dev, "cannot get irq %d\n", priv->irq);
goto out_pm_disable;

View File

@ -781,7 +781,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
/* declare our i2c functionality */
static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART |
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL_ALL | I2C_FUNC_NOSTART |
I2C_FUNC_PROTOCOL_MANGLING;
}

View File

@ -1,475 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* I2C bus driver for CSR SiRFprimaII
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#define SIRFSOC_I2C_CLK_CTRL 0x00
#define SIRFSOC_I2C_STATUS 0x0C
#define SIRFSOC_I2C_CTRL 0x10
#define SIRFSOC_I2C_IO_CTRL 0x14
#define SIRFSOC_I2C_SDA_DELAY 0x18
#define SIRFSOC_I2C_CMD_START 0x1C
#define SIRFSOC_I2C_CMD_BUF 0x30
#define SIRFSOC_I2C_DATA_BUF 0x80
#define SIRFSOC_I2C_CMD_BUF_MAX 16
#define SIRFSOC_I2C_DATA_BUF_MAX 16
#define SIRFSOC_I2C_CMD(x) (SIRFSOC_I2C_CMD_BUF + (x)*0x04)
#define SIRFSOC_I2C_DATA_MASK(x) (0xFF<<(((x)&3)*8))
#define SIRFSOC_I2C_DATA_SHIFT(x) (((x)&3)*8)
#define SIRFSOC_I2C_DIV_MASK (0xFFFF)
/* I2C status flags */
#define SIRFSOC_I2C_STAT_BUSY BIT(0)
#define SIRFSOC_I2C_STAT_TIP BIT(1)
#define SIRFSOC_I2C_STAT_NACK BIT(2)
#define SIRFSOC_I2C_STAT_TR_INT BIT(4)
#define SIRFSOC_I2C_STAT_STOP BIT(6)
#define SIRFSOC_I2C_STAT_CMD_DONE BIT(8)
#define SIRFSOC_I2C_STAT_ERR BIT(9)
#define SIRFSOC_I2C_CMD_INDEX (0x1F<<16)
/* I2C control flags */
#define SIRFSOC_I2C_RESET BIT(0)
#define SIRFSOC_I2C_CORE_EN BIT(1)
#define SIRFSOC_I2C_MASTER_MODE BIT(2)
#define SIRFSOC_I2C_CMD_DONE_EN BIT(11)
#define SIRFSOC_I2C_ERR_INT_EN BIT(12)
#define SIRFSOC_I2C_SDA_DELAY_MASK (0xFF)
#define SIRFSOC_I2C_SCLF_FILTER (3<<8)
#define SIRFSOC_I2C_START_CMD BIT(0)
#define SIRFSOC_I2C_CMD_RP(x) ((x)&0x7)
#define SIRFSOC_I2C_NACK BIT(3)
#define SIRFSOC_I2C_WRITE BIT(4)
#define SIRFSOC_I2C_READ BIT(5)
#define SIRFSOC_I2C_STOP BIT(6)
#define SIRFSOC_I2C_START BIT(7)
#define SIRFSOC_I2C_ERR_NOACK 1
#define SIRFSOC_I2C_ERR_TIMEOUT 2
struct sirfsoc_i2c {
void __iomem *base;
struct clk *clk;
u32 cmd_ptr; /* Current position in CMD buffer */
u8 *buf; /* Buffer passed by user */
u32 msg_len; /* Message length */
u32 finished_len; /* number of bytes read/written */
u32 read_cmd_len; /* number of read cmd sent */
int msg_read; /* 1 indicates a read message */
int err_status; /* 1 indicates an error on bus */
u32 sda_delay; /* For suspend/resume */
u32 clk_div;
int last; /* Last message in transfer, STOP cmd can be sent */
struct completion done; /* indicates completion of message transfer */
struct i2c_adapter adapter;
};
static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
{
u32 data = 0;
int i;
for (i = 0; i < siic->read_cmd_len; i++) {
if (!(i & 0x3))
data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
siic->buf[siic->finished_len++] =
(u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
SIRFSOC_I2C_DATA_SHIFT(i));
}
}
static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
{
u32 regval;
int i = 0;
if (siic->msg_read) {
while (((siic->finished_len + i) < siic->msg_len)
&& (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
if (((siic->finished_len + i) ==
(siic->msg_len - 1)) && siic->last)
regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
writel(regval,
siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
i++;
}
siic->read_cmd_len = i;
} else {
while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
&& (siic->finished_len < siic->msg_len)) {
regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
if ((siic->finished_len == (siic->msg_len - 1))
&& siic->last)
regval |= SIRFSOC_I2C_STOP;
writel(regval,
siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
writel(siic->buf[siic->finished_len++],
siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
}
}
siic->cmd_ptr = 0;
/* Trigger the transfer */
writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
}
static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
{
struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
/* Error conditions */
siic->err_status = SIRFSOC_I2C_ERR_NOACK;
writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
dev_dbg(&siic->adapter.dev, "ACK not received\n");
else
dev_err(&siic->adapter.dev, "I2C error\n");
/*
* Due to hardware ANOMALY, we need to reset I2C earlier after
* we get NOACK while accessing non-existing clients, otherwise
* we will get errors even we access existing clients later
*/
writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
complete(&siic->done);
} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
/* CMD buffer execution complete */
if (siic->msg_read)
i2c_sirfsoc_read_data(siic);
if (siic->finished_len == siic->msg_len)
complete(&siic->done);
else /* Fill a new CMD buffer for left data */
i2c_sirfsoc_queue_cmd(siic);
writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
}
return IRQ_HANDLED;
}
static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
struct i2c_msg *msg)
{
unsigned char addr;
u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
/* no data and last message -> add STOP */
if (siic->last && (msg->len == 0))
regval |= SIRFSOC_I2C_STOP;
writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
addr = i2c_8bit_addr_from_msg(msg);
/* Reverse direction bit */
if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
}
static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
{
u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
/* timeout waiting for the xfer to finish or fail */
int timeout = msecs_to_jiffies((msg->len + 1) * 50);
i2c_sirfsoc_set_address(siic, msg);
writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
siic->base + SIRFSOC_I2C_CTRL);
i2c_sirfsoc_queue_cmd(siic);
if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
dev_err(&siic->adapter.dev, "Transfer timeout\n");
}
writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
siic->base + SIRFSOC_I2C_CTRL);
writel(0, siic->base + SIRFSOC_I2C_CMD_START);
/* i2c control doesn't response, reset it */
if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
}
return siic->err_status ? -EAGAIN : 0;
}
static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct sirfsoc_i2c *siic = adap->algo_data;
int i, ret;
clk_enable(siic->clk);
for (i = 0; i < num; i++) {
siic->buf = msgs[i].buf;
siic->msg_len = msgs[i].len;
siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
siic->err_status = 0;
siic->cmd_ptr = 0;
siic->finished_len = 0;
siic->last = (i == (num - 1));
ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
if (ret) {
clk_disable(siic->clk);
return ret;
}
}
clk_disable(siic->clk);
return num;
}
/* I2C algorithms associated with this master controller driver */
static const struct i2c_algorithm i2c_sirfsoc_algo = {
.master_xfer = i2c_sirfsoc_xfer,
.functionality = i2c_sirfsoc_func,
};
static int i2c_sirfsoc_probe(struct platform_device *pdev)
{
struct sirfsoc_i2c *siic;
struct i2c_adapter *adap;
struct clk *clk;
int bitrate;
int ctrl_speed;
int irq;
int err;
u32 regval;
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
err = PTR_ERR(clk);
dev_err(&pdev->dev, "Clock get failed\n");
goto err_get_clk;
}
err = clk_prepare(clk);
if (err) {
dev_err(&pdev->dev, "Clock prepare failed\n");
goto err_clk_prep;
}
err = clk_enable(clk);
if (err) {
dev_err(&pdev->dev, "Clock enable failed\n");
goto err_clk_en;
}
ctrl_speed = clk_get_rate(clk);
siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
if (!siic) {
err = -ENOMEM;
goto out;
}
adap = &siic->adapter;
adap->class = I2C_CLASS_DEPRECATED;
siic->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(siic->base)) {
err = PTR_ERR(siic->base);
goto out;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
err = irq;
goto out;
}
err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
dev_name(&pdev->dev), siic);
if (err)
goto out;
adap->algo = &i2c_sirfsoc_algo;
adap->algo_data = siic;
adap->retries = 3;
adap->dev.of_node = pdev->dev.of_node;
adap->dev.parent = &pdev->dev;
adap->nr = pdev->id;
strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
platform_set_drvdata(pdev, adap);
init_completion(&siic->done);
/* Controller initialisation */
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
siic->base + SIRFSOC_I2C_CTRL);
siic->clk = clk;
err = of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &bitrate);
if (err < 0)
bitrate = I2C_MAX_STANDARD_MODE_FREQ;
/*
* Due to some hardware design issues, we need to tune the formula.
* Since i2c is open drain interface that allows the slave to
* stall the transaction by holding the SCL line at '0', the RTL
* implementation is waiting for SCL feedback from the pin after
* setting it to High-Z ('1'). This wait adds to the high-time
* interval counter few cycles of the input synchronization
* (depending on the SCL_FILTER_REG field), and also the time it
* takes for the board pull-up resistor to rise the SCL line.
* For slow SCL settings these additions are negligible,
* but they start to affect the speed when clock is set to faster
* frequencies.
* Through the actual tests, use the different user_div value(which
* in the divider formula 'Fio / (Fi2c * user_div)') to adapt
* the different ranges of i2c bus clock frequency, to make the SCL
* more accurate.
*/
if (bitrate <= 30000)
regval = ctrl_speed / (bitrate * 5);
else if (bitrate > 30000 && bitrate <= 280000)
regval = (2 * ctrl_speed) / (bitrate * 11);
else
regval = ctrl_speed / (bitrate * 6);
writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
if (regval > 0xFF)
writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
else
writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
err = i2c_add_numbered_adapter(adap);
if (err < 0)
goto out;
clk_disable(clk);
dev_info(&pdev->dev, " I2C adapter ready to operate\n");
return 0;
out:
clk_disable(clk);
err_clk_en:
clk_unprepare(clk);
err_clk_prep:
clk_put(clk);
err_get_clk:
return err;
}
static int i2c_sirfsoc_remove(struct platform_device *pdev)
{
struct i2c_adapter *adapter = platform_get_drvdata(pdev);
struct sirfsoc_i2c *siic = adapter->algo_data;
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
i2c_del_adapter(adapter);
clk_unprepare(siic->clk);
clk_put(siic->clk);
return 0;
}
#ifdef CONFIG_PM
static int i2c_sirfsoc_suspend(struct device *dev)
{
struct i2c_adapter *adapter = dev_get_drvdata(dev);
struct sirfsoc_i2c *siic = adapter->algo_data;
clk_enable(siic->clk);
siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
clk_disable(siic->clk);
return 0;
}
static int i2c_sirfsoc_resume(struct device *dev)
{
struct i2c_adapter *adapter = dev_get_drvdata(dev);
struct sirfsoc_i2c *siic = adapter->algo_data;
clk_enable(siic->clk);
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
siic->base + SIRFSOC_I2C_CTRL);
writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
clk_disable(siic->clk);
return 0;
}
static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
.suspend = i2c_sirfsoc_suspend,
.resume = i2c_sirfsoc_resume,
};
#endif
static const struct of_device_id sirfsoc_i2c_of_match[] = {
{ .compatible = "sirf,prima2-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
static struct platform_driver i2c_sirfsoc_driver = {
.driver = {
.name = "sirfsoc_i2c",
#ifdef CONFIG_PM
.pm = &i2c_sirfsoc_pm_ops,
#endif
.of_match_table = sirfsoc_i2c_of_match,
},
.probe = i2c_sirfsoc_probe,
.remove = i2c_sirfsoc_remove,
};
module_platform_driver(i2c_sirfsoc_driver);
MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>");
MODULE_AUTHOR("Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
MODULE_LICENSE("GPL v2");

View File

@ -2035,12 +2035,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
}
irq_error = platform_get_irq(pdev, 1);
if (irq_error <= 0) {
if (irq_error != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get IRQ error: %d\n",
irq_error);
if (irq_error <= 0)
return irq_error ? : -ENOENT;
}
i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node,
"wakeup-source");

File diff suppressed because it is too large Load Diff

View File

@ -550,7 +550,7 @@ static int tegra_i2c_poll_register(struct tegra_i2c_dev *i2c_dev,
void __iomem *addr = i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg);
u32 val;
if (!i2c_dev->atomic_mode && !in_irq())
if (!i2c_dev->atomic_mode)
return readl_relaxed_poll_timeout(addr, val, !(val & mask),
delay_us, timeout_us);
@ -1739,9 +1739,10 @@ static int tegra_i2c_probe(struct platform_device *pdev)
/* interrupt will be enabled during of transfer time */
irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
err = devm_request_irq(i2c_dev->dev, i2c_dev->irq, tegra_i2c_isr,
IRQF_NO_SUSPEND, dev_name(i2c_dev->dev),
i2c_dev);
err = devm_request_threaded_irq(i2c_dev->dev, i2c_dev->irq,
NULL, tegra_i2c_isr,
IRQF_NO_SUSPEND | IRQF_ONESHOT,
dev_name(i2c_dev->dev), i2c_dev);
if (err)
return err;

View File

@ -1,602 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Sanechips Technology Co., Ltd.
* Copyright 2017 Linaro Ltd.
*
* Author: Baoyou Xie <baoyou.xie@linaro.org>
*/
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define REG_CMD 0x04
#define REG_DEVADDR_H 0x0C
#define REG_DEVADDR_L 0x10
#define REG_CLK_DIV_FS 0x14
#define REG_CLK_DIV_HS 0x18
#define REG_WRCONF 0x1C
#define REG_RDCONF 0x20
#define REG_DATA 0x24
#define REG_STAT 0x28
#define I2C_STOP 0
#define I2C_MASTER BIT(0)
#define I2C_ADDR_MODE_TEN BIT(1)
#define I2C_IRQ_MSK_ENABLE BIT(3)
#define I2C_RW_READ BIT(4)
#define I2C_CMB_RW_EN BIT(5)
#define I2C_START BIT(6)
#define I2C_ADDR_LOW_MASK GENMASK(6, 0)
#define I2C_ADDR_LOW_SHIFT 0
#define I2C_ADDR_HI_MASK GENMASK(2, 0)
#define I2C_ADDR_HI_SHIFT 7
#define I2C_WFIFO_RESET BIT(7)
#define I2C_RFIFO_RESET BIT(7)
#define I2C_IRQ_ACK_CLEAR BIT(7)
#define I2C_INT_MASK GENMASK(6, 0)
#define I2C_TRANS_DONE BIT(0)
#define I2C_SR_EDEVICE BIT(1)
#define I2C_SR_EDATA BIT(2)
#define I2C_FIFO_MAX 16
#define I2C_TIMEOUT msecs_to_jiffies(1000)
#define DEV(i2c) ((i2c)->adap.dev.parent)
struct zx2967_i2c {
struct i2c_adapter adap;
struct clk *clk;
struct completion complete;
u32 clk_freq;
void __iomem *reg_base;
size_t residue;
int irq;
int msg_rd;
u8 *cur_trans;
u8 access_cnt;
int error;
};
static void zx2967_i2c_writel(struct zx2967_i2c *i2c,
u32 val, unsigned long reg)
{
writel_relaxed(val, i2c->reg_base + reg);
}
static u32 zx2967_i2c_readl(struct zx2967_i2c *i2c, unsigned long reg)
{
return readl_relaxed(i2c->reg_base + reg);
}
static void zx2967_i2c_writesb(struct zx2967_i2c *i2c,
void *data, unsigned long reg, int len)
{
writesb(i2c->reg_base + reg, data, len);
}
static void zx2967_i2c_readsb(struct zx2967_i2c *i2c,
void *data, unsigned long reg, int len)
{
readsb(i2c->reg_base + reg, data, len);
}
static void zx2967_i2c_start_ctrl(struct zx2967_i2c *i2c)
{
u32 status;
u32 ctl;
status = zx2967_i2c_readl(i2c, REG_STAT);
status |= I2C_IRQ_ACK_CLEAR;
zx2967_i2c_writel(i2c, status, REG_STAT);
ctl = zx2967_i2c_readl(i2c, REG_CMD);
if (i2c->msg_rd)
ctl |= I2C_RW_READ;
else
ctl &= ~I2C_RW_READ;
ctl &= ~I2C_CMB_RW_EN;
ctl |= I2C_START;
zx2967_i2c_writel(i2c, ctl, REG_CMD);
}
static void zx2967_i2c_flush_fifos(struct zx2967_i2c *i2c)
{
u32 offset;
u32 val;
if (i2c->msg_rd) {
offset = REG_RDCONF;
val = I2C_RFIFO_RESET;
} else {
offset = REG_WRCONF;
val = I2C_WFIFO_RESET;
}
val |= zx2967_i2c_readl(i2c, offset);
zx2967_i2c_writel(i2c, val, offset);
}
static int zx2967_i2c_empty_rx_fifo(struct zx2967_i2c *i2c, u32 size)
{
u8 val[I2C_FIFO_MAX] = {0};
int i;
if (size > I2C_FIFO_MAX) {
dev_err(DEV(i2c), "fifo size %d over the max value %d\n",
size, I2C_FIFO_MAX);
return -EINVAL;
}
zx2967_i2c_readsb(i2c, val, REG_DATA, size);
for (i = 0; i < size; i++) {
*i2c->cur_trans++ = val[i];
i2c->residue--;
}
barrier();
return 0;
}
static int zx2967_i2c_fill_tx_fifo(struct zx2967_i2c *i2c)
{
size_t residue = i2c->residue;
u8 *buf = i2c->cur_trans;
if (residue == 0) {
dev_err(DEV(i2c), "residue is %d\n", (int)residue);
return -EINVAL;
}
if (residue <= I2C_FIFO_MAX) {
zx2967_i2c_writesb(i2c, buf, REG_DATA, residue);
/* Again update before writing to FIFO to make sure isr sees. */
i2c->residue = 0;
i2c->cur_trans = NULL;
} else {
zx2967_i2c_writesb(i2c, buf, REG_DATA, I2C_FIFO_MAX);
i2c->residue -= I2C_FIFO_MAX;
i2c->cur_trans += I2C_FIFO_MAX;
}
barrier();
return 0;
}
static int zx2967_i2c_reset_hardware(struct zx2967_i2c *i2c)
{
u32 val;
u32 clk_div;
val = I2C_MASTER | I2C_IRQ_MSK_ENABLE;
zx2967_i2c_writel(i2c, val, REG_CMD);
clk_div = clk_get_rate(i2c->clk) / i2c->clk_freq - 1;
zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_FS);
zx2967_i2c_writel(i2c, clk_div, REG_CLK_DIV_HS);
zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_WRCONF);
zx2967_i2c_writel(i2c, I2C_FIFO_MAX - 1, REG_RDCONF);
zx2967_i2c_writel(i2c, 1, REG_RDCONF);
zx2967_i2c_flush_fifos(i2c);
return 0;
}
static void zx2967_i2c_isr_clr(struct zx2967_i2c *i2c)
{
u32 status;
status = zx2967_i2c_readl(i2c, REG_STAT);
status |= I2C_IRQ_ACK_CLEAR;
zx2967_i2c_writel(i2c, status, REG_STAT);
}
static irqreturn_t zx2967_i2c_isr(int irq, void *dev_id)
{
u32 status;
struct zx2967_i2c *i2c = (struct zx2967_i2c *)dev_id;
status = zx2967_i2c_readl(i2c, REG_STAT) & I2C_INT_MASK;
zx2967_i2c_isr_clr(i2c);
if (status & I2C_SR_EDEVICE)
i2c->error = -ENXIO;
else if (status & I2C_SR_EDATA)
i2c->error = -EIO;
else if (status & I2C_TRANS_DONE)
i2c->error = 0;
else
goto done;
complete(&i2c->complete);
done:
return IRQ_HANDLED;
}
static void zx2967_set_addr(struct zx2967_i2c *i2c, u16 addr)
{
u16 val;
val = (addr >> I2C_ADDR_LOW_SHIFT) & I2C_ADDR_LOW_MASK;
zx2967_i2c_writel(i2c, val, REG_DEVADDR_L);
val = (addr >> I2C_ADDR_HI_SHIFT) & I2C_ADDR_HI_MASK;
zx2967_i2c_writel(i2c, val, REG_DEVADDR_H);
if (val)
val = zx2967_i2c_readl(i2c, REG_CMD) | I2C_ADDR_MODE_TEN;
else
val = zx2967_i2c_readl(i2c, REG_CMD) & ~I2C_ADDR_MODE_TEN;
zx2967_i2c_writel(i2c, val, REG_CMD);
}
static int zx2967_i2c_xfer_bytes(struct zx2967_i2c *i2c, u32 bytes)
{
unsigned long time_left;
int rd = i2c->msg_rd;
int ret;
reinit_completion(&i2c->complete);
if (rd) {
zx2967_i2c_writel(i2c, bytes - 1, REG_RDCONF);
} else {
ret = zx2967_i2c_fill_tx_fifo(i2c);
if (ret)
return ret;
}
zx2967_i2c_start_ctrl(i2c);
time_left = wait_for_completion_timeout(&i2c->complete,
I2C_TIMEOUT);
if (time_left == 0)
return -ETIMEDOUT;
if (i2c->error)
return i2c->error;
return rd ? zx2967_i2c_empty_rx_fifo(i2c, bytes) : 0;
}
static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c,
struct i2c_msg *msg)
{
int ret;
int i;
zx2967_i2c_flush_fifos(i2c);
i2c->cur_trans = msg->buf;
i2c->residue = msg->len;
i2c->access_cnt = msg->len / I2C_FIFO_MAX;
i2c->msg_rd = msg->flags & I2C_M_RD;
for (i = 0; i < i2c->access_cnt; i++) {
ret = zx2967_i2c_xfer_bytes(i2c, I2C_FIFO_MAX);
if (ret)
return ret;
}
if (i2c->residue > 0) {
ret = zx2967_i2c_xfer_bytes(i2c, i2c->residue);
if (ret)
return ret;
}
i2c->residue = 0;
i2c->access_cnt = 0;
return 0;
}
static int zx2967_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct zx2967_i2c *i2c = i2c_get_adapdata(adap);
int ret;
int i;
zx2967_set_addr(i2c, msgs->addr);
for (i = 0; i < num; i++) {
ret = zx2967_i2c_xfer_msg(i2c, &msgs[i]);
if (ret)
return ret;
}
return num;
}
static void
zx2967_smbus_xfer_prepare(struct zx2967_i2c *i2c, u16 addr,
char read_write, u8 command, int size,
union i2c_smbus_data *data)
{
u32 val;
val = zx2967_i2c_readl(i2c, REG_RDCONF);
val |= I2C_RFIFO_RESET;
zx2967_i2c_writel(i2c, val, REG_RDCONF);
zx2967_set_addr(i2c, addr);
val = zx2967_i2c_readl(i2c, REG_CMD);
val &= ~I2C_RW_READ;
zx2967_i2c_writel(i2c, val, REG_CMD);
switch (size) {
case I2C_SMBUS_BYTE:
zx2967_i2c_writel(i2c, command, REG_DATA);
break;
case I2C_SMBUS_BYTE_DATA:
zx2967_i2c_writel(i2c, command, REG_DATA);
if (read_write == I2C_SMBUS_WRITE)
zx2967_i2c_writel(i2c, data->byte, REG_DATA);
break;
case I2C_SMBUS_WORD_DATA:
zx2967_i2c_writel(i2c, command, REG_DATA);
if (read_write == I2C_SMBUS_WRITE) {
zx2967_i2c_writel(i2c, (data->word >> 8), REG_DATA);
zx2967_i2c_writel(i2c, (data->word & 0xff),
REG_DATA);
}
break;
}
}
static int zx2967_smbus_xfer_read(struct zx2967_i2c *i2c, int size,
union i2c_smbus_data *data)
{
unsigned long time_left;
u8 buf[2];
u32 val;
reinit_completion(&i2c->complete);
val = zx2967_i2c_readl(i2c, REG_CMD);
val |= I2C_CMB_RW_EN;
zx2967_i2c_writel(i2c, val, REG_CMD);
val = zx2967_i2c_readl(i2c, REG_CMD);
val |= I2C_START;
zx2967_i2c_writel(i2c, val, REG_CMD);
time_left = wait_for_completion_timeout(&i2c->complete,
I2C_TIMEOUT);
if (time_left == 0)
return -ETIMEDOUT;
if (i2c->error)
return i2c->error;
switch (size) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
val = zx2967_i2c_readl(i2c, REG_DATA);
data->byte = val;
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
buf[0] = zx2967_i2c_readl(i2c, REG_DATA);
buf[1] = zx2967_i2c_readl(i2c, REG_DATA);
data->word = (buf[0] << 8) | buf[1];
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int zx2967_smbus_xfer_write(struct zx2967_i2c *i2c)
{
unsigned long time_left;
u32 val;
reinit_completion(&i2c->complete);
val = zx2967_i2c_readl(i2c, REG_CMD);
val |= I2C_START;
zx2967_i2c_writel(i2c, val, REG_CMD);
time_left = wait_for_completion_timeout(&i2c->complete,
I2C_TIMEOUT);
if (time_left == 0)
return -ETIMEDOUT;
if (i2c->error)
return i2c->error;
return 0;
}
static int zx2967_smbus_xfer(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{
struct zx2967_i2c *i2c = i2c_get_adapdata(adap);
if (size == I2C_SMBUS_QUICK)
read_write = I2C_SMBUS_WRITE;
switch (size) {
case I2C_SMBUS_QUICK:
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
case I2C_SMBUS_WORD_DATA:
zx2967_smbus_xfer_prepare(i2c, addr, read_write,
command, size, data);
break;
default:
return -EOPNOTSUPP;
}
if (read_write == I2C_SMBUS_READ)
return zx2967_smbus_xfer_read(i2c, size, data);
return zx2967_smbus_xfer_write(i2c);
}
static u32 zx2967_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C |
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_PROC_CALL |
I2C_FUNC_SMBUS_I2C_BLOCK;
}
static int __maybe_unused zx2967_i2c_suspend(struct device *dev)
{
struct zx2967_i2c *i2c = dev_get_drvdata(dev);
i2c_mark_adapter_suspended(&i2c->adap);
clk_disable_unprepare(i2c->clk);
return 0;
}
static int __maybe_unused zx2967_i2c_resume(struct device *dev)
{
struct zx2967_i2c *i2c = dev_get_drvdata(dev);
clk_prepare_enable(i2c->clk);
i2c_mark_adapter_resumed(&i2c->adap);
return 0;
}
static SIMPLE_DEV_PM_OPS(zx2967_i2c_dev_pm_ops,
zx2967_i2c_suspend, zx2967_i2c_resume);
static const struct i2c_algorithm zx2967_i2c_algo = {
.master_xfer = zx2967_i2c_xfer,
.smbus_xfer = zx2967_smbus_xfer,
.functionality = zx2967_i2c_func,
};
static const struct i2c_adapter_quirks zx2967_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static const struct of_device_id zx2967_i2c_of_match[] = {
{ .compatible = "zte,zx296718-i2c", },
{ },
};
MODULE_DEVICE_TABLE(of, zx2967_i2c_of_match);
static int zx2967_i2c_probe(struct platform_device *pdev)
{
struct zx2967_i2c *i2c;
void __iomem *reg_base;
struct clk *clk;
int ret;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "missing controller clock");
return PTR_ERR(clk);
}
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable i2c_clk\n");
return ret;
}
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
&i2c->clk_freq);
if (ret) {
dev_err(&pdev->dev, "missing clock-frequency");
return ret;
}
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
i2c->irq = ret;
i2c->reg_base = reg_base;
i2c->clk = clk;
init_completion(&i2c->complete);
platform_set_drvdata(pdev, i2c);
ret = zx2967_i2c_reset_hardware(i2c);
if (ret) {
dev_err(&pdev->dev, "failed to initialize i2c controller\n");
goto err_clk_unprepare;
}
ret = devm_request_irq(&pdev->dev, i2c->irq,
zx2967_i2c_isr, 0, dev_name(&pdev->dev), i2c);
if (ret) {
dev_err(&pdev->dev, "failed to request irq %i\n", i2c->irq);
goto err_clk_unprepare;
}
i2c_set_adapdata(&i2c->adap, i2c);
strlcpy(i2c->adap.name, "zx2967 i2c adapter",
sizeof(i2c->adap.name));
i2c->adap.algo = &zx2967_i2c_algo;
i2c->adap.quirks = &zx2967_i2c_quirks;
i2c->adap.nr = pdev->id;
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node;
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret)
goto err_clk_unprepare;
return 0;
err_clk_unprepare:
clk_disable_unprepare(i2c->clk);
return ret;
}
static int zx2967_i2c_remove(struct platform_device *pdev)
{
struct zx2967_i2c *i2c = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c->adap);
clk_disable_unprepare(i2c->clk);
return 0;
}
static struct platform_driver zx2967_i2c_driver = {
.probe = zx2967_i2c_probe,
.remove = zx2967_i2c_remove,
.driver = {
.name = "zx2967_i2c",
.of_match_table = zx2967_i2c_of_match,
.pm = &zx2967_i2c_dev_pm_ops,
},
};
module_platform_driver(zx2967_i2c_driver);
MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
MODULE_DESCRIPTION("ZTE ZX2967 I2C Bus Controller driver");
MODULE_LICENSE("GPL v2");

View File

@ -225,12 +225,8 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter,
adev->power.flags.ignore_parent = true;
acpi_device_set_enumerated(adev);
if (IS_ERR(i2c_new_client_device(adapter, info))) {
if (IS_ERR(i2c_new_client_device(adapter, info)))
adev->power.flags.ignore_parent = false;
dev_err(&adapter->dev,
"failed to add I2C device %s from ACPI\n",
dev_name(&adev->dev));
}
}
static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level,

View File

@ -323,8 +323,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
*/
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ ? 2 : 1;
int i;
int nmsgs = read_write == I2C_SMBUS_READ ? 2 : 1;
u8 partial_pec = 0;
int status;
struct i2c_msg msg[2] = {
@ -340,6 +339,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
.buf = msgbuf1,
},
};
bool wants_pec = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
msgbuf0[0] = command;
switch (size) {
@ -348,13 +349,13 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
/* Special case: The read/write field is used as data */
msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
I2C_M_RD : 0);
num = 1;
nmsgs = 1;
break;
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_READ) {
/* Special case: only a read! */
msg[0].flags = I2C_M_RD | flags;
num = 1;
nmsgs = 1;
}
break;
case I2C_SMBUS_BYTE_DATA:
@ -375,7 +376,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
}
break;
case I2C_SMBUS_PROC_CALL:
num = 2; /* Special case */
nmsgs = 2; /* Special case */
read_write = I2C_SMBUS_READ;
msg[0].len = 3;
msg[1].len = 2;
@ -398,12 +399,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
}
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
msg[0].buf[i] = data->block[i - 1];
memcpy(msg[0].buf + 1, data->block, msg[0].len - 1);
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
num = 2; /* Another special case */
nmsgs = 2; /* Another special case */
read_write = I2C_SMBUS_READ;
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
dev_err(&adapter->dev,
@ -414,8 +414,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
msg[0].len = data->block[0] + 2;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i < msg[0].len; i++)
msg[0].buf[i] = data->block[i - 1];
memcpy(msg[0].buf + 1, data->block, msg[0].len - 1);
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; /* block length will be added by
@ -437,8 +436,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
msg[0].len = data->block[0] + 1;
i2c_smbus_try_get_dmabuf(&msg[0], command);
for (i = 1; i <= data->block[0]; i++)
msg[0].buf[i] = data->block[i];
memcpy(msg[0].buf + 1, data->block + 1, data->block[0]);
}
break;
default:
@ -446,33 +444,31 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
return -EOPNOTSUPP;
}
i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
if (i) {
if (wants_pec) {
/* Compute PEC if first message is a write */
if (!(msg[0].flags & I2C_M_RD)) {
if (num == 1) /* Write only */
if (nmsgs == 1) /* Write only */
i2c_smbus_add_pec(&msg[0]);
else /* Write followed by read */
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
}
/* Ask for PEC if last message is a read */
if (msg[num-1].flags & I2C_M_RD)
msg[num-1].len++;
if (msg[nmsgs - 1].flags & I2C_M_RD)
msg[nmsgs - 1].len++;
}
status = __i2c_transfer(adapter, msg, num);
status = __i2c_transfer(adapter, msg, nmsgs);
if (status < 0)
goto cleanup;
if (status != num) {
if (status != nmsgs) {
status = -EIO;
goto cleanup;
}
status = 0;
/* Check PEC if last message is a read */
if (i && (msg[num-1].flags & I2C_M_RD)) {
status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
if (wants_pec && (msg[nmsgs - 1].flags & I2C_M_RD)) {
status = i2c_smbus_check_pec(partial_pec, &msg[nmsgs - 1]);
if (status < 0)
goto cleanup;
}
@ -490,8 +486,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
data->block[i + 1] = msg[1].buf[i];
memcpy(data->block + 1, msg[1].buf, data->block[0]);
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
@ -502,8 +497,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
status = -EPROTO;
goto cleanup;
}
for (i = 0; i < msg[1].buf[0] + 1; i++)
data->block[i] = msg[1].buf[i];
memcpy(data->block, msg[1].buf, msg[1].buf[0] + 1);
break;
}

View File

@ -19,6 +19,7 @@
enum testunit_cmds {
TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */
TU_CMD_HOST_NOTIFY,
TU_CMD_SMBUS_BLOCK_PROC_CALL,
TU_NUM_CMDS
};
@ -88,6 +89,8 @@ 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);
bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 &&
tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL;
int ret = 0;
switch (event) {
@ -118,12 +121,17 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
fallthrough;
case I2C_SLAVE_WRITE_REQUESTED:
memset(tu->regs, 0, TU_NUM_REGS);
tu->reg_idx = 0;
break;
case I2C_SLAVE_READ_REQUESTED:
case I2C_SLAVE_READ_PROCESSED:
*val = TU_CUR_VERSION;
if (is_proc_call && tu->regs[TU_REG_DATAH])
tu->regs[TU_REG_DATAH]--;
fallthrough;
case I2C_SLAVE_READ_REQUESTED:
*val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION;
break;
}

View File

@ -7,7 +7,6 @@
*/
#define DEBUG 1
#define pr_fmt(fmt) "i2c-stub: " fmt
#include <linux/errno.h>

View File

@ -49,60 +49,112 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
#ifdef CONFIG_OF
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
#ifdef CONFIG_ACPI
static int i2c_mux_gpio_get_acpi_adr(struct device *dev,
struct fwnode_handle *fwdev,
unsigned int *adr)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
unsigned *values;
int i = 0;
unsigned long long adr64;
acpi_status status;
if (!np)
return -ENODEV;
status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev),
METHOD_NAME__ADR,
NULL, &adr64);
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
if (!ACPI_SUCCESS(status)) {
dev_err(dev, "Cannot get address\n");
return -EINVAL;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
of_node_put(adapter_np);
*adr = adr64;
if (*adr != adr64) {
dev_err(dev, "Address out of range\n");
return -ERANGE;
}
return 0;
}
#else
static int i2c_mux_gpio_get_acpi_adr(struct device *dev,
struct fwnode_handle *fwdev,
unsigned int *adr)
{
return -EINVAL;
}
#endif
static int i2c_mux_gpio_probe_fw(struct gpiomux *mux,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *adapter_np;
struct i2c_adapter *adapter = NULL;
struct fwnode_handle *child;
unsigned *values;
int rc, i = 0;
if (is_of_node(dev->fwnode)) {
if (!np)
return -ENODEV;
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
of_node_put(adapter_np);
} else if (is_acpi_node(dev->fwnode)) {
/*
* In ACPI land the mux should be a direct child of the i2c
* bus it muxes.
*/
acpi_handle dev_handle = ACPI_HANDLE(dev->parent);
adapter = i2c_acpi_find_adapter_by_handle(dev_handle);
}
if (!adapter)
return -EPROBE_DEFER;
mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev);
mux->data.n_values = of_get_child_count(np);
values = devm_kcalloc(&pdev->dev,
mux->data.n_values = device_get_child_node_count(dev);
values = devm_kcalloc(dev,
mux->data.n_values, sizeof(*mux->data.values),
GFP_KERNEL);
if (!values) {
dev_err(&pdev->dev, "Cannot allocate values array");
dev_err(dev, "Cannot allocate values array");
return -ENOMEM;
}
for_each_child_of_node(np, child) {
of_property_read_u32(child, "reg", values + i);
device_for_each_child_node(dev, child) {
if (is_of_node(child)) {
fwnode_property_read_u32(child, "reg", values + i);
} else if (is_acpi_node(child)) {
rc = i2c_mux_gpio_get_acpi_adr(dev, child, values + i);
if (rc)
return rc;
}
i++;
}
mux->data.values = values;
if (of_property_read_u32(np, "idle-state", &mux->data.idle))
if (fwnode_property_read_u32(dev->fwnode, "idle-state", &mux->data.idle))
mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
return 0;
}
#else
static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
struct platform_device *pdev)
{
return 0;
}
#endif
static int i2c_mux_gpio_probe(struct platform_device *pdev)
{
@ -118,7 +170,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev);
ret = i2c_mux_gpio_probe_fw(mux, pdev);
if (ret < 0)
return ret;
} else {

View File

@ -1,35 +1,8 @@
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/*
* drivers/i2c/muxes/i2c-mux-mlxcpld.c
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
* Mellanox i2c mux driver
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* Copyright (C) 2016-2020 Mellanox Technologies
*/
#include <linux/device.h>
@ -38,19 +11,19 @@
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_data/x86/mlxcpld.h>
#include <linux/platform_data/mlxcpld.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define CPLD_MUX_MAX_NCHANS 8
/* mlxcpld_mux - mux control structure:
* @last_chan - last register value
* @last_val - last selected register value or -1 if mux deselected
* @client - I2C device client
* @pdata: platform data
*/
struct mlxcpld_mux {
u8 last_chan;
int last_val;
struct i2c_client *client;
struct mlxcpld_mux_plat_data pdata;
};
/* MUX logic description.
@ -81,37 +54,50 @@ struct mlxcpld_mux {
*
*/
static const struct i2c_device_id mlxcpld_mux_id[] = {
{ "mlxcpld_mux_module", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id);
/* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer()
* for this as they will try to lock adapter a second time.
*/
static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
struct mlxcpld_mux *mux, u32 val)
{
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
union i2c_smbus_data data = { .byte = val };
struct i2c_client *client = mux->client;
union i2c_smbus_data data;
struct i2c_msg msg;
u8 buf[3];
return __i2c_smbus_xfer(adap, client->addr, client->flags,
I2C_SMBUS_WRITE, pdata->sel_reg_addr,
I2C_SMBUS_BYTE_DATA, &data);
switch (mux->pdata.reg_size) {
case 1:
data.byte = val;
return __i2c_smbus_xfer(adap, client->addr, client->flags,
I2C_SMBUS_WRITE, mux->pdata.sel_reg_addr,
I2C_SMBUS_BYTE_DATA, &data);
case 2:
buf[0] = mux->pdata.sel_reg_addr >> 8;
buf[1] = mux->pdata.sel_reg_addr;
buf[2] = val;
msg.addr = client->addr;
msg.buf = buf;
msg.len = mux->pdata.reg_size + 1;
msg.flags = 0;
return __i2c_transfer(adap, &msg, 1);
default:
return -EINVAL;
}
}
static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct mlxcpld_mux *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
u8 regval = chan + 1;
struct mlxcpld_mux *mux = i2c_mux_priv(muxc);
u32 regval = chan;
int err = 0;
if (mux->pdata.reg_size == 1)
regval += 1;
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
data->last_chan = err < 0 ? 0 : regval;
if (mux->last_val != regval) {
err = mlxcpld_mux_reg_write(muxc->parent, mux, regval);
mux->last_val = err < 0 ? -1 : regval;
}
return err;
@ -119,56 +105,64 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
{
struct mlxcpld_mux *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
struct mlxcpld_mux *mux = i2c_mux_priv(muxc);
/* Deselect active channel */
data->last_chan = 0;
mux->last_val = -1;
return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan);
return mlxcpld_mux_reg_write(muxc->parent, mux, 0);
}
/* Probe/reomove functions */
static int mlxcpld_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int mlxcpld_mux_probe(struct platform_device *pdev)
{
struct i2c_adapter *adap = client->adapter;
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&pdev->dev);
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct i2c_mux_core *muxc;
int num, force;
struct mlxcpld_mux *data;
int err;
int num, err;
u32 func;
if (!pdata)
return -EINVAL;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
switch (pdata->reg_size) {
case 1:
func = I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
break;
case 2:
func = I2C_FUNC_I2C;
break;
default:
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter, func))
return -ENODEV;
muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS,
muxc = i2c_mux_alloc(client->adapter, &pdev->dev, pdata->num_adaps,
sizeof(*data), 0, mlxcpld_mux_select_chan,
mlxcpld_mux_deselect);
if (!muxc)
return -ENOMEM;
platform_set_drvdata(pdev, muxc);
data = i2c_mux_priv(muxc);
i2c_set_clientdata(client, muxc);
data->client = client;
data->last_chan = 0; /* force the first selection */
memcpy(&data->pdata, pdata, sizeof(*pdata));
data->last_val = -1; /* force the first selection */
/* Create an adapter for each channel. */
for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) {
if (num >= pdata->num_adaps)
/* discard unconfigured channels */
break;
force = pdata->adap_ids[num];
err = i2c_mux_add_adapter(muxc, force, num, 0);
for (num = 0; num < pdata->num_adaps; num++) {
err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0);
if (err)
goto virt_reg_failed;
}
/* Notify caller when all channels' adapters are created. */
if (pdata->completion_notify)
pdata->completion_notify(pdata->handle, muxc->parent, muxc->adapter);
return 0;
virt_reg_failed:
@ -176,24 +170,23 @@ static int mlxcpld_mux_probe(struct i2c_client *client,
return err;
}
static int mlxcpld_mux_remove(struct i2c_client *client)
static int mlxcpld_mux_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
i2c_mux_del_adapters(muxc);
return 0;
}
static struct i2c_driver mlxcpld_mux_driver = {
.driver = {
.name = "mlxcpld-mux",
static struct platform_driver mlxcpld_mux_driver = {
.driver = {
.name = "i2c-mux-mlxcpld",
},
.probe = mlxcpld_mux_probe,
.remove = mlxcpld_mux_remove,
.id_table = mlxcpld_mux_id,
.probe = mlxcpld_mux_probe,
.remove = mlxcpld_mux_remove,
};
module_i2c_driver(mlxcpld_mux_driver);
module_platform_driver(mlxcpld_mux_driver);
MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)");
MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver");

View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/*
* Mellanox I2C multiplexer support in CPLD
*
* Copyright (C) 2016-2020 Mellanox Technologies
*/
#ifndef _LINUX_I2C_MLXCPLD_H
#define _LINUX_I2C_MLXCPLD_H
/* Platform data for the CPLD I2C multiplexers */
/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info
* @chan_ids - channels array
* @num_adaps - number of adapters
* @sel_reg_addr - mux select register offset in CPLD space
* @reg_size: register size in bytes
* @handle: handle to be passed by callback
* @completion_notify: callback to notify when all the adapters are created
*/
struct mlxcpld_mux_plat_data {
int *chan_ids;
int num_adaps;
int sel_reg_addr;
u8 reg_size;
void *handle;
int (*completion_notify)(void *handle, struct i2c_adapter *parent,
struct i2c_adapter *adapters[]);
};
#endif /* _LINUX_I2C_MLXCPLD_H */

View File

@ -1,52 +0,0 @@
/*
* mlxcpld.h - Mellanox I2C multiplexer support in CPLD
*
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
* Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX_I2C_MLXCPLD_H
#define _LINUX_I2C_MLXCPLD_H
/* Platform data for the CPLD I2C multiplexers */
/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info
* @adap_ids - adapter array
* @num_adaps - number of adapters
* @sel_reg_addr - mux select register offset in CPLD space
*/
struct mlxcpld_mux_plat_data {
int *adap_ids;
int num_adaps;
int sel_reg_addr;
};
#endif /* _LINUX_I2C_MLXCPLD_H */

View File

@ -1,25 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
i2c-dev.h - i2c-bus driver, char device interface
Copyright (C) 1995-97 Simon G. Vogl
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
* i2c-dev.h - I2C bus char device interface
*
* Copyright (C) 1995-97 Simon G. Vogl
* Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
*/
#ifndef _UAPI_LINUX_I2C_DEV_H
#define _UAPI_LINUX_I2C_DEV_H

View File

@ -1,29 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/* ------------------------------------------------------------------------- */
/* */
/* i2c.h - definitions for the i2c-bus interface */
/* */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-2000 Simon G. Vogl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA. */
/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
Frodo Looijaard <frodol@dds.nl> */
/*
* i2c.h - definitions for the I2C bus interface
*
* Copyright (C) 1995-2000 Simon G. Vogl
* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
* Frodo Looijaard <frodol@dds.nl>
*/
#ifndef _UAPI_LINUX_I2C_H
#define _UAPI_LINUX_I2C_H
@ -32,18 +14,41 @@
/**
* struct i2c_msg - an I2C transaction segment beginning with START
* @addr: Slave address, either seven or ten bits. When this is a ten
* bit address, I2C_M_TEN must be set in @flags and the adapter
* must support I2C_FUNC_10BIT_ADDR.
* @flags: I2C_M_RD is handled by all adapters. No other flags may be
* provided unless the adapter exported the relevant I2C_FUNC_*
* flags through i2c_check_functionality().
* @len: Number of data bytes in @buf being read from or written to the
* I2C slave address. For read transactions where I2C_M_RECV_LEN
* is set, the caller guarantees that this buffer can hold up to
* 32 bytes in addition to the initial length byte sent by the
* slave (plus, if used, the SMBus PEC); and this value will be
* incremented by the number of block data bytes received.
*
* @addr: Slave address, either 7 or 10 bits. When this is a 10 bit address,
* %I2C_M_TEN must be set in @flags and the adapter must support
* %I2C_FUNC_10BIT_ADDR.
*
* @flags:
* Supported by all adapters:
* %I2C_M_RD: read data (from slave to master). Guaranteed to be 0x0001!
*
* Optional:
* %I2C_M_DMA_SAFE: the buffer of this message is DMA safe. Makes only sense
* in kernelspace, because userspace buffers are copied anyway
*
* Only if I2C_FUNC_10BIT_ADDR is set:
* %I2C_M_TEN: this is a 10 bit chip address
*
* Only if I2C_FUNC_SMBUS_READ_BLOCK_DATA is set:
* %I2C_M_RECV_LEN: message length will be first received byte
*
* Only if I2C_FUNC_NOSTART is set:
* %I2C_M_NOSTART: skip repeated start sequence
* Only if I2C_FUNC_PROTOCOL_MANGLING is set:
* %I2C_M_NO_RD_ACK: in a read message, master ACK/NACK bit is skipped
* %I2C_M_IGNORE_NAK: treat NACK from client as ACK
* %I2C_M_REV_DIR_ADDR: toggles the Rd/Wr bit
* %I2C_M_STOP: force a STOP condition after the message
*
* @len: Number of data bytes in @buf being read from or written to the I2C
* slave address. For read transactions where %I2C_M_RECV_LEN is set, the
* caller guarantees that this buffer can hold up to %I2C_SMBUS_BLOCK_MAX
* bytes in addition to the initial length byte sent by the slave (plus,
* if used, the SMBus PEC); and this value will be incremented by the number
* of block data bytes received.
*
* @buf: The buffer into which data is read, or from which it's written.
*
* An i2c_msg is the low level representation of one segment of an I2C
@ -60,40 +65,36 @@
* group, it is followed by a STOP. Otherwise it is followed by the next
* @i2c_msg transaction segment, beginning with a (repeated) START.
*
* Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
* Alternatively, when the adapter supports %I2C_FUNC_PROTOCOL_MANGLING then
* passing certain @flags may have changed those standard protocol behaviors.
* Those flags are only for use with broken/nonconforming slaves, and with
* adapters which are known to support the specific mangling options they
* need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
* adapters which are known to support the specific mangling options they need.
*/
struct i2c_msg {
__u16 addr; /* slave address */
__u16 addr;
__u16 flags;
#define I2C_M_RD 0x0001 /* read data, from slave to master */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */
/* makes only sense in kernelspace */
/* userspace buffers are copied anyway */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
#define I2C_M_RD 0x0001 /* guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* use only if I2C_FUNC_10BIT_ADDR */
#define I2C_M_DMA_SAFE 0x0200 /* use only in kernel space */
#define I2C_M_RECV_LEN 0x0400 /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */
#define I2C_M_NO_RD_ACK 0x0800 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* use only if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */
__u16 len;
__u8 *buf;
};
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */
#define I2C_FUNC_10BIT_ADDR 0x00000002 /* required for I2C_M_TEN */
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* required for I2C_M_IGNORE_NAK etc. */
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */
#define I2C_FUNC_NOSTART 0x00000010 /* required for I2C_M_NOSTART */
#define I2C_FUNC_SLAVE 0x00000020
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 or later */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
@ -102,11 +103,11 @@ struct i2c_msg {
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 /* required for I2C_M_RECV_LEN */
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000
#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000 /* SMBus 2.0 or later */
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE)
@ -128,6 +129,11 @@ struct i2c_msg {
I2C_FUNC_SMBUS_I2C_BLOCK | \
I2C_FUNC_SMBUS_PEC)
/* if I2C_M_RECV_LEN is also supported */
#define I2C_FUNC_SMBUS_EMUL_ALL (I2C_FUNC_SMBUS_EMUL | \
I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_BLOCK_PROC_CALL)
/*
* Data for SMBus Messages
*/