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

Patrick Delaunay patrick.delaunay at st.com
Mon Jul 6 13:31:35 CEST 2020


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 at 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(&regs->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 },
 	{}
 };
 
-- 
2.17.1



More information about the U-Boot mailing list