2022-04-11 19:36:19

by Lucas Tanure

[permalink] [raw]
Subject: [PATCH v2 0/2] Ensure High and Low periods of SCL are correct

The default duty cycle of 33% is less than the required
by the I2C specs for the LOW period of the SCL clock at
100KHz bus speed.

So, for 100Khz or less, use 50%H/50%L duty cycle, and
for the clock above 100Khz, use 40%H/60%L duty cycle.
That ensures the low period of SCL is always more than
the minimum required by the specs at any given frequency.

I did a few measures on the Khadas Vim3 board:

i2c_AO (i2c@5000):

Before the patchset, I got:
- 100KHz: 3.338us HIGH, 6.746us LOW, 33%/67%, Freq 99KHz (Not Valid tHIGH < 4.0us)
- 400KHz: 860ns HIGH, 1.734us LOW, 33.15%/62.85%, Freq 385.505KHz (Valid)
- 1000KHz: 362ns HIGH, 732ns LOW, 33.09%/66.91%, Freq 914.077KHz (Valid)

With the patchset
- 100KHz: 4.952us HIGH, 5.134us LOW, 49%/51%, Freq 99KHz (Valid)
- 400KHz: 966ns HIGH, 1.628us LOW, 37.24%/62.76%, Freq 385.505KHz (Valid)
- 1000KHz: 372ns HIGH, 720ns LOW, 34.07%/65.93%, Freq 915.741KHz (Valid)

i2c3 (i2c@1c000):

Before the patchset, I got:
- 100KHz: 3.348us HIGH, 6.704us LOW, 33%/67%, Freq 99.5KHz (Not Valid tHIGH < 4.0us)
- 400KHz: 864ns HIGH, 1.69us LOW, 33.83%/62.17%, Freq 391.543KHz (Valid)
- 1000KHz: 360ns HIGH, 690ns LOW, 34.29%/65.71%, Freq 952.381KHz (Valid)

With the patchset
- 100KHz: 4.958us HIGH, 5.092us LOW, 49%/51%, Freq 99KHz (Valid)
- 400KHz: 970ns HIGH, 1.582us LOW, 38%/62%, Freq 391.85KHz (Valid)
- 1000KHz: 370ns HIGH, 680ns LOW, 35.24%/64.76%, Freq 952.57KHz (Valid)

v2 changelog:
- Keep the previous calculation for Meson6
- Use I2C_MAX_STANDARD_MODE_FREQ
- move the comment before the if()
- use FIELD_PREP for setting div_l
- Drop removal of meson_i2c_data

Previous versions:
V1: https://lkml.org/lkml/2022/3/26/109

Lucas Tanure (2):
i2c: meson: Use _SHIFT and _MASK for register definitions
i2c: meson: Use 50% duty cycle for I2C clock

drivers/i2c/busses/i2c-meson.c | 111 ++++++++++++++++++++++++---------
1 file changed, 82 insertions(+), 29 deletions(-)

--
2.35.1


2022-04-12 21:18:29

by Lucas Tanure

[permalink] [raw]
Subject: [PATCH v2 1/2] i2c: meson: Use _SHIFT and _MASK for register definitions

Differentiate between masks and shifts

Signed-off-by: Lucas Tanure <[email protected]>
---
drivers/i2c/busses/i2c-meson.c | 41 ++++++++++++++++++----------------
1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 07eb819072c4..4b4a5b2d77ab 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -30,18 +30,21 @@
#define REG_TOK_RDATA1 0x1c

/* Control register fields */
-#define REG_CTRL_START BIT(0)
-#define REG_CTRL_ACK_IGNORE BIT(1)
-#define REG_CTRL_STATUS BIT(2)
-#define REG_CTRL_ERROR BIT(3)
-#define REG_CTRL_CLKDIV GENMASK(21, 12)
-#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)
-
-#define REG_SLV_ADDR GENMASK(7, 0)
-#define REG_SLV_SDA_FILTER GENMASK(10, 8)
-#define REG_SLV_SCL_FILTER GENMASK(13, 11)
-#define REG_SLV_SCL_LOW GENMASK(27, 16)
-#define REG_SLV_SCL_LOW_EN BIT(28)
+#define REG_CTRL_START BIT(0)
+#define REG_CTRL_ACK_IGNORE BIT(1)
+#define REG_CTRL_STATUS BIT(2)
+#define REG_CTRL_ERROR BIT(3)
+#define REG_CTRL_CLKDIV_SHIFT 12
+#define REG_CTRL_CLKDIV_MASK GENMASK(21, REG_CTRL_CLKDIV_SHIFT)
+#define REG_CTRL_CLKDIVEXT_SHIFT 28
+#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, REG_CTRL_CLKDIVEXT_SHIFT)
+
+#define REG_SLV_ADDR_MASK GENMASK(7, 0)
+#define REG_SLV_SDA_FILTER_MASK GENMASK(10, 8)
+#define REG_SLV_SCL_FILTER_MASK GENMASK(13, 11)
+#define REG_SLV_SCL_LOW_SHIFT 16
+#define REG_SLV_SCL_LOW_MASK GENMASK(27, REG_SLV_SCL_LOW_SHIFT)
+#define REG_SLV_SCL_LOW_EN BIT(28)

#define I2C_TIMEOUT_MS 500
#define FILTER_DELAY 15
@@ -149,11 +152,11 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
div = GENMASK(11, 0);
}

- meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
- FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
+ FIELD_PREP(REG_CTRL_CLKDIV_MASK, div & GENMASK(9, 0)));

- meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
- FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
+ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
+ FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div >> 10));

/* Disable HIGH/LOW mode */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
@@ -292,8 +295,8 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
TOKEN_SLAVE_ADDR_WRITE;


- meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
- FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
+ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR_MASK,
+ FIELD_PREP(REG_SLV_ADDR_MASK, msg->addr << 1));

meson_i2c_add_token(i2c, TOKEN_START);
meson_i2c_add_token(i2c, token);
@@ -467,7 +470,7 @@ static int meson_i2c_probe(struct platform_device *pdev)

/* Disable filtering */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
- REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
+ REG_SLV_SDA_FILTER_MASK | REG_SLV_SCL_FILTER_MASK, 0);

meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);

--
2.35.1

2022-04-12 23:13:04

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] i2c: meson: Use _SHIFT and _MASK for register definitions

On 09/04/2022 18:43, Lucas Tanure wrote:
> Differentiate between masks and shifts
>
> Signed-off-by: Lucas Tanure <[email protected]>
> ---
> drivers/i2c/busses/i2c-meson.c | 41 ++++++++++++++++++----------------
> 1 file changed, 22 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
> index 07eb819072c4..4b4a5b2d77ab 100644
> --- a/drivers/i2c/busses/i2c-meson.c
> +++ b/drivers/i2c/busses/i2c-meson.c
> @@ -30,18 +30,21 @@
> #define REG_TOK_RDATA1 0x1c
>
> /* Control register fields */
> -#define REG_CTRL_START BIT(0)
> -#define REG_CTRL_ACK_IGNORE BIT(1)
> -#define REG_CTRL_STATUS BIT(2)
> -#define REG_CTRL_ERROR BIT(3)
> -#define REG_CTRL_CLKDIV GENMASK(21, 12)
> -#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)
> -
> -#define REG_SLV_ADDR GENMASK(7, 0)
> -#define REG_SLV_SDA_FILTER GENMASK(10, 8)
> -#define REG_SLV_SCL_FILTER GENMASK(13, 11)
> -#define REG_SLV_SCL_LOW GENMASK(27, 16)
> -#define REG_SLV_SCL_LOW_EN BIT(28)
> +#define REG_CTRL_START BIT(0)
> +#define REG_CTRL_ACK_IGNORE BIT(1)
> +#define REG_CTRL_STATUS BIT(2)
> +#define REG_CTRL_ERROR BIT(3)
> +#define REG_CTRL_CLKDIV_SHIFT 12
> +#define REG_CTRL_CLKDIV_MASK GENMASK(21, REG_CTRL_CLKDIV_SHIFT)
> +#define REG_CTRL_CLKDIVEXT_SHIFT 28
> +#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, REG_CTRL_CLKDIVEXT_SHIFT)
> +
> +#define REG_SLV_ADDR_MASK GENMASK(7, 0)
> +#define REG_SLV_SDA_FILTER_MASK GENMASK(10, 8)
> +#define REG_SLV_SCL_FILTER_MASK GENMASK(13, 11)
> +#define REG_SLV_SCL_LOW_SHIFT 16
> +#define REG_SLV_SCL_LOW_MASK GENMASK(27, REG_SLV_SCL_LOW_SHIFT)
> +#define REG_SLV_SCL_LOW_EN BIT(28)
>
> #define I2C_TIMEOUT_MS 500
> #define FILTER_DELAY 15
> @@ -149,11 +152,11 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
> div = GENMASK(11, 0);
> }
>
> - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
> - FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
> + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
> + FIELD_PREP(REG_CTRL_CLKDIV_MASK, div & GENMASK(9, 0)));
>
> - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
> - FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
> + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
> + FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div >> 10));
>
> /* Disable HIGH/LOW mode */
> meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
> @@ -292,8 +295,8 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
> TOKEN_SLAVE_ADDR_WRITE;
>
>
> - meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
> - FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
> + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR_MASK,
> + FIELD_PREP(REG_SLV_ADDR_MASK, msg->addr << 1));
>
> meson_i2c_add_token(i2c, TOKEN_START);
> meson_i2c_add_token(i2c, token);
> @@ -467,7 +470,7 @@ static int meson_i2c_probe(struct platform_device *pdev)
>
> /* Disable filtering */
> meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
> - REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
> + REG_SLV_SDA_FILTER_MASK | REG_SLV_SCL_FILTER_MASK, 0);
>
> meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
>

Reviewed-by: Neil Armstrong <[email protected]>

2022-04-16 01:36:54

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] i2c: meson: Use _SHIFT and _MASK for register definitions

On Sat, Apr 09, 2022 at 05:43:33PM +0100, Lucas Tanure wrote:
> Differentiate between masks and shifts
>
> Signed-off-by: Lucas Tanure <[email protected]>

Applied to for-next, thanks!


Attachments:
(No filename) (193.00 B)
signature.asc (849.00 B)
Download all attachments