Hi! Alex.
Thanks for ur detailed review.
On 2025/2/12 05:39, Alex Elder wrote:
On 11/25/24 12:49 AM, Troy Mitchell wrote:
From: Troy Mitchell <troymitchell988@xxxxxxxxx>
This patch introduces basic I2C support for the SpacemiT K1 SoC,
utilizing interrupts for transfers.
The driver has been tested using i2c-tools on a Bananapi-F3 board,
and basic I2C read/write operations have been confirmed to work.
Signed-off-by: Troy Mitchell <TroyMitchell988@xxxxxxxxx>
The descriptions below are also good. Maybe be consistentYes. The above is to explain the full name.
with your capitalization in comments? (Though I suppose
the capitalization above is to explain the name of the
register.)
So I still need to keep them consistent?
+#define CR_START BIT(0) /* start bit */
+#define CR_STOP BIT(1) /* stop bit */
For the *IE symbols that follow, why not use *_IE as the specThe symbols follow the datasheet of SpacemiT.
does?
Even if the data sheet doesn't have IE, should I add it myself?
+#define CR_ALDIE BIT(18) /* enable arbitration interrupt */
+#define CR_DTEIE BIT(19) /* enable tx interrupts */
+#define CR_DRFIE BIT(20) /* enable rx interrupts */
Is it simply assumed to be already configured that way? (Thisyes. by dts.
driver doesn't set it at initialization time.) Someday
we should set things up explicitly.
I will handle frequency that is from dts in next version.
The only place the next symbol is used is in computing aYes, but I wanna explain the freq number is fast mode.
custom timeout period before initiating a transfer.
So I define it here.
But don't worry, I will drop it in next version and accept freq from dts.
The next function only resets the bus if it's not idle (whereHow about `spacemit_i2c_conditional_reset`?
"idle" means both SCL and SDA are high). Based on the name
of the function, I'd expect it to always reset. In other
words, I'd rather this be named something slightly different,
or have the check of SDA and SCL be done in the caller(s).
Because I am worried that in the future, when the fifo or other reset is called,
SDA and SCL will always be checked.
The register value is always returned directly。+static void spacemit_i2c_bus_reset(struct spacemit_i2c_dev *i2c)
+{
+ u32 status;
+
+ /* if bus is locked, reset unit. 0: locked */
+ status = readl(i2c->base + IBMR);
+ if ((status & BMR_SDA) && (status & BMR_SCL))
+ return;
+
+ spacemit_i2c_reset(i2c);
+ usleep_range(10, 20);
+
+ /* check scl status again */
+ status = readl(i2c->base + IBMR);
+ if (!(status & BMR_SCL))
+ dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
+}
+
+static int spacemit_i2c_recover_bus_busy(struct spacemit_i2c_dev *i2c)
+{
+ int ret = 0;
+ u32 val;
+
I think the next 4 lines can be deleted. The readl_poll_timeout()
immediately does what they do, without delay.
but it needs to be judged if the bus is busy by !(val & (SR_UB | SR_IBB).
I will drop it.
+ val = readl(i2c->base + ISR);
+ if (likely(!(val & (SR_UB | SR_IBB))))
+ return 0;
+
+ ret = readl_poll_timeout(i2c->base + ISR, val, !(val & (SR_UB | SR_IBB)),
+ 1500, I2C_BUS_RECOVER_TIMEOUT);
+ if (unlikely(ret)) {
+ spacemit_i2c_reset(i2c);
If readl_poll_timeout() returns non-zero, it is -ETIMEDOUT.
Why change it to -EAGAIN? (It ultimately gets consumed by
spacemit_i2c_xfer(), which handles -ETIMEDOUT and -EAGAIN
identically.
The following function is used in two places, but I don't thinkI want to explain more clearly what is done in the init phase, so I put them
it really adds any value. Just open-code the writel() call in
those two spots.
into a function and assign values step by step.
Is it not necessary?
or maybe I can add `inline`.
+static inline void
+spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
+{
+ writel(mask & I2C_INT_STATUS_MASK, i2c->base + ISR);
+}