Update comment and driver-local identifiers to use the
controller/target terminology ratified by coding guideline A.2
and already used by the Zephyr I2C API.
Identifiers mirroring the DesignWare databook
(e.g. IC_CON union bitfields, IC_TAR union bitfield ic_10bitaddr_master,
IC_TX_ABRT_SOURCE union bitfields) are kept unchanged.
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Assisted-by: Claude:fable-5
Replace the direct NVIC_ClearPendingIRQ() call in the RTS5912 quirk
path with the portable k_irq_clear_pending() and drop the cmsis_core.h
include, removing the last piece of CPU-specific code from the
DesignWare I2C driver. RTS5912 is a plain-NVIC Cortex-M33, so the
capability is always available where the quirk compiles.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
i2c_dw_transfer_complete() clears the NVIC pending bit for its own IRQ
line after clearing the IP-level interrupt source. This was added along
with the RTS5912 support in commit 748789eadf ("drivers: i2c: rts5912
i2c dirver") but gated on CONFIG_CPU_CORTEX_M, so every Cortex-M user of
the DesignWare IP -- RP2040/RP2350, SiWG917, Synaptics SR100 -- silently
inherited a Realtek-specific workaround, and the shared IP driver grew a
dependency on cmsis_core.h.
Clearing the NVIC pending bit after the source has already been cleared
also discards any interrupt that latched in between, so it is not a
harmless no-op on parts that do not need it.
Gate the call, the cmsis_core.h include and the irqnumber config member
on CONFIG_I2C_RTS5912 instead, matching the other RTS5912 carve-outs
already present in Kconfig.dw. Behaviour on RTS5912 is unchanged; other
Cortex-M platforms return to the pre-748789eadf710 behaviour. Dropping
irqnumber for everyone else also removes a DT_INST_IRQN() on PCIe
instances, which have no devicetree interrupt of their own.
Also drop the unused zephyr/arch/cpu.h include added by the same commit;
it is a pure dispatch header and kernel.h and irq.h already provide
everything the driver uses.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
i2c_dw_probe_hw() still stores the MMIO base returned by
DEVICE_MMIO_GET() in a uint32_t, truncating addresses above 4 GiB on
64-bit systems. Use mm_reg_t for the remaining MMIO base address.
Signed-off-by: Liwen Wu <liwen.wu@spacemit.com>
The controller path in i2c_dw_setup() had three issues around
10-bit addressing:
* addr_master_10bit was only ever set on the 10-bit branch and
never cleared, so once a 10-bit configuration had been
programmed the controller stayed latched in 10-bit mode for
subsequent 7-bit transfers.
* Both check sites used the deprecated I2C_ADDR_10_BITS macro
instead of the current I2C_MSG_ADDR_10_BITS definition.
* The ic_10bitaddr_master programming (dynamic TAR path) was
guarded by an additional I2C_MODE_CONTROLLER check that is
already asserted earlier in the same function, making the
outer branch redundant.
Fix all three by adding an explicit 7-bit clear branch, replacing
I2C_ADDR_10_BITS with I2C_MSG_ADDR_10_BITS, and collapsing the
dynamic TAR block to a straight if/else. No functional change to
the 7-bit default behavior.
Signed-off-by: Shreehari HK <shreehari.hk@alifsemi.com>
Use mm_reg_t for DesignWare I2C MMIO register addresses to avoid
truncating addresses above 4 GiB on 64-bit systems.
Keep register values as uint32_t since the controller still uses
32-bit register accesses.
Signed-off-by: Liwen Wu <liwen.wu@spacemit.com>
The need_setup member of struct i2c_dw_dev_config only exists when
CONFIG_I2C_ALLOW_NO_STOP_TRANSACTIONS is enabled, and every other
access to it in the driver is wrapped in a matching #if. The write
added in i2c_dw_transfer() to require a re-setup after a failed or
aborted transaction was left unguarded, so the driver fails to build
whenever that option is off:
drivers/i2c/i2c_dw.c:1032:19: error: 'struct i2c_dw_dev_config'
has no member named 'need_setup'
Wrap the write in the same #if used by the rest of the driver.
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Explicitly set the addressing type during target mode registration.
In the DW implementation, the addressing type is configured
independently for controller and target modes, so this change also
removes setting of the target mode address type during controller
mode configuration.
Tested on Realtek rts5915 board with an EEPROM target enabled.
Signed-off-by: Keith Short <keithshort@google.com>
If an i2c transaction got past setting the need_setup but didn't
complete for some reason the i2c driver would send the next transaction
to that address regardless of what was passed into the driver. Update the
i2c_dw_transfer error handler to reset need_setup to true since the failed
transaction is no longer active.
Also adds a check in setup to verify that the target address is the address
that is setup, if not require setup.
Signed-off-by: Brandon Breitenstein <brandon.breitenstein@intel.com>
Replace the driver specific I2C_DW_RW_TIMEOUT_MS with the generic macro
that allows override via Kconfig and dt properties.
Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
DT_INST_NODE_HAS_PROP was spelled with hyphens in the sda_hold_tx
initializer, so the i2c-sda-hold-time-ns property was silently
ignored.
Assisted-by: Claude:fable-5
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
Add device power management to the DesignWare I2C driver so instances
under a switchable power domain can be used safely with runtime PM.
Hardware bring-up is moved from initialize() to PM_DEVICE_ACTION_TURN_ON
via i2c_dw_turn_on(), which reuses the helpers introduced in the
previous commit (prepare, probe_hw, init_config). initialize() now
only performs one-time CPU-side setup: MMIO/PCIe mapping, semaphores,
IRQ connect, and default app_config, then calls pm_device_driver_init().
It also add pm_device_runtime_get()/put() when needed to prevent the CPU
from sleeping while the device is in use.
When CONFIG_PM_DEVICE or runtime PM is not enabled for an instance,
existing behavior is preserved: runtime get/put are no-ops, and
pm_device_driver_init() still invokes TURN_ON at the end of init when
the device is powered.
Signed-off-by: Martin Hoff <martin.hoff@silabs.com>
In i2c_dw_initialize(), move the i2c_dw_prepare() call to after
MMIO/PCIe mapping instead of before it.
MMIO mapping and PCIe BAR setup are CPU-side bus operations and do not
require the peripheral clock, reset, or pinctrl to be enabled first.
Clock, reset, and pin configuration are still applied before any
controller register access (probe and init_config).
No change to the helpers themselves or to the overall initialization
sequence beyond this ordering fix.
Signed-off-by: Martin Hoff <martin.hoff@silabs.com>
Refactor i2c_dw_initialize() by extracting the hardware setup into
focused helpers without changing runtime behavior:
- i2c_dw_prepare(): enable clock, optional reset, and pinctrl
- i2c_dw_probe_hw(): COMP_TYPE check and high-speed mode detection
- i2c_dw_init_config(): controller register programming (SDA hold,
block mode, spike length, bitrate configuration, extended timeouts)
i2c_dw_initialize() still follows the same call order as before except
for :
- we are now doing the COMPT_TYPE + high-speed mode detection before
setting up the SDAHOLD timing register (register programming)
- we are now doing the controller register programming before the IRQ
registration (that was done in the middle of it before )
Register programming has been assembled into a single helper function to
make it easier to understand and maintain hence the diff in call order.
This is a preparatory step for introducing runtime power management for
the I2C driver.
Signed-off-by: Martin Hoff <martin.hoff@silabs.com>
Replace nested MIN/MAX macro calls with the min3/max3 APIs which are
safer (evaluate arguments only once) and cleaner.
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
In target mode, read_in_progress is only cleared on STOP_DET.
When a master issues a compound transaction with multiple repeated
STARTs that transitions from read back to write and then read again,
read_in_progress remains set from the first read phase. On the
second read phase the ISR takes the read_processed path instead of
read_requested, returning data from the wrong offset.
For example, an EEPROM-style compound transaction:
S addr+W ptr Sr addr+R [data1] NAK
Sr addr+W ptr Sr addr+R [data2] NAK P
Where S = START, Sr = repeated START, P = STOP, W = write,
R = read, NAK = not-acknowledge (last byte of a read).
data1 reads correctly, but data2 returns stale EEPROM content
because read_requested (which returns the byte at the current
pointer) is skipped in favor of read_processed (which increments
first, then returns the next byte).
Reset read_in_progress when entering a new write phase (RX_FULL
with state != CMD_SEND). This ensures the subsequent read phase
correctly calls read_requested to fetch data at the updated pointer.
The bug can be reproduced with the following C test program using
the I2C_RDWR ioctl against any I2C EEPROM target:
/* 4-message compound: set ptr + read + set ptr + read */
struct i2c_msg msgs[4] = {
{ .addr = 0x54, .flags = 0, .len = 1, .buf = &ptr },
{ .addr = 0x54, .flags = I2C_M_RD, .len = 1, .buf = &rd1 },
{ .addr = 0x54, .flags = 0, .len = 1, .buf = &ptr },
{ .addr = 0x54, .flags = I2C_M_RD, .len = 1, .buf = &rd2 },
};
ioctl(fd, I2C_RDWR, &(struct i2c_rdwr_ioctl_data){msgs, 4});
/* Before fix: rd1 correct, rd2 wrong (stale offset) */
/* After fix: rd1 == rd2 == expected value */
Tested with FT232H master and RP2040 EEPROM target at 400 kHz:
10000 compound w+r+w+r cycles with 0 failures. Also verified with
libmpsse userspace I2C.
Signed-off-by: Vincent Jardin <vjardin@free.fr>
Update all drivers to use "flags" instead of "sense" when accessing
interrupt properties from device tree. This aligns with the updated
interrupt controller bindings that now consistently use "flags" as
the cell name for the IRQ type field.
Signed-off-by: Amneesh Singh <amneesh@ti.com>
This adds optional clock control support to the i2c_dw driver. The
support currently assumes that the clock control binding uses clkid for
the clock cell name.
Signed-off-by: Łukasz Kędziora <lkedziora@antmicro.com>
Signed-off-by: Piotr Zierhoffer <pzierhoffer@antmicro.com>
Signed-off-by: Andreas Weissel <andreas.weissel@synaptics.com>
The stop_det handler resets dw->state to READY and clears
read_in_progress before calling the target's stop() callback.
The driver is already in READY stateand a concurrent interrupt
may observe an inconsistent view.
Invoke stop() first, then reset state. This matches the ordering of
most other Zephyr I2C target drivers and keeps the state transition
atomic with respect to the callback.
Signed-off-by: Sudarshan Iyengar <sudarshan.iyengar@alifsemi.com>
dw->read_in_progress is only cleared in the stop_det branch of the
target ISR and at target_register() time. If a master read is
aborted by NACK (tx_abrt) or by bus error (rx_under/rx_over/tx_over)
without a terminating STOP, the flag remains set. The next legitimate
master read then takes the else branch and invokes read_processed()
instead of read_requested(), so the target never sees a fresh
read transaction and returns stale data.
Clear read_in_progress in every error path that resets dw->state
to READY.
i2c_dw_slave_read_clear_intr_bits() previously re-read IC_INTR_STAT
locally, while i2c_dw_isr() had already cached the same register at
entry. Two independent reads of a hardware status register create a
race: bits can be asserted by hardware between the two reads, causing
the helper and the ISR to observe different views of the interrupt
state.
Signed-off-by: Sudarshan Iyengar <sudarshan.iyengar@alifsemi.com>
Assisted-by: Claude:claude-opus-4.7
The target ISR gates write_requested() on `dw->state != CMD_SEND` so
that back-to-back rx_full interrupts during a single write do not
re-enter the callback. However, dw->state is only transitioned back
to READY on stop_det. If the STOP interrupt is lost (glitch, bus
reset, another master drives STOP while we are servicing the ISR),
or if the master issues a repeated START with the same direction
(WRITE-Sr-WRITE, which is legal in I2C), the state stays CMD_SEND
forever and write_requested() is never called again for the rest of
the target's life.
i2c_dw_slave_read_clear_intr_bits() already handles start_det by
resetting state to READY, but START_DET is not in the enabled
interrupt mask in i2c_dw_slave_register(), so that path is dead code.
Unmask START_DET so the boundary of every new (re)START on the bus
is observed and state is correctly reset before the rx_full handler
decides whether to call write_requested().
Signed-off-by: Sudarshan Iyengar <sudarshan.iyengar@alifsemi.com>
This PR introduces the `sda-hold-time-ns` DeviceTree property for
DesignWare I2C controllers. The driver logic is updated to prioritize
this nanosecond configuration, calculating the necessary hardware clock
ticks at build time using the new `HOLD_TIME_TO_TICKS` macro. If the
property is not defined, it safely falls back to the legacy
`sda-hold-tx` tick configuration.
Fixes#83437
Signed-off-by: Akansh Sinha <akansh.sinha.dev@gmail.com>
The i2c bus may be pulled low by unstable environment.
Check the status before I2C transfer and
skip transmission if the bus is not ready.
Signed-off-by: Lin Yu-Cheng <lin_yu_cheng@realtek.com>
There is such situation where the PINCTRL is enabled but no pinctrl
state for i2c dw, we need to skip the pinctrl_apply_state() otherwise
the driver can't be initialized successfully.
Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
- Introduce support for the DesignWare I2C specific core clock frequency
optimization feature (IC_CLK_FREQ_OPTIMIZATION).
- This feature reduces the internal latency cycles required to generate
the SCL high and low periods, allowing the controller to achieve target
bus speeds with a lower input clock (ic_clk) frequency.
- The driver now supports both standard calculation (optimization=0) and
the new optimized mode, selectable via Kconfig. This ensures
compatibility with existing hardware while enabling the optimization
on platforms that support it.
Signed-off-by: Shreehari HK <shreehari.hk@alifsemi.com>
- Replace hardcoded magic numbers for SCL High and Low Count register
minimum values with descriptive macros.
- The DesignWare I2C controller requires specific minimum values
(Section 2.14.1 of DW Spec) for IC_*_SCL_HCNT and IC_*_SCL_LCNT
registers based on the spike length (SPKLEN) configuration.
Specifically:
- HCNT must be at least IC_*_SPKLEN + 6
- LCNT must be at least IC_*_SPKLEN + 8
- Using macros improves readability and maintainability by documenting
the source of these constraints and ensuring consistency across the
driver.
Signed-off-by: Shreehari HK <shreehari.hk@alifsemi.com>
Previously, the spike length suppression was only configured in the
master mode. This resulted in the slave mode
missing this configuration.
Move the spike length setting to the common initialization function
to ensure it is applied for both master and slave modes.
Signed-off-by: Shreehari HK <shreehari.hk@alifsemi.com>
Move the get_regs(dev) call after DEVICE_MMIO_MAP() to ensure the MMIO
region is mapped before retrieving the register base.
This fixes the potential invalid MMIO access.
Signed-off-by: Muhammad Waleed Badar <walid.badar@gmail.com>
Corrected the DT_INST_PROP_OR mapping for sda_hold_rx.
It was mistakenly using scl_hold_rx as the property name.
Signed-off-by: Elmo Lan <elmo_lan@realtek.com>
The read clear in i2c_dw_error_chk() will misclean the tx_abrt interrupt.
This patch will move the read clear function into the isr handler
to make the transaction flow end normally.
Signed-off-by: Lin Yu-Cheng <lin_yu_cheng@realtek.com>
Some implementations of the DesginWare I2C controller do not support the
system suspending to idle during an I2C transaction. Add a Kconfig
option to allow locking of the power management policy state during
I2C transactions.
Signed-off-by: Keith Short <keithshort@google.com>
Add support for configuring SCL and SDA spike suppression based on
the I2C controller input clock.
The DesignWare I2C spike suppression registers are programmed using
values expressed in ic_clk cycles, in line with the I2C-bus
specification.
Signed-off-by: Shreehari HK <shreehari.hk@alifsemi.com>
When the transfer timeout and driver set user abort,
we need go recovery flow to make sure bus recovery and reg recovery.
Signed-off-by: Elmo Lan <elmo_lan@realtek.com>
Remove duplicated #include directives within the same
preprocessor scope across the Zephyr tree.
Duplicates inside different #ifdef branches are preserved
as they may be intentional.
Signed-off-by: Sylvio Alves <sylvio.alves@espressif.com>
Depending on the IP's `IC_TX_CMD_BLOCK_DEFAULT` parameter, we
might have to clear the `TX_CMD_BLOCK` bit on init so that
Controller mode works.
Signed-off-by: Yong Cong Sin <ycsin@meta.com>
Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
In target mode, issue the stop callback from the I2C DW driver after the
read/write callbacks. This mirrors the behavior of other I2C target mode
drivers, and allows target handler code to correctly service any pending
read or write requests before it handles the stop condition.
Fixes#98675
Signed-off-by: Daniel DeGrasse <ddegrasse@tenstorrent.com>
NACK message now log with LOG_ERR_RATELIMIT
instead of LOG_ERR to reduce log noise.
When scanning I2C device,
receiving a NACK is expected behavior and not necessarily an error.
Logging it at LOG_ERR causes unnecessary clutter in the logs.
Therefore, the log level is change to LOG_ERR_RATELIMIT for NACK cases.
Signed-off-by: Elmo Lan <elmo_lan@realtek.com>
Including soc.h is causing issues - drop as it's not needed
Fixes e.g. the below:
west build -p -b em_starterkit@2.2.0/emsk_em7d \
tests/drivers/build_all/w1 -T drivers.w1.build
Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
The I2C target implementation for i2c_dw does not follow the
zephyr target specification. The following three issues are corrected:
1) The read_requested CB is called on every byte of the transaction
- it must be called only on the first byte of the transaction
2) The read_processed CB is called on every byte of the transaction
- it must be called only on bytes following the first byte
3) Bytes returned in the data ptr param of read_processed are not
sent to the controller
-These bytes must be sent to the controller
Signed-off-by: James Growden <jgrowden@tenstorrent.com>
Only include cmsis_core.h on ARM platforms, including it unconditionally
as it is now causes a build failure on all other platforms, namely x86
on the weekly build run.
Tested with:
west build -p -b up_squared/apollo_lake tests/drivers/build_all/led
(and others)
Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
base on DesignWare I2C driver to implement RTS5912 I2C driver.
1. support customize bus recovery function.
2. fix isr timing issue by enable tx empty control.
3. support stuck at low handle by enable bus clear feature.
4. support custom stuck at low timeout set from dts
5. disable block mode in rts5912 i2c.
6. support I2C_ALLOW_NO_STOP_TRANSACTIONS
Signed-off-by: Titan Chen <titan.chen@realtek.com>
On timeout, it's possible for the controller to be in a bad state.
This change initiates the transfer abort sequence which can recover
from these cases and make the bus usable again.
Signed-off-by: Corey Wharton <xodus7@cwharton.com>
Regardless of the argument specified, it always references the
property of the 0th, so it was corrected to reference the instance
specified by the argument.
Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
The actual clock speed of the bus is partially determined by the
rising/falling edges of the SCL. These settings allow applications
to tune the clock based on board characteristics.
Signed-off-by: Corey Wharton <xodus7@cwharton.com>
To reduce lint warnings during code review, it is best
to keep clang-format happy
This commit makes a lint pass to this driver
Signed-off-by: Rafael Laya <rafael_laya97@hotmail.com>