From: Eugen Hristev <[email protected]>
Hello,
This series adds support for analog and digital filters for i2c controllers
This series is based on the series:
[PATCH v2 0/9] i2c: at91: filters support for at91 SoCs
and enhanced to add the bindings for all controllers plus an extra binding
for the width of the spikes in nanoseconds.
First, bindings are created for
'i2c-analog-filter'
'i2c-digital-filter'
'i2c-filter-width-ns'
The support is added in the i2c core to retrieve filter width and add it
to the timings structure.
Next, the at91 driver is enhanced for supporting digital filter, advanced
digital filter (with selectable spike width) and the analog filter.
Finally the device tree for two boards are modified to make use of the
new properties.
This series is the result of the comments on the ML in the direction
requested: to make the bindings globally available for i2c drivers.
Changes in v4:
- renamed i2c-ana-filter to i2c-analog-filter
- renamed i2c-dig-filter to i2c-digital-filter
Changes in v3:
- made bindings global for i2c controllers and modified accordingly
- gave up PADFCDF bit because it's a lack in datasheet
- the computation on the width of the spike is based on periph clock as it
is done for hold time.
Changes in v2:
- added device tree bindings and support for enable-ana-filt and
enable-dig-filt
- added the new properties to the DT for sama5d4_xplained/sama5d2_xplained
Eugen Hristev (9):
dt-bindings: i2c: at91: add new compatible
dt-bindings: i2c: add bindings for i2c analog and digital filter
i2c: add support for filter-width-ns optional property
i2c: at91: add new platform support for sam9x60
i2c: at91: add support for digital filtering
i2c: at91: add support for advanced digital filtering
i2c: at91: add support for analog filtering
ARM: dts: at91: sama5d2_xplained: add analog and digital filter for
i2c
ARM: dts: at91: sama5d4_xplained: add digital filter for i2c
Documentation/devicetree/bindings/i2c/i2c-at91.txt | 3 +-
Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++
arch/arm/boot/dts/at91-sama5d2_xplained.dts | 6 +++
arch/arm/boot/dts/at91-sama5d4_xplained.dts | 1 +
drivers/i2c/busses/i2c-at91-core.c | 38 +++++++++++++++++
drivers/i2c/busses/i2c-at91-master.c | 49 ++++++++++++++++++++--
drivers/i2c/busses/i2c-at91.h | 13 ++++++
drivers/i2c/i2c-core-base.c | 2 +
include/linux/i2c.h | 2 +
9 files changed, 121 insertions(+), 4 deletions(-)
--
2.7.4
From: Eugen Hristev <[email protected]>
Some i2c controllers have a built-in digital or analog filter.
This is specifically required depending on the hardware PCB/board.
Some controllers also allow specifying the maximum width of the
spikes that can be filtered. The width length can be specified in nanoseconds.
Signed-off-by: Eugen Hristev <[email protected]>
---
Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
index 44efafd..8dbff67 100644
--- a/Documentation/devicetree/bindings/i2c/i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c.txt
@@ -55,6 +55,17 @@ wants to support one of the below features, it should adapt the bindings below.
Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
specification.
+- i2c-analog-filter
+ Enable analog filter for i2c lines.
+
+- i2c-digital-filter
+ Enable digital filter for i2c lines.
+
+- i2c-filter-width-ns
+ Width of spikes which can be filtered by either digital or analog
+ filters (i2c-analog-filtr or i2c-digital-filtr). This width is specified
+ in nanoseconds.
+
- interrupts
interrupts used by the device.
--
2.7.4
From: Eugen Hristev <[email protected]>
Add compatible for new Microchip SoC, sam9x60
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Eugen Hristev <[email protected]>
---
Documentation/devicetree/bindings/i2c/i2c-at91.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
index b7cec17..2210f43 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
@@ -3,7 +3,8 @@ I2C for Atmel platforms
Required properties :
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
- "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
+ "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
+ "microchip,sam9x60-i2c"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
--
2.7.4
From: Eugen Hristev <[email protected]>
Add new platform data support for the sam9x60 SoC
Signed-off-by: Eugen Hristev <[email protected]>
---
drivers/i2c/busses/i2c-at91-core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c
index 435c7d7..caf1846 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -148,6 +148,14 @@ static struct at91_twi_pdata sama5d2_config = {
.has_hold_field = true,
};
+static struct at91_twi_pdata sam9x60_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = true,
+ .has_alt_cmd = true,
+ .has_hold_field = true,
+};
+
static const struct of_device_id atmel_twi_dt_ids[] = {
{
.compatible = "atmel,at91rm9200-i2c",
@@ -174,6 +182,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
.compatible = "atmel,sama5d2-i2c",
.data = &sama5d2_config,
}, {
+ .compatible = "microchip,sam9x60-i2c",
+ .data = &sam9x60_config,
+ }, {
/* sentinel */
}
};
--
2.7.4
From: Eugen Hristev <[email protected]>
Add support for analog filtering for i2c lines.
The sama5d2 and sam9x60 support this feature.
Signed-off-by: Eugen Hristev <[email protected]>
---
drivers/i2c/busses/i2c-at91-core.c | 9 +++++++++
drivers/i2c/busses/i2c-at91-master.c | 18 ++++++++++++++----
drivers/i2c/busses/i2c-at91.h | 3 +++
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c
index 1f4ee7e..e13af48 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -70,6 +70,7 @@ static struct at91_twi_pdata at91rm9200_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata at91sam9261_config = {
@@ -80,6 +81,7 @@ static struct at91_twi_pdata at91sam9261_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata at91sam9260_config = {
@@ -90,6 +92,7 @@ static struct at91_twi_pdata at91sam9260_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
@@ -100,6 +103,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
@@ -110,6 +114,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static const struct platform_device_id at91_twi_devtypes[] = {
@@ -142,6 +147,7 @@ static struct at91_twi_pdata at91sam9x5_config = {
.has_hold_field = false,
.has_dig_filtr = false,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata sama5d4_config = {
@@ -152,6 +158,7 @@ static struct at91_twi_pdata sama5d4_config = {
.has_hold_field = true,
.has_dig_filtr = true,
.has_adv_dig_filtr = false,
+ .has_ana_filtr = false,
};
static struct at91_twi_pdata sama5d2_config = {
@@ -162,6 +169,7 @@ static struct at91_twi_pdata sama5d2_config = {
.has_hold_field = true,
.has_dig_filtr = true,
.has_adv_dig_filtr = true,
+ .has_ana_filtr = true,
};
static struct at91_twi_pdata sam9x60_config = {
@@ -172,6 +180,7 @@ static struct at91_twi_pdata sam9x60_config = {
.has_hold_field = true,
.has_dig_filtr = true,
.has_adv_dig_filtr = true,
+ .has_ana_filtr = true,
};
static const struct of_device_id atmel_twi_dt_ids[] = {
diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c
index 078bbde..68e1ca7 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -32,6 +32,7 @@
void at91_init_twi_bus_master(struct at91_twi_dev *dev)
{
struct at91_twi_pdata *pdata = dev->pdata;
+ u32 filtr = 0;
/* FIFO should be enabled immediately after the software reset */
if (dev->fifo_size)
@@ -42,13 +43,20 @@ void at91_init_twi_bus_master(struct at91_twi_dev *dev)
/* enable digital filter */
if (pdata->has_dig_filtr && dev->enable_dig_filt)
- at91_twi_write(dev, AT91_TWI_FILTR, AT91_TWI_FILTR_FILT);
+ filtr |= AT91_TWI_FILTR_FILT;
/* enable advanced digital filter */
if (pdata->has_adv_dig_filtr && dev->enable_dig_filt)
- at91_twi_write(dev, AT91_TWI_FILTR, AT91_TWI_FILTR_FILT |
- (AT91_TWI_FILTR_THRES(dev->filter_width) &
- AT91_TWI_FILTR_THRES_MASK));
+ 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);
}
/*
@@ -826,6 +834,8 @@ int at91_twi_probe_master(struct platform_device *pdev,
dev->enable_dig_filt = of_property_read_bool(pdev->dev.of_node,
"i2c-digital-filter");
+ dev->enable_ana_filt = of_property_read_bool(pdev->dev.of_node,
+ "i2c-analog-filter");
at91_calc_twi_clock(dev);
dev->adapter.algo = &at91_twi_algorithm;
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index d7cf01e3..977a67b 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -86,6 +86,7 @@
#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)
@@ -116,6 +117,7 @@ struct at91_twi_pdata {
bool has_hold_field;
bool has_dig_filtr;
bool has_adv_dig_filtr;
+ bool has_ana_filtr;
struct at_dma_slave dma_slave;
};
@@ -154,6 +156,7 @@ struct at91_twi_dev {
struct i2c_client *slave;
#endif
bool enable_dig_filt;
+ bool enable_ana_filt;
u32 filter_width;
};
--
2.7.4
From: Eugen Hristev <[email protected]>
Add property for analog and digital filter for i2c1 and i2c2 nodes
for sama5d2_xplained
Signed-off-by: Eugen Hristev <[email protected]>
---
arch/arm/boot/dts/at91-sama5d2_xplained.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index 808e399..2083585 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -334,6 +334,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flx4_default>;
atmel,fifo-size = <16>;
+ i2c-analog-filter;
+ i2c-digital-filter;
+ i2c-filter-width-ns = <35>;
status = "okay";
};
};
@@ -342,6 +345,9 @@
dmas = <0>, <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_default>;
+ i2c-analog-filter;
+ i2c-digital-filter;
+ i2c-filter-width-ns = <35>;
status = "okay";
at24@54 {
--
2.7.4
On 2019-09-02 12:11, [email protected] wrote:
> From: Eugen Hristev <[email protected]>
>
> Add compatible for new Microchip SoC, sam9x60
>
> Reviewed-by: Rob Herring <[email protected]>
> Signed-off-by: Eugen Hristev <[email protected]>
> ---
> Documentation/devicetree/bindings/i2c/i2c-at91.txt | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
> index b7cec17..2210f43 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
> @@ -3,7 +3,8 @@ I2C for Atmel platforms
> Required properties :
> - compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
> "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
> - "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
> + "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
> + "microchip,sam9x60-i2c"
IIUC, this list should ideally be reformatted with one compatible per line.
Side note; unfortunate naming with SAM9x60, when there is a preexisting 9260
fitting the "wildcard" (AFAICT, it's not a wildcard in this case, but it sure
looks like one).
Cheers,
Peter
> - reg: physical base address of the controller and length of memory mapped
> region.
> - interrupts: interrupt number to the cpu.
>
From: Eugen Hristev <[email protected]>
This optional timing property specifies the width of the spikes on the i2c
lines (in ns) that can be filtered out by built-in analog or digital filters
which are embedded in some i2c controllers.
Include it in the timings structure and read it as integer property.
Signed-off-by: Eugen Hristev <[email protected]>
---
drivers/i2c/i2c-core-base.c | 2 ++
include/linux/i2c.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index f26ed49..804197e 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1658,6 +1658,8 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de
t->sda_fall_ns = t->scl_fall_ns;
device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns);
+
+ device_property_read_u32(dev, "i2c-filter-width-ns", &t->filter_width_ns);
}
EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index fa5552c..b1e9c39 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -575,6 +575,7 @@ struct i2c_lock_operations {
* @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
+ * @filter_width_ns: width in ns of spikes on i2c lines that the IP core can filter out
*/
struct i2c_timings {
u32 bus_freq_hz;
@@ -583,6 +584,7 @@ struct i2c_timings {
u32 scl_int_delay_ns;
u32 sda_fall_ns;
u32 sda_hold_ns;
+ u32 filter_width_ns;
};
/**
--
2.7.4
From: Eugen Hristev <[email protected]>
Add property for digital filter for i2c0 node sama5d4_xplained
Signed-off-by: Eugen Hristev <[email protected]>
---
arch/arm/boot/dts/at91-sama5d4_xplained.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
index fdfc37d..924d949 100644
--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -49,6 +49,7 @@
};
i2c0: i2c@f8014000 {
+ i2c-digital-filter;
status = "okay";
};
--
2.7.4
On 2019-09-02 12:12, [email protected] wrote:
> From: Eugen Hristev <[email protected]>
>
> Some i2c controllers have a built-in digital or analog filter.
> This is specifically required depending on the hardware PCB/board.
> Some controllers also allow specifying the maximum width of the
> spikes that can be filtered. The width length can be specified in nanoseconds.
>
> Signed-off-by: Eugen Hristev <[email protected]>
> ---
> Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
> index 44efafd..8dbff67 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
> @@ -55,6 +55,17 @@ wants to support one of the below features, it should adapt the bindings below.
> Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
> specification.
>
> +- i2c-analog-filter
> + Enable analog filter for i2c lines.
> +
> +- i2c-digital-filter
> + Enable digital filter for i2c lines.
> +
> +- i2c-filter-width-ns
> + Width of spikes which can be filtered by either digital or analog
> + filters (i2c-analog-filtr or i2c-digital-filtr). This width is specified
filtr -> filter (two instances)
What if you want/need to have different bandwidth for the digital and analog
filters? After all, this is a generic binding...
Cheers,
Peter
> + in nanoseconds.
> +
> - interrupts
> interrupts used by the device.
>
>
From: Eugen Hristev <[email protected]>
Add new platform data support for digital filtering for i2c.
The sama5d4, sama5d2 and sam9x60 support this feature.
Signed-off-by: Eugen Hristev <[email protected]>
---
drivers/i2c/busses/i2c-at91-core.c | 9 +++++++++
drivers/i2c/busses/i2c-at91-master.c | 9 +++++++++
drivers/i2c/busses/i2c-at91.h | 5 +++++
3 files changed, 23 insertions(+)
diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c
index caf1846..e96360f 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -68,6 +68,7 @@ static struct at91_twi_pdata at91rm9200_config = {
.has_unre_flag = true,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9261_config = {
@@ -76,6 +77,7 @@ static struct at91_twi_pdata at91sam9261_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9260_config = {
@@ -84,6 +86,7 @@ static struct at91_twi_pdata at91sam9260_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
@@ -92,6 +95,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
@@ -100,6 +104,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static const struct platform_device_id at91_twi_devtypes[] = {
@@ -130,6 +135,7 @@ static struct at91_twi_pdata at91sam9x5_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = false,
+ .has_dig_filtr = false,
};
static struct at91_twi_pdata sama5d4_config = {
@@ -138,6 +144,7 @@ static struct at91_twi_pdata sama5d4_config = {
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = true,
+ .has_dig_filtr = true,
};
static struct at91_twi_pdata sama5d2_config = {
@@ -146,6 +153,7 @@ static struct at91_twi_pdata sama5d2_config = {
.has_unre_flag = true,
.has_alt_cmd = true,
.has_hold_field = true,
+ .has_dig_filtr = true,
};
static struct at91_twi_pdata sam9x60_config = {
@@ -154,6 +162,7 @@ static struct at91_twi_pdata sam9x60_config = {
.has_unre_flag = true,
.has_alt_cmd = true,
.has_hold_field = true,
+ .has_dig_filtr = true,
};
static const struct of_device_id atmel_twi_dt_ids[] = {
diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c
index a3fcc35..df80557 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -31,12 +31,18 @@
void at91_init_twi_bus_master(struct at91_twi_dev *dev)
{
+ struct at91_twi_pdata *pdata = dev->pdata;
+
/* FIFO should be enabled immediately after the software reset */
if (dev->fifo_size)
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN);
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)
+ at91_twi_write(dev, AT91_TWI_FILTR, AT91_TWI_FILTR_FILT);
}
/*
@@ -793,6 +799,9 @@ int at91_twi_probe_master(struct platform_device *pdev,
dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size);
}
+ dev->enable_dig_filt = of_property_read_bool(pdev->dev.of_node,
+ "i2c-digital-filter");
+
at91_calc_twi_clock(dev);
dev->adapter.algo = &at91_twi_algorithm;
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index 499b506..c75447e 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -84,6 +84,9 @@
#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
#define AT91_TWI_ACR_DIR BIT(8)
+#define AT91_TWI_FILTR 0x0044
+#define AT91_TWI_FILTR_FILT BIT(0)
+
#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */
#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0)
#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0)
@@ -108,6 +111,7 @@ struct at91_twi_pdata {
bool has_unre_flag;
bool has_alt_cmd;
bool has_hold_field;
+ bool has_dig_filtr;
struct at_dma_slave dma_slave;
};
@@ -145,6 +149,7 @@ struct at91_twi_dev {
unsigned smr;
struct i2c_client *slave;
#endif
+ bool enable_dig_filt;
};
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg);
--
2.7.4
From: Eugen Hristev <[email protected]>
Add new platform data support for advanced digital filtering for i2c.
The sama5d2 and sam9x60 support this feature.
This digital filter allows the user to configure the maximum
width of the spikes that can be filtered.
Signed-off-by: Eugen Hristev <[email protected]>
---
drivers/i2c/busses/i2c-at91-core.c | 9 +++++++++
drivers/i2c/busses/i2c-at91-master.c | 30 +++++++++++++++++++++++++++---
drivers/i2c/busses/i2c-at91.h | 5 +++++
3 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c
index e96360f..1f4ee7e 100644
--- a/drivers/i2c/busses/i2c-at91-core.c
+++ b/drivers/i2c/busses/i2c-at91-core.c
@@ -69,6 +69,7 @@ static struct at91_twi_pdata at91rm9200_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9261_config = {
@@ -78,6 +79,7 @@ static struct at91_twi_pdata at91sam9261_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9260_config = {
@@ -87,6 +89,7 @@ static struct at91_twi_pdata at91sam9260_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
@@ -96,6 +99,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
@@ -105,6 +109,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static const struct platform_device_id at91_twi_devtypes[] = {
@@ -136,6 +141,7 @@ static struct at91_twi_pdata at91sam9x5_config = {
.has_alt_cmd = false,
.has_hold_field = false,
.has_dig_filtr = false,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata sama5d4_config = {
@@ -145,6 +151,7 @@ static struct at91_twi_pdata sama5d4_config = {
.has_alt_cmd = false,
.has_hold_field = true,
.has_dig_filtr = true,
+ .has_adv_dig_filtr = false,
};
static struct at91_twi_pdata sama5d2_config = {
@@ -154,6 +161,7 @@ static struct at91_twi_pdata sama5d2_config = {
.has_alt_cmd = true,
.has_hold_field = true,
.has_dig_filtr = true,
+ .has_adv_dig_filtr = true,
};
static struct at91_twi_pdata sam9x60_config = {
@@ -163,6 +171,7 @@ static struct at91_twi_pdata sam9x60_config = {
.has_alt_cmd = true,
.has_hold_field = true,
.has_dig_filtr = true,
+ .has_adv_dig_filtr = true,
};
static const struct of_device_id atmel_twi_dt_ids[] = {
diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c
index df80557..078bbde 100644
--- a/drivers/i2c/busses/i2c-at91-master.c
+++ b/drivers/i2c/busses/i2c-at91-master.c
@@ -43,6 +43,12 @@ void at91_init_twi_bus_master(struct at91_twi_dev *dev)
/* enable digital filter */
if (pdata->has_dig_filtr && dev->enable_dig_filt)
at91_twi_write(dev, AT91_TWI_FILTR, AT91_TWI_FILTR_FILT);
+
+ /* enable advanced digital filter */
+ if (pdata->has_adv_dig_filtr && dev->enable_dig_filt)
+ at91_twi_write(dev, AT91_TWI_FILTR, AT91_TWI_FILTR_FILT |
+ (AT91_TWI_FILTR_THRES(dev->filter_width) &
+ AT91_TWI_FILTR_THRES_MASK));
}
/*
@@ -51,7 +57,7 @@ void at91_init_twi_bus_master(struct at91_twi_dev *dev)
*/
static void at91_calc_twi_clock(struct at91_twi_dev *dev)
{
- int ckdiv, cdiv, div, hold = 0;
+ 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;
@@ -90,11 +96,29 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev)
}
}
+ if (pdata->has_adv_dig_filtr) {
+ /*
+ * filter width = 0 to AT91_TWI_FILTR_THRES_MAX
+ * peripheral clocks
+ */
+ filter_width = DIV_ROUND_UP(t->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_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
- cdiv, ckdiv, hold, t->sda_hold_ns);
+ 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->filter_width_ns);
}
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h
index c75447e..d7cf01e3 100644
--- a/drivers/i2c/busses/i2c-at91.h
+++ b/drivers/i2c/busses/i2c-at91.h
@@ -86,6 +86,9 @@
#define AT91_TWI_FILTR 0x0044
#define AT91_TWI_FILTR_FILT BIT(0)
+#define AT91_TWI_FILTR_THRES(v) ((v) << 8)
+#define AT91_TWI_FILTR_THRES_MAX 7
+#define AT91_TWI_FILTR_THRES_MASK GENMASK(10, 8)
#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */
#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0)
@@ -112,6 +115,7 @@ struct at91_twi_pdata {
bool has_alt_cmd;
bool has_hold_field;
bool has_dig_filtr;
+ bool has_adv_dig_filtr;
struct at_dma_slave dma_slave;
};
@@ -150,6 +154,7 @@ struct at91_twi_dev {
struct i2c_client *slave;
#endif
bool enable_dig_filt;
+ u32 filter_width;
};
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg);
--
2.7.4
Eugen,
On 02/09/2019 14:15:14+0000, [email protected] wrote:
> On 02.09.2019 13:49, Peter Rosin wrote:
>
> > On 2019-09-02 12:12, [email protected] wrote:
> >> From: Eugen Hristev <[email protected]>
> >>
> >> Some i2c controllers have a built-in digital or analog filter.
> >> This is specifically required depending on the hardware PCB/board.
> >> Some controllers also allow specifying the maximum width of the
> >> spikes that can be filtered. The width length can be specified in nanoseconds.
> >>
> >> Signed-off-by: Eugen Hristev <[email protected]>
> >> ---
> >> Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++++++++
> >> 1 file changed, 11 insertions(+)
> >>
> >> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
> >> index 44efafd..8dbff67 100644
> >> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
> >> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
> >> @@ -55,6 +55,17 @@ wants to support one of the below features, it should adapt the bindings below.
> >> Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
> >> specification.
> >>
> >> +- i2c-analog-filter
> >> + Enable analog filter for i2c lines.
> >> +
> >> +- i2c-digital-filter
> >> + Enable digital filter for i2c lines.
> >> +
> >> +- i2c-filter-width-ns
> >> + Width of spikes which can be filtered by either digital or analog
> >> + filters (i2c-analog-filtr or i2c-digital-filtr). This width is specified
> >
> > filtr -> filter (two instances)
> >
> > What if you want/need to have different bandwidth for the digital and analog
> > filters? After all, this is a generic binding...
>
> For our needs, this is enough: the purpose of the filters is to avoid
> noise on the lines, the noise is as big as it is for the digital and for
> the analog filters, since we use an absolute measurement for them. So I
> do not know how useful it would be to make a difference.
>
You are adding generic properties so they have to be generic and not
tied to your particular use case.
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
On 2019-09-02 16:15, [email protected] wrote:
>
>
> On 02.09.2019 13:49, Peter Rosin wrote:
>
>> On 2019-09-02 12:12, [email protected] wrote:
>>> From: Eugen Hristev <[email protected]>
>>>
>>> Some i2c controllers have a built-in digital or analog filter.
>>> This is specifically required depending on the hardware PCB/board.
>>> Some controllers also allow specifying the maximum width of the
>>> spikes that can be filtered. The width length can be specified in nanoseconds.
>>>
>>> Signed-off-by: Eugen Hristev <[email protected]>
>>> ---
>>> Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++++++++
>>> 1 file changed, 11 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
>>> index 44efafd..8dbff67 100644
>>> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
>>> @@ -55,6 +55,17 @@ wants to support one of the below features, it should adapt the bindings below.
>>> Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
>>> specification.
>>>
>>> +- i2c-analog-filter
>>> + Enable analog filter for i2c lines.
>>> +
>>> +- i2c-digital-filter
>>> + Enable digital filter for i2c lines.
>>> +
>>> +- i2c-filter-width-ns
>>> + Width of spikes which can be filtered by either digital or analog
>>> + filters (i2c-analog-filtr or i2c-digital-filtr). This width is specified
>>
>> filtr -> filter (two instances)
>>
>> What if you want/need to have different bandwidth for the digital and analog
>> filters? After all, this is a generic binding...
>
> Hi Peter,
>
> For our needs, this is enough: the purpose of the filters is to avoid
> noise on the lines, the noise is as big as it is for the digital and for
> the analog filters, since we use an absolute measurement for them. So I
> do not know how useful it would be to make a difference.
I think my gripe is that the description also seems non-generic. Analog
filters never (ok, usually, but I have a hard time seeing how a simple
analog filter can) work in terms of some "width of spikes". That phrasing
seems like something inherent to trivial digital filters. For analog
filters, specifying the bandwidth or cut-off frequency seems much more
appropriate. And bandwidth would work equally well for digital filters,
methinks.
I also think it should be mentioned explicitly that this binding is for
LP filters. I don't think anything else would be useful, but better safe
than sorry...
Hmm, would it be good or bad to specify the bandwidth relative to the
current maximum bus speed?
Cheers,
Peter
> Wolfram, what do you think ?
>
> Eugen
>
>
>>
>> Cheers,
>> Peter
>>
>>> + in nanoseconds.
>>> +
>>> - interrupts
>>> interrupts used by the device.
>>>
>>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>>
On 02.09.2019 13:44, Peter Rosin wrote:
>
> On 2019-09-02 12:11, [email protected] wrote:
>> From: Eugen Hristev <[email protected]>
>>
>> Add compatible for new Microchip SoC, sam9x60
>>
>> Reviewed-by: Rob Herring <[email protected]>
>> Signed-off-by: Eugen Hristev <[email protected]>
>> ---
>> Documentation/devicetree/bindings/i2c/i2c-at91.txt | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
>> index b7cec17..2210f43 100644
>> --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt
>> @@ -3,7 +3,8 @@ I2C for Atmel platforms
>> Required properties :
>> - compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
>> "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
>> - "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
>> + "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
>> + "microchip,sam9x60-i2c"
>
> IIUC, this list should ideally be reformatted with one compatible per line.
>
> Side note; unfortunate naming with SAM9x60, when there is a preexisting 9260
> fitting the "wildcard" (AFAICT, it's not a wildcard in this case, but it sure
> looks like one).
>
Yes, this is a separate SoC. It is named SAM9X60 and not related to old
9260
Reformatting the list would be useful perhaps in a different cosmetic
patch ?
> Cheers,
> Peter
>
>> - reg: physical base address of the controller and length of memory mapped
>> region.
>> - interrupts: interrupt number to the cpu.
>>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
On 02.09.2019 13:49, Peter Rosin wrote:
> On 2019-09-02 12:12, [email protected] wrote:
>> From: Eugen Hristev <[email protected]>
>>
>> Some i2c controllers have a built-in digital or analog filter.
>> This is specifically required depending on the hardware PCB/board.
>> Some controllers also allow specifying the maximum width of the
>> spikes that can be filtered. The width length can be specified in nanoseconds.
>>
>> Signed-off-by: Eugen Hristev <[email protected]>
>> ---
>> Documentation/devicetree/bindings/i2c/i2c.txt | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
>> index 44efafd..8dbff67 100644
>> --- a/Documentation/devicetree/bindings/i2c/i2c.txt
>> +++ b/Documentation/devicetree/bindings/i2c/i2c.txt
>> @@ -55,6 +55,17 @@ wants to support one of the below features, it should adapt the bindings below.
>> Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
>> specification.
>>
>> +- i2c-analog-filter
>> + Enable analog filter for i2c lines.
>> +
>> +- i2c-digital-filter
>> + Enable digital filter for i2c lines.
>> +
>> +- i2c-filter-width-ns
>> + Width of spikes which can be filtered by either digital or analog
>> + filters (i2c-analog-filtr or i2c-digital-filtr). This width is specified
>
> filtr -> filter (two instances)
>
> What if you want/need to have different bandwidth for the digital and analog
> filters? After all, this is a generic binding...
Hi Peter,
For our needs, this is enough: the purpose of the filters is to avoid
noise on the lines, the noise is as big as it is for the digital and for
the analog filters, since we use an absolute measurement for them. So I
do not know how useful it would be to make a difference.
Wolfram, what do you think ?
Eugen
>
> Cheers,
> Peter
>
>> + in nanoseconds.
>> +
>> - interrupts
>> interrupts used by the device.
>>
>>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>
Hi Eugen,
> Wolfram, what do you think ?
Yes, the bindings should be generic. Peter's reasoning makes much sense
to me. I am quite sure if the two of you can work things out, I'll have
nothing to add.
Thanks,
Wolfram