[PATCH] i2c: stm32f7: SYSCFG Fast Mode Plus support for I2C STM32F7

Read SYSCFG bindings to set Fast Mode Plus bits if Fast Mode Plus speed is selected.
Handle the stm32mp15 specific compatible to handle FastMode+ registers handling which is different on the stm32mp15 compared to the stm32f7 or stm32h7. Indeed, on the stm32mp15, the FastMode+ set and clear registers are separated while on the other platforms (F7 or H7) the control is done in a unique register.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com ---
drivers/i2c/stm32f7_i2c.c | 74 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 593f713d6b..2f60911549 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -8,7 +8,9 @@ #include <dm.h> #include <i2c.h> #include <log.h> +#include <regmap.h> #include <reset.h> +#include <syscon.h> #include <linux/bitops.h> #include <linux/delay.h>
@@ -154,6 +156,7 @@ struct stm32_i2c_spec { * @fall_time: Fall time (ns) * @dnf: Digital filter coefficient (0-16) * @analog_filter: Analog filter delay (On/Off) + * @fmp_clr_offset: Fast Mode Plus clear register offset from set register */ struct stm32_i2c_setup { u32 speed_freq; @@ -162,6 +165,7 @@ struct stm32_i2c_setup { u32 fall_time; u8 dnf; bool analog_filter; + u32 fmp_clr_offset; };
/** @@ -181,11 +185,26 @@ struct stm32_i2c_timings { u8 scll; };
+/** + * struct stm32_i2c_priv - private data of the controller + * @regs: I2C registers address + * @clk: hw i2c clock + * @setup: I2C timing setup parameters + * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+ + * @regmap: holds SYSCFG phandle for Fast Mode Plus bit + * @regmap_sreg: register address for setting Fast Mode Plus bits + * @regmap_creg: register address for clearing Fast Mode Plus bits + * @regmap_mask: mask for Fast Mode Plus bits + */ struct stm32_i2c_priv { struct stm32_i2c_regs *regs; struct clk clk; struct stm32_i2c_setup *setup; u32 speed; + struct regmap *regmap; + u32 regmap_sreg; + u32 regmap_creg; + u32 regmap_mask; };
static const struct stm32_i2c_spec i2c_specs[] = { @@ -237,6 +256,14 @@ static const struct stm32_i2c_setup stm32f7_setup = { .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE, };
+static const struct stm32_i2c_setup stm32mp15_setup = { + .rise_time = STM32_I2C_RISE_TIME_DEFAULT, + .fall_time = STM32_I2C_FALL_TIME_DEFAULT, + .dnf = STM32_I2C_DNF_DEFAULT, + .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE, + .fmp_clr_offset = 0x40, +}; + static int stm32_i2c_check_device_busy(struct stm32_i2c_priv *i2c_priv) { struct stm32_i2c_regs *regs = i2c_priv->regs; @@ -761,6 +788,29 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, return 0; }
+static int stm32_i2c_write_fm_plus_bits(struct stm32_i2c_priv *i2c_priv) +{ + int ret; + bool enable = i2c_priv->speed > I2C_SPEED_FAST_RATE; + + /* Optional */ + if (IS_ERR_OR_NULL(i2c_priv->regmap)) + return 0; + + if (i2c_priv->regmap_sreg == i2c_priv->regmap_creg) + ret = regmap_update_bits(i2c_priv->regmap, + i2c_priv->regmap_sreg, + i2c_priv->regmap_mask, + enable ? i2c_priv->regmap_mask : 0); + else + ret = regmap_write(i2c_priv->regmap, + enable ? i2c_priv->regmap_sreg : + i2c_priv->regmap_creg, + i2c_priv->regmap_mask); + + return ret; +} + static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv) { struct stm32_i2c_regs *regs = i2c_priv->regs; @@ -775,6 +825,11 @@ static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv) /* Disable I2C */ clrbits_le32(®s->cr1, STM32_I2C_CR1_PE);
+ /* Setup Fast mode plus if necessary */ + ret = stm32_i2c_write_fm_plus_bits(i2c_priv); + if (ret) + return ret; + /* Timing settings */ timing |= STM32_I2C_TIMINGR_PRESC(t.presc); timing |= STM32_I2C_TIMINGR_SCLDEL(t.scldel); @@ -850,6 +905,7 @@ static int stm32_ofdata_to_platdata(struct udevice *dev) { struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev); u32 rise_time, fall_time; + int ret;
i2c_priv->setup = (struct stm32_i2c_setup *)dev_get_driver_data(dev); if (!i2c_priv->setup) @@ -863,6 +919,22 @@ static int stm32_ofdata_to_platdata(struct udevice *dev) if (fall_time) i2c_priv->setup->fall_time = fall_time;
+ /* Optional */ + i2c_priv->regmap = syscon_regmap_lookup_by_phandle(dev, + "st,syscfg-fmp"); + if (!IS_ERR(i2c_priv->regmap)) { + u32 fmp[3]; + + ret = dev_read_u32_array(dev, "st,syscfg-fmp", fmp, 3); + if (ret) + return ret; + + i2c_priv->regmap_sreg = fmp[1]; + i2c_priv->regmap_creg = fmp[1] + + i2c_priv->setup->fmp_clr_offset; + i2c_priv->regmap_mask = fmp[2]; + } + return 0; }
@@ -873,7 +945,7 @@ static const struct dm_i2c_ops stm32_i2c_ops = {
static const struct udevice_id stm32_i2c_of_match[] = { { .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup }, - { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32f7_setup }, + { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32mp15_setup }, {} };

Hello Patrick,
Am 06.07.2020 um 13:31 schrieb Patrick Delaunay:
Read SYSCFG bindings to set Fast Mode Plus bits if Fast Mode Plus speed is selected.
Handle the stm32mp15 specific compatible to handle FastMode+ registers handling which is different on the stm32mp15 compared to the stm32f7 or stm32h7. Indeed, on the stm32mp15, the FastMode+ set and clear registers are separated while on the other platforms (F7 or H7) the control is done in a unique register.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com
drivers/i2c/stm32f7_i2c.c | 74 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-)
Just tried to apply your patch on current mainline, but this fails for me, reason is missing patch:
http://patchwork.ozlabs.org/project/uboot/patch/20200706112653.18951-2-patri...
So I add this patch also to my repo, if nobody has objections.
Beside of this:
Reviewed-by: Heiko Schocher hs@denx.de
Thanks!
bye, Heiko

Hi Heiko
From: Heiko Schocher hs@denx.de Sent: mardi 7 juillet 2020 07:21
Hello Patrick,
Am 06.07.2020 um 13:31 schrieb Patrick Delaunay:
Read SYSCFG bindings to set Fast Mode Plus bits if Fast Mode Plus speed is selected.
Handle the stm32mp15 specific compatible to handle FastMode+ registers handling which is different on the stm32mp15 compared to the stm32f7 or stm32h7. Indeed, on the stm32mp15, the FastMode+ set and clear registers are separated while on the other platforms (F7 or H7) the control is done in a unique register.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com
drivers/i2c/stm32f7_i2c.c | 74
++++++++++++++++++++++++++++++++++++++-
1 file changed, 73 insertions(+), 1 deletion(-)
Just tried to apply your patch on current mainline, but this fails for me, reason is missing patch:
http://patchwork.ozlabs.org/project/uboot/patch/20200706112653.18951-2- patrick.delaunay@st.com/
So I add this patch also to my repo, if nobody has objections.
No objection for me (as u-boot stm32 custodians / shared with Patrice Chotard), You can take the in tiny patch in your repo.
I delegate the serie to Patrice only to have a review before merge this serie in stm32 tree. But he is in holiday... and I wait him for my next pull request (including this serie).
Beside of this:
Reviewed-by: Heiko Schocher hs@denx.de
Thanks.
Thanks!
bye, Heiko
Regards, Patrick
-- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs@denx.de

Hello Patrick,
Am 06.07.2020 um 13:31 schrieb Patrick Delaunay:
Read SYSCFG bindings to set Fast Mode Plus bits if Fast Mode Plus speed is selected.
Handle the stm32mp15 specific compatible to handle FastMode+ registers handling which is different on the stm32mp15 compared to the stm32f7 or stm32h7. Indeed, on the stm32mp15, the FastMode+ set and clear registers are separated while on the other platforms (F7 or H7) the control is done in a unique register.
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com
drivers/i2c/stm32f7_i2c.c | 74 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-)
Applied to u-boot-i2c.git master
Thanks!
bye, Heiko
participants (3)
-
Heiko Schocher
-
Patrick DELAUNAY
-
Patrick Delaunay