mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream
@ 2020-07-21  6:14 Ahmad Fatoum
  2020-07-21  6:14 ` [PATCH 2/3] i2c: at91: extend for sama5d2 support Ahmad Fatoum
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2020-07-21  6:14 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

Upstream now has support for i2c-digital-filter-width-ns and
i2c-analog-filter-cutoff-frequency device tree properties, that are
used in an upcoming patch.
Prepare for it by syncing with Linux v5.8-rc4.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/i2c/i2c.c | 73 ++++++++++++++++++++++-------------------------
 include/i2c/i2c.h | 14 +++++++++
 2 files changed, 48 insertions(+), 39 deletions(-)

diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 2fed624d69f9..57d8c7017f4b 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -569,6 +569,18 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 	return to_i2c_client(dev);
 }
 
+static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val_p,
+			    u32 def_val, bool use_def)
+{
+	int ret;
+
+	ret = of_property_read_u32(dev->device_node, prop_name, cur_val_p);
+	if (ret && use_def)
+		*cur_val_p = def_val;
+
+	dev_dbg(dev, "%s: %u\n", prop_name, *cur_val_p);
+}
+
 /**
  * i2c_parse_fw_timings - get I2C related timing parameters from firmware
  * @dev: The device to scan for I2C timing properties
@@ -587,45 +599,28 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 
 void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults)
 {
-	int ret;
-
-	memset(t, 0, sizeof(*t));
-
-	ret = of_property_read_u32(dev->device_node, "clock-frequency",
-				   &t->bus_freq_hz);
-	if (ret && use_defaults)
-		t->bus_freq_hz = 100000;
-
-	ret = of_property_read_u32(dev->device_node, "i2c-scl-rising-time-ns",
-				   &t->scl_rise_ns);
-	if (ret && use_defaults) {
-		if (t->bus_freq_hz <= 100000)
-			t->scl_rise_ns = 1000;
-		else if (t->bus_freq_hz <= 400000)
-			t->scl_rise_ns = 300;
-		else
-			t->scl_rise_ns = 120;
-	}
-
-	ret = of_property_read_u32(dev->device_node, "i2c-scl-falling-time-ns",
-				   &t->scl_fall_ns);
-	if (ret && use_defaults) {
-		if (t->bus_freq_hz <= 400000)
-			t->scl_fall_ns = 300;
-		else
-			t->scl_fall_ns = 120;
-	}
-
-	of_property_read_u32(dev->device_node, "i2c-scl-internal-delay-ns",
-			     &t->scl_int_delay_ns);
-
-	ret = of_property_read_u32(dev->device_node, "i2c-sda-falling-time-ns",
-				   &t->sda_fall_ns);
-	if (ret && use_defaults)
-		t->sda_fall_ns = t->scl_fall_ns;
-
-	of_property_read_u32(dev->device_node, "i2c-sda-hold-time-ns",
-			     &t->sda_hold_ns);
+	bool u = use_defaults;
+	u32 d;
+
+	i2c_parse_timing(dev, "clock-frequency", &t->bus_freq_hz,
+			 I2C_MAX_STANDARD_MODE_FREQ, u);
+
+	d = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 :
+	    t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
+	i2c_parse_timing(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns, d, u);
+
+	d = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120;
+	i2c_parse_timing(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns, d, u);
+
+	i2c_parse_timing(dev, "i2c-scl-internal-delay-ns",
+			 &t->scl_int_delay_ns, 0, u);
+	i2c_parse_timing(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns,
+			 t->scl_fall_ns, u);
+	i2c_parse_timing(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, u);
+	i2c_parse_timing(dev, "i2c-digital-filter-width-ns",
+			 &t->digital_filter_width_ns, 0, u);
+	i2c_parse_timing(dev, "i2c-analog-filter-cutoff-frequency",
+			 &t->analog_filter_cutoff_freq_hz, 0, u);
 }
 EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
 
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index bfc1eab81588..af6287602ca5 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -31,6 +31,14 @@ struct i2c_platform_data {
 	int bitrate;
 };
 
+/* I2C Frequency Modes */
+#define I2C_MAX_STANDARD_MODE_FREQ	100000
+#define I2C_MAX_FAST_MODE_FREQ		400000
+#define I2C_MAX_FAST_MODE_PLUS_FREQ	1000000
+#define I2C_MAX_TURBO_MODE_FREQ		1400000
+#define I2C_MAX_HIGH_SPEED_MODE_FREQ	3400000
+#define I2C_MAX_ULTRA_FAST_MODE_FREQ	5000000
+
 #define I2C_NAME_SIZE	20
 
 #define I2C_M_RD		0x0001	/* read data, from slave to master */
@@ -246,6 +254,10 @@ struct i2c_board_info {
  * @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns
  * @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification
  * @sda_hold_ns: time IP core additionally needs to hold SDA in ns
+ * @digital_filter_width_ns: width in ns of spikes on i2c lines that the IP core
+ *	digital filter can filter out
+ * @analog_filter_cutoff_freq_hz: threshold frequency for the low pass IP core
+ *	analog filter
  */
 struct i2c_timings {
 	u32 bus_freq_hz;
@@ -254,6 +266,8 @@ struct i2c_timings {
 	u32 scl_int_delay_ns;
 	u32 sda_fall_ns;
 	u32 sda_hold_ns;
+	u32 digital_filter_width_ns;
+	u32 analog_filter_cutoff_freq_hz;
 };
 
 /**
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] i2c: at91: extend for sama5d2 support
  2020-07-21  6:14 [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Ahmad Fatoum
@ 2020-07-21  6:14 ` Ahmad Fatoum
  2020-07-21  6:14 ` [PATCH 3/3] mfd: add Atmel Flexcom support Ahmad Fatoum
  2020-08-03 21:33 ` [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2020-07-21  6:14 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

Port over the Linux v5.8-rc4 bits to support i2c on the sama5d2.
This has been tested by reading the i2c EEPROM on the sama5d27-som1-ek.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/i2c/busses/i2c-at91.c | 135 +++++++++++++++++++++++++++++-----
 1 file changed, 116 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 76bb51bf30c2..70e87c1b2cc4 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -48,6 +48,8 @@
 #define	AT91_TWI_IADR		0x000c	/* Internal Address Register */
 
 #define	AT91_TWI_CWGR		0x0010	/* Clock Waveform Generator Reg */
+#define	AT91_TWI_CWGR_HOLD_MAX	0x1f
+#define	AT91_TWI_CWGR_HOLD(x)	(((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
 
 #define	AT91_TWI_SR		0x0020	/* Status Register */
 #define	AT91_TWI_TXCOMP		0x0001	/* Transmission Complete */
@@ -64,14 +66,27 @@
 #define	AT91_TWI_RHR		0x0030	/* Receive Holding Register */
 #define	AT91_TWI_THR		0x0034	/* Transmit Holding Register */
 
+#define AT91_TWI_FILTR		0x0044
+#define AT91_TWI_FILTR_FILT	BIT(0)
+#define AT91_TWI_FILTR_PADFEN	BIT(1)
+#define AT91_TWI_FILTR_THRES(v)		((v) << 8)
+#define AT91_TWI_FILTR_THRES_MAX	7
+#define AT91_TWI_FILTR_THRES_MASK	GENMASK(10, 8)
+
 struct at91_twi_pdata {
 	unsigned clk_max_div;
 	unsigned clk_offset;
 	bool has_unre_flag;
+	bool has_alt_cmd;
+	bool has_hold_field;
+	bool has_dig_filtr;
+	bool has_adv_dig_filtr;
+	bool has_ana_filtr;
+	bool has_clear_cmd;
 };
 
 struct at91_twi_dev {
-	struct device *dev;
+	struct device_d *dev;
 	void __iomem *base;
 	struct clk *clk;
 	u8 *buf;
@@ -82,6 +97,10 @@ struct at91_twi_dev {
 	struct i2c_adapter adapter;
 	unsigned twi_cwgr_reg;
 	struct at91_twi_pdata *pdata;
+	u32 filter_width;
+
+	bool enable_dig_filt;
+	bool enable_ana_filt;
 };
 
 #define to_at91_twi_dev(a) container_of(a, struct at91_twi_dev, adapter)
@@ -104,11 +123,31 @@ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
 
 static void at91_init_twi_bus(struct at91_twi_dev *dev)
 {
+	struct at91_twi_pdata *pdata = dev->pdata;
+	u32 filtr = 0;
+
 	at91_disable_twi_interrupts(dev);
 	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
 	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
 	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
 	at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
+
+	/* enable digital filter */
+	if (pdata->has_dig_filtr && dev->enable_dig_filt)
+		filtr |= AT91_TWI_FILTR_FILT;
+
+	/* enable advanced digital filter */
+	if (pdata->has_adv_dig_filtr && dev->enable_dig_filt)
+		filtr |= AT91_TWI_FILTR_FILT |
+			 (AT91_TWI_FILTR_THRES(dev->filter_width) &
+			 AT91_TWI_FILTR_THRES_MASK);
+
+	/* enable analog filter */
+	if (pdata->has_ana_filtr && dev->enable_ana_filt)
+		filtr |= AT91_TWI_FILTR_PADFEN;
+
+	if (filtr)
+		at91_twi_write(dev, AT91_TWI_FILTR, filtr);
 }
 
 /*
@@ -117,10 +156,13 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev)
  */
 static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
 {
-	int ckdiv, cdiv, div;
+	int ckdiv, cdiv, div, hold = 0, filter_width = 0;
 	struct at91_twi_pdata *pdata = dev->pdata;
 	int offset = pdata->clk_offset;
 	int max_ckdiv = pdata->clk_max_div;
+	struct i2c_timings timings, *t = &timings;
+
+	i2c_parse_fw_timings(dev->dev, t, true);
 
 	div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
 				       2 * twi_clk) - offset);
@@ -128,14 +170,54 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
 	cdiv = div >> ckdiv;
 
 	if (ckdiv > max_ckdiv) {
-		dev_warn(&dev->adapter.dev, "%d exceeds ckdiv max value which is %d.\n",
+		dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
 			 ckdiv, max_ckdiv);
 		ckdiv = max_ckdiv;
 		cdiv = 255;
 	}
 
-	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
-	dev_dbg(&dev->adapter.dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+	if (pdata->has_hold_field) {
+		/*
+		 * hold time = HOLD + 3 x T_peripheral_clock
+		 * Use clk rate in kHz to prevent overflows when computing
+		 * hold.
+		 */
+		hold = DIV_ROUND_UP(t->sda_hold_ns
+				    * (clk_get_rate(dev->clk) / 1000), 1000000);
+		hold -= 3;
+		if (hold < 0)
+			hold = 0;
+		if (hold > AT91_TWI_CWGR_HOLD_MAX) {
+			dev_warn(dev->dev,
+				 "HOLD field set to its maximum value (%d instead of %d)\n",
+				 AT91_TWI_CWGR_HOLD_MAX, hold);
+			hold = AT91_TWI_CWGR_HOLD_MAX;
+		}
+	}
+
+	if (pdata->has_adv_dig_filtr) {
+		/*
+		 * filter width = 0 to AT91_TWI_FILTR_THRES_MAX
+		 * peripheral clocks
+		 */
+		filter_width = DIV_ROUND_UP(t->digital_filter_width_ns
+				* (clk_get_rate(dev->clk) / 1000), 1000000);
+		if (filter_width > AT91_TWI_FILTR_THRES_MAX) {
+			dev_warn(dev->dev,
+				"Filter threshold set to its maximum value (%d instead of %d)\n",
+				AT91_TWI_FILTR_THRES_MAX, filter_width);
+			filter_width = AT91_TWI_FILTR_THRES_MAX;
+		}
+	}
+
+	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
+			    | AT91_TWI_CWGR_HOLD(hold);
+
+	dev->filter_width = filter_width;
+
+	dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns), filter_width %d (%d ns)\n",
+		cdiv, ckdiv, hold, t->sda_hold_ns, filter_width,
+		t->digital_filter_width_ns);
 }
 
 static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
@@ -149,7 +231,7 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
 	if (--dev->buf_len == 0)
 		at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
 
-	dev_dbg(&dev->adapter.dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+	dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
 
 	++dev->buf;
 }
@@ -166,7 +248,7 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
 	if (dev->buf_len == 1)
 		at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
 
-	dev_dbg(&dev->adapter.dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
+	dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
 
 	++dev->buf;
 }
@@ -183,7 +265,7 @@ static int at91_twi_wait_completion(struct at91_twi_dev *dev)
 
 		if (!(status & irqstatus)) {
 			if (is_timeout(start, AT91_I2C_TIMEOUT)) {
-				dev_warn(&dev->adapter.dev, "timeout waiting for bus ready\n");
+				dev_warn(dev->dev, "timeout waiting for bus ready\n");
 				return -ETIMEDOUT;
 			} else {
 				continue;
@@ -195,7 +277,7 @@ static int at91_twi_wait_completion(struct at91_twi_dev *dev)
 		else if (irqstatus & AT91_TWI_TXRDY)
 			at91_twi_write_next_byte(dev);
 		else
-			dev_warn(&dev->adapter.dev, "neither rx and tx are ready\n");
+			dev_warn(dev->dev, "neither rx and tx are ready\n");
 
 		dev->transfer_status |= status;
 
@@ -211,7 +293,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 	int ret;
 	bool has_unre_flag = dev->pdata->has_unre_flag;
 
-	dev_dbg(&dev->adapter.dev, "transfer: %s %d bytes.\n",
+	dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
 		(dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
 
 	dev->transfer_status = 0;
@@ -223,7 +305,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 		unsigned start_flags = AT91_TWI_START;
 
 		if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
-			dev_err(&dev->adapter.dev, "RXRDY still set!");
+			dev_err(dev->dev, "RXRDY still set!");
 			at91_twi_read(dev, AT91_TWI_RHR);
 		}
 
@@ -243,27 +325,27 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 
 	ret = at91_twi_wait_completion(dev);
 	if (ret < 0) {
-		dev_err(&dev->adapter.dev, "controller timed out\n");
+		dev_err(dev->dev, "controller timed out\n");
 		at91_init_twi_bus(dev);
 		ret = -ETIMEDOUT;
 		goto error;
 	}
 	if (dev->transfer_status & AT91_TWI_NACK) {
-		dev_dbg(&dev->adapter.dev, "received nack\n");
+		dev_dbg(dev->dev, "received nack\n");
 		ret = -EREMOTEIO;
 		goto error;
 	}
 	if (dev->transfer_status & AT91_TWI_OVRE) {
-		dev_err(&dev->adapter.dev, "overrun while reading\n");
+		dev_err(dev->dev, "overrun while reading\n");
 		ret = -EIO;
 		goto error;
 	}
 	if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
-		dev_err(&dev->adapter.dev, "underrun while writing\n");
+		dev_err(dev->dev, "underrun while writing\n");
 		ret = -EIO;
 		goto error;
 	}
-	dev_dbg(&dev->adapter.dev, "transfer complete\n");
+	dev_dbg(dev->dev, "transfer complete\n");
 
 	return 0;
 
@@ -285,7 +367,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 	 * repeated start via it's internal address feature.
 	 */
 	if (num > 2) {
-		dev_err(&dev->adapter.dev,
+		dev_err(dev->dev,
 			"cannot handle more than two concatenated messages.\n");
 		return 0;
 	} else if (num == 2) {
@@ -293,11 +375,11 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 		int i;
 
 		if (msg->flags & I2C_M_RD) {
-			dev_err(&dev->adapter.dev, "first transfer must be write.\n");
+			dev_err(dev->dev, "first transfer must be write.\n");
 			return -EINVAL;
 		}
 		if (msg->len > 3) {
-			dev_err(&dev->adapter.dev, "first message size must be <= 3.\n");
+			dev_err(dev->dev, "first message size must be <= 3.\n");
 			return -EINVAL;
 		}
 
@@ -360,6 +442,17 @@ static struct at91_twi_pdata at91sam9x5_config = {
 	.has_unre_flag = false,
 };
 
+static struct at91_twi_pdata sama5d2_config = {
+	.clk_max_div = 7,
+	.clk_offset = 3,
+	.has_unre_flag = true,
+	.has_alt_cmd = true,
+	.has_hold_field = true,
+	.has_dig_filtr = true,
+	.has_adv_dig_filtr = true,
+	.has_ana_filtr = true,
+};
+
 static struct platform_device_id at91_twi_devtypes[] = {
 	{
 		.name = "at91rm9200-i2c",
@@ -403,6 +496,9 @@ static struct of_device_id at91_twi_dt_ids[] = {
 	}, {
 		.compatible = "atmel,at91sam9x5-i2c",
 		.data = &at91sam9x5_config,
+	}, {
+		.compatible = "atmel,sama5d2-i2c",
+		.data = &sama5d2_config,
 	}, {
 		/* sentinel */
 	}
@@ -417,6 +513,7 @@ static int at91_twi_probe(struct device_d *dev)
 	u32 bus_clk_rate;
 
 	i2c_at91 = xzalloc(sizeof(struct at91_twi_dev));
+	i2c_at91->dev = dev;
 
 	rc = dev_get_drvdata(dev, (const void **)&i2c_data);
 	if (rc < 0) {
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] mfd: add Atmel Flexcom support
  2020-07-21  6:14 [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Ahmad Fatoum
  2020-07-21  6:14 ` [PATCH 2/3] i2c: at91: extend for sama5d2 support Ahmad Fatoum
@ 2020-07-21  6:14 ` Ahmad Fatoum
  2020-08-03 21:33 ` [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Fatoum @ 2020-07-21  6:14 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

This is a wrapper which embeds a SPI controller, a I2C controller and
a USART. Only one function can be used at a time. The choice is done
at boot time by the probe function of this MFD driver according to
a device tree property.

These IP cores are available in the sama5d2 and sam9x60. We already have
support for all three configurations, only thing we need is the MFD
selecting one of them. Add this.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 drivers/mfd/Kconfig         | 10 +++++
 drivers/mfd/Makefile        |  1 +
 drivers/mfd/atmel-flexcom.c | 73 +++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
 create mode 100644 drivers/mfd/atmel-flexcom.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d03d481898d8..d7a8949bafc8 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -91,4 +91,14 @@ config MFD_STM32_TIMERS
 	  Select this to get regmap support for the timer blocks on STM32
 	  MCUs and MPUs.
 
+config MFD_ATMEL_FLEXCOM
+	tristate "Atmel Flexcom (Flexible Serial Communication Unit)"
+	depends on OFDEVICE
+	help
+	  Select this to get support for Atmel Flexcom. This is a wrapper
+	  which embeds a SPI controller, a I2C controller and a USART. Only
+	  one function can be used at a time. The choice is done at boot time
+	  by the probe function of this MFD driver according to a device tree
+	  property.
+
 endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a3b296a803f8..690e53693ebc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_MFD_SUPERIO)	+= superio.o
 obj-$(CONFIG_FINTEK_SUPERIO)	+= fintek-superio.o
 obj-$(CONFIG_SMSC_SUPERIO)	+= smsc-superio.o
 obj-$(CONFIG_MFD_STM32_TIMERS)	+= stm32-timers.o
+obj-$(CONFIG_MFD_ATMEL_FLEXCOM)	+= atmel-flexcom.o
diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c
new file mode 100644
index 000000000000..996d4850ee81
--- /dev/null
+++ b/drivers/mfd/atmel-flexcom.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: (C) 2015 Atmel Corporation
+/*
+ * Driver for Atmel Flexcom
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ */
+
+#include <common.h>
+#include <of.h>
+#include <linux/clk.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+/* I/O register offsets */
+#define FLEX_MR		0x0	/* Mode Register */
+#define FLEX_VERSION	0xfc	/* Version Register */
+
+/* Mode Register bit fields */
+#define FLEX_MR_OPMODE_OFFSET	(0)  /* Operating Mode */
+#define FLEX_MR_OPMODE_MASK	(0x3 << FLEX_MR_OPMODE_OFFSET)
+#define FLEX_MR_OPMODE(opmode)	(((opmode) << FLEX_MR_OPMODE_OFFSET) &	\
+				 FLEX_MR_OPMODE_MASK)
+
+static int atmel_flexcom_probe(struct device_d *dev)
+{
+	struct resource *res;
+	struct clk *clk;
+	u32 opmode;
+	int err;
+
+	err = of_property_read_u32(dev->device_node,
+				   "atmel,flexcom-mode", &opmode);
+	if (err)
+		return err;
+
+	if (opmode < ATMEL_FLEXCOM_MODE_USART || opmode > ATMEL_FLEXCOM_MODE_TWI)
+		return -EINVAL;
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	err = clk_enable(clk);
+	if (err)
+		return err;
+
+	/*
+	 * Set the Operating Mode in the Mode Register: only the selected device
+	 * is clocked. Hence, registers of the other serial devices remain
+	 * inaccessible and are read as zero. Also the external I/O lines of the
+	 * Flexcom are muxed to reach the selected device.
+	 */
+	writel(FLEX_MR_OPMODE(opmode), IOMEM(res->start) + FLEX_MR);
+
+	clk_disable(clk);
+
+	return of_platform_populate(dev->device_node, NULL, dev);
+}
+
+static const struct of_device_id atmel_flexcom_of_match[] = {
+	{ .compatible = "atmel,sama5d2-flexcom" },
+	{ /* sentinel */ }
+};
+
+static struct driver_d atmel_flexcom_driver = {
+	.probe		= atmel_flexcom_probe,
+	.name		= "atmel_flexcom",
+	.of_compatible	= atmel_flexcom_of_match,
+};
+coredevice_platform_driver(atmel_flexcom_driver);
-- 
2.27.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream
  2020-07-21  6:14 [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Ahmad Fatoum
  2020-07-21  6:14 ` [PATCH 2/3] i2c: at91: extend for sama5d2 support Ahmad Fatoum
  2020-07-21  6:14 ` [PATCH 3/3] mfd: add Atmel Flexcom support Ahmad Fatoum
@ 2020-08-03 21:33 ` Sascha Hauer
  2 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2020-08-03 21:33 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: barebox

On Tue, Jul 21, 2020 at 08:14:56AM +0200, Ahmad Fatoum wrote:
> Upstream now has support for i2c-digital-filter-width-ns and
> i2c-analog-filter-cutoff-frequency device tree properties, that are
> used in an upcoming patch.
> Prepare for it by syncing with Linux v5.8-rc4.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
>  drivers/i2c/i2c.c | 73 ++++++++++++++++++++++-------------------------
>  include/i2c/i2c.h | 14 +++++++++
>  2 files changed, 48 insertions(+), 39 deletions(-)

Applied, thanks

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-08-03 21:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-21  6:14 [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Ahmad Fatoum
2020-07-21  6:14 ` [PATCH 2/3] i2c: at91: extend for sama5d2 support Ahmad Fatoum
2020-07-21  6:14 ` [PATCH 3/3] mfd: add Atmel Flexcom support Ahmad Fatoum
2020-08-03 21:33 ` [PATCH 1/3] i2c: sync i2c_parse_fw_timings() with upstream Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox