For many of the state checks with timeout, the check
should be very fast (sub 1 microseconds) and the
previous implemention involving busy waits between
checks could add unneeded latency. Change the
timeout checking method to use WAIT_FOR(), with
no extra delays between checks.
Signed-off-by: Mike J. Chen <mjchen@google.com>
Have seen timeout error occur when doing an emit stop at
end of a multiple register write to a mmc5633 mag sensor IC.
The i3c_mcux driver would return on such an error without
doing the k_condvar_broadcast(), since the stop wasn't
technically done (or unclear if it was), and then future
transfers requests waiting on the condvar could be blocked
forever. Add a limited retry when a timeout occurs to
avoid such a stall condition from happening.
Signed-off-by: Mike J. Chen <mjchen@google.com>
Error check was incorrect, causing wait for complete
not to be done. This can result in emit stop not
working on writes because controller won't do the
stop if it is still busy processing transmit.
Signed-off-by: Mike J. Chen <mjchen@google.com>
The main improvement is that mcux_i3c_transfer() and
mcux_i3c_i2c_api_transfer() will try much harder to not return an error
that could be caused by the bus being busy. The bus could be busy because
of IBI handling, especially if there are multiple I3C devices all raising
IBI that need to be processed, which can involve a number of context
switches and delays and take considerable time such that an application
initiated I3C transfer request might have returned busy. Replaced the code
that polled for idle state with a timeout with an infinite loop on a
condvar. The condvar is broadcast to at the end of every stop, which should
be when the bus goes idle.
Details of other changes:
* Remove ibi_lock, which seemed not useful. Use the single lock (switched
from semaphore to mutex so it can be released by condvar) for both IBI
handling and application requests.
* Remove code that disables i3c controller interrupts during transfers.
Since the only interrupt is SLVSTART, and that just posts a work, it
didn't seem necessary to disable that interrupt.
* Don't clear SLVSTART interrupt in mcux_i3c_status_clear_all(), to prevent
any application transfers from accidentally clearing the SLVSTART
interrupt or the handling of one IBI clearing the START initiated by
another I3C device immeidately as the other one finishes.
The only clearing of SLVSTART is in the isr.
* Add back a wait in mcux_i3c_request_auto_ibi(), otherwise the ibitype
could be 0 if the processor is faster than the auto ibi handling.
An earlier change removed a wait for MCTRLDONE, which isn't
always set when AUTO_IBI is requested, but that could mean we try to
read the ibitype before it's ready. Waiting for IBIWON instead should be
correct and better, since the AUTO_IBI should result in IBIWON status bit
being set (and MCTRLDONE being set would not guarantee that IBIWON was
set).
* Change mcux_i3c_request_emit_stop() to still wait for idle if requested,
even if the STOP wasn't actually issued, and add the release of the new
condvar
* Change mcux_i3c_do_one_xfer_read() to handle the IBI use case differently
than the regular application requested transfer case. In the application
requested transfer case, the rx_len is known and set in RDTERM, so we
could check for the COMPLETE status bit, but for IBI transfers, we
just do a read to the payload buffer without knowing how many bytes
the target may send us so never get a COMPLETE. Rather than check for a
COMPLETE bit that might never occur, just have both cases read until we
either read all requested bytes or we get a timeout error. But for the
timeout error, if it's IBI and non-zero bytes were received, return
the bytes received instead of an error.
* Change mcux_i3c_do_one_xfer() to return the error returned by
mcux_i3c_do_one_xfer_read/write().
* Remove spurious return -EIO from end of mcux_i3c_do_daa()
* Change mcux_i3c_ibi_enable() to restore SLVSTART on error, and
add some LOG_ERR() messages for error cases. Also add check to
make sure idx is valid since there is a limit to how many IBI
this controller can support.
* Change mcux_i3c_ibi_disable() to always reenable SLVSTART interrupt,
even if the CCC to tell the target to disable IBI events fails.
* Change mcux_i3c_isr() to reenable SLVSTART interrupt if the
work_enqueue() fails.
Signed-off-by: Mike J. Chen <mjchen@google.com>
It might happens that DT(_INST)_PROP_OR is used with boolean properties.
For instance:
.single_wire = DT_INST_PROP_OR(index, single_wire, false), \
.tx_rx_swap = DT_INST_PROP_OR(index, tx_rx_swap, false), \
This is not required as boolean properties are generated with false
value when not present, so the _OR macro extension is superflous
and the above code can be replaced by:
.single_wire = DT_INST_PROP(index, single_wire), \
.tx_rx_swap = DT_INST_PROP(index, tx_rx_swap), \
Signed-off-by: Roman Studenikin <srv@meta.com>
The default is that the high time for open-drain clk is one
PPBAUD, which is typically very short. Some device require
a longer high time during the open-drain address phase so
add a property to allow device tree to override the default.
Signed-off-by: Mike J. Chen <mjchen@google.com>
Remove the MCTRLDONE wait in mcux_i3c_request_auto_ibi().
I've seen this code getting stuck where the MCTRLDONE
bit is never set in the MSTATUS register by the controller
and this function spins forever. Documentaiton of the
MCTRLDONE bit only mentions it being set for EmitStartAddr
and ProcessDAA, but not for AutoIBI requests.
All the calls to this function do completion checks
afterwards, and with a timeout, so I believe the MCTRLDONE
check is not needed (and may not even be correct).
Signed-off-by: Mike J. Chen <mjchen@google.com>
At high i3c rates, the mcux_i3c_do_one_xfer_read()
could get into an infinite loop where the rx_count
kept returning 0 but the complete status bit
was never set. I believe the problem was that
the function was not emptying the FIFO fast enough,
so tighten the loop that processes the FIFO.
Signed-off-by: Mike J. Chen <mjchen@google.com>
mcux_i3c_configure() was saving values to a ctrl_config_hal
struct, but config_get() was not returning the values in
that struct. Remove that struct from the static data of
the driver and instead just have it on the stack. We init
that struct as needed just before calling the SDK API
I3C_MasterInit(). There's no reason to keep it around.
Change mcux_i3c_configure() to save a copy of the configuration
in the static data common.ctrl_config, which is what is
returned by config_get().
Signed-off-by: Mike J. Chen <mjchen@google.com>
Fixes for bug:
https://github.com/zephyrproject-rtos/zephyr/issues/57560
* don't do CCC if no i3c devices in device tree
* don't wait for MCTRLDONE status when issuing stop
* don't do data part of transfer if buf_sz is 0
* don't limit transfers to only i2c devices in the device tree
so "i2c scan" shell cmd works as expected
Signed-off-by: Mike J. Chen <mjchen@google.com>
The MCUX platform always uses pinctrl, there's no need to keep extra
macrology around pinctrl. Also updated driver's Kconfig options to
`select PINCTRL` (note that some already did).
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
There are some needs to attach and reattach i3c/i2c devices at runtime
Some I2C devices can have special registers where the address can be
changed at runtime. Also some I3C devices can be powered off at runtime
freeing up the address space they take up. These new APIs allow for these
to be changed at runtime. This also moves some config/data in to a common
i3c config/data structure which would allow the api to operate on to be
common for all I3C drivers.
Signed-off-by: Ryan McClelland <ryanmcclelland@meta.com>
Rename is_primary to is_secondary. The justification for this is
because it is less likely to have something configured to be
secondary, and the 0 value would be if it is primary.
Signed-off-by: Ryan McClelland <ryanmcclelland@meta.com>
This adds a very basic driver to utilize the I3C IP block
on MCUX (e.g. RT685). Note that, for now, this only supports
being the active controller on the bus.
Origin: NXP MCUXpresso SDK
License: BSD 3-Clause
URL: https://github.com/zephyrproject-rtos/hal_nxp
Commit: 2302a1e94f5bc00ce59db4e249b688ad2e959f58
Purpose: Enabling the I3C controller on RT685.
Signed-off-by: Daniel Leung <daniel.leung@intel.com>