* [PATCH v10 3/5] ARM: dts: stm32: Add I2C1 support for STM32F429 SoC
From: M'boumba Cedric Madianga @ 2017-01-19 13:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484832316-5594-1-git-send-email-cedric.madianga@gmail.com>
This patch adds I2C1 support for STM32F429 SoC
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
arch/arm/boot/dts/stm32f429.dtsi | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index e4dae0e..5b063e9 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -48,6 +48,7 @@
#include "skeleton.dtsi"
#include "armv7-m.dtsi"
#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
+#include <dt-bindings/mfd/stm32f4-rcc.h>
/ {
clocks {
@@ -153,6 +154,18 @@
status = "disabled";
};
+ i2c1: i2c at 40005400 {
+ compatible = "st,stm32f4-i2c";
+ reg = <0x40005400 0x400>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc STM32F4_APB1_RESET(I2C1)>;
+ clocks = <&rcc 0 STM32F4_APB1_CLOCK(I2C1)>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
usart7: serial at 40007800 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40007800 0x400>;
@@ -355,6 +368,16 @@
slew-rate = <2>;
};
};
+
+ i2c1_pins_b: i2c1 at 0 {
+ pins {
+ pinmux = <STM32F429_PB9_FUNC_I2C1_SDA>,
+ <STM32F429_PB6_FUNC_I2C1_SCL>;
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <3>;
+ };
+ };
};
rcc: rcc at 40023810 {
--
1.9.1
^ permalink raw reply related
* [PATCH v10 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2017-01-19 13:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484832316-5594-1-git-send-email-cedric.madianga@gmail.com>
This patch adds support for the STM32F4 I2C controller.
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-stm32f4.c | 897 +++++++++++++++++++++++++++++++++++++++
3 files changed, 908 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0cdc844..2719208 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -886,6 +886,16 @@ config I2C_ST
This driver can also be built as module. If so, the module
will be called i2c-st.
+config I2C_STM32F4
+ tristate "STMicroelectronics STM32F4 I2C support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Enable this option to add support for STM32 I2C controller embedded
+ in STM32F4 SoCs.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-stm32f4.
+
config I2C_STU300
tristate "ST Microelectronics DDC I2C interface"
depends on MACH_U300
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 1c1bac8..a2c6ff5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_ST) += i2c-st.o
+obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
new file mode 100644
index 0000000..f9dd7e8
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32f4.c
@@ -0,0 +1,897 @@
+/*
+ * Driver for STMicroelectronics STM32 I2C controller
+ *
+ * This I2C controller is described in the STM32F429/439 Soc reference manual.
+ * Please see below a link to the documentation:
+ * http://www.st.com/resource/en/reference_manual/DM00031020.pdf
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2016
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * This driver is based on i2c-st.c
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/* STM32F4 I2C offset registers */
+#define STM32F4_I2C_CR1 0x00
+#define STM32F4_I2C_CR2 0x04
+#define STM32F4_I2C_DR 0x10
+#define STM32F4_I2C_SR1 0x14
+#define STM32F4_I2C_SR2 0x18
+#define STM32F4_I2C_CCR 0x1C
+#define STM32F4_I2C_TRISE 0x20
+#define STM32F4_I2C_FLTR 0x24
+
+/* STM32F4 I2C control 1*/
+#define STM32F4_I2C_CR1_POS BIT(11)
+#define STM32F4_I2C_CR1_ACK BIT(10)
+#define STM32F4_I2C_CR1_STOP BIT(9)
+#define STM32F4_I2C_CR1_START BIT(8)
+#define STM32F4_I2C_CR1_PE BIT(0)
+
+/* STM32F4 I2C control 2 */
+#define STM32F4_I2C_CR2_FREQ_MASK GENMASK(5, 0)
+#define STM32F4_I2C_CR2_FREQ(n) ((n) & STM32F4_I2C_CR2_FREQ_MASK)
+#define STM32F4_I2C_CR2_ITBUFEN BIT(10)
+#define STM32F4_I2C_CR2_ITEVTEN BIT(9)
+#define STM32F4_I2C_CR2_ITERREN BIT(8)
+#define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN | \
+ STM32F4_I2C_CR2_ITEVTEN | \
+ STM32F4_I2C_CR2_ITERREN)
+
+/* STM32F4 I2C Status 1 */
+#define STM32F4_I2C_SR1_AF BIT(10)
+#define STM32F4_I2C_SR1_ARLO BIT(9)
+#define STM32F4_I2C_SR1_BERR BIT(8)
+#define STM32F4_I2C_SR1_TXE BIT(7)
+#define STM32F4_I2C_SR1_RXNE BIT(6)
+#define STM32F4_I2C_SR1_BTF BIT(2)
+#define STM32F4_I2C_SR1_ADDR BIT(1)
+#define STM32F4_I2C_SR1_SB BIT(0)
+#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF | \
+ STM32F4_I2C_SR1_ADDR | \
+ STM32F4_I2C_SR1_SB)
+#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE | \
+ STM32F4_I2C_SR1_RXNE)
+#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF | \
+ STM32F4_I2C_SR1_ARLO | \
+ STM32F4_I2C_SR1_BERR)
+
+/* STM32F4 I2C Status 2 */
+#define STM32F4_I2C_SR2_BUSY BIT(1)
+
+/* STM32F4 I2C Control Clock */
+#define STM32F4_I2C_CCR_CCR_MASK GENMASK(11, 0)
+#define STM32F4_I2C_CCR_CCR(n) ((n) & STM32F4_I2C_CCR_CCR_MASK)
+#define STM32F4_I2C_CCR_FS BIT(15)
+#define STM32F4_I2C_CCR_DUTY BIT(14)
+
+/* STM32F4 I2C Trise */
+#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
+#define STM32F4_I2C_TRISE_VALUE(n) ((n) & STM32F4_I2C_TRISE_VALUE_MASK)
+
+#define STM32F4_I2C_MIN_STANDARD_FREQ 2U
+#define STM32F4_I2C_MIN_FAST_FREQ 6U
+#define STM32F4_I2C_MAX_FREQ 46U
+#define HZ_TO_MHZ 1000000
+
+enum stm32f4_i2c_speed {
+ STM32F4_I2C_SPEED_STANDARD, /* 100 kHz */
+ STM32F4_I2C_SPEED_FAST, /* 400 kHz */
+ STM32F4_I2C_SPEED_END,
+};
+
+/**
+ * struct stm32f4_i2c_msg - client specific data
+ * @addr: 8-bit slave addr, including r/w bit
+ * @count: number of bytes to be transferred
+ * @buf: data buffer
+ * @result: result of the transfer
+ * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ */
+struct stm32f4_i2c_msg {
+ u8 addr;
+ u32 count;
+ u8 *buf;
+ int result;
+ bool stop;
+};
+
+/**
+ * struct stm32f4_i2c_dev - private data of the controller
+ * @adap: I2C adapter for this controller
+ * @dev: device for this controller
+ * @base: virtual memory area
+ * @complete: completion of I2C message
+ * @clk: hw i2c clock
+ * @speed: I2C clock frequency of the controller. Standard or Fast are supported
+ * @parent_rate: I2C clock parent rate in MHz
+ * @msg: I2C transfer information
+ */
+struct stm32f4_i2c_dev {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct completion complete;
+ struct clk *clk;
+ int speed;
+ int parent_rate;
+ struct stm32f4_i2c_msg msg;
+};
+
+static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) | mask, reg);
+}
+
+static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) & ~mask, reg);
+}
+
+static void stm32f4_i2c_disable_irq(struct stm32f4_i2c_dev *i2c_dev)
+{
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
+}
+
+static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 freq;
+ u32 cr2 = 0;
+
+ i2c_dev->parent_rate = clk_get_rate(i2c_dev->clk);
+ freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
+
+ if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
+ /*
+ * To reach 100 kHz, the parent clk frequency should be between
+ * a minimum value of 2 MHz and a maximum value of 46 MHz due
+ * to hardware limitation
+ */
+ if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
+ freq > STM32F4_I2C_MAX_FREQ) {
+ dev_err(i2c_dev->dev,
+ "bad parent clk freq for standard mode\n");
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * To be as close as possible to 400 kHz, the parent clk
+ * frequency should be between a minimum value of 6 MHz and a
+ * maximum value of 46 MHz due to hardware limitation
+ */
+ if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
+ freq > STM32F4_I2C_MAX_FREQ) {
+ dev_err(i2c_dev->dev,
+ "bad parent clk freq for fast mode\n");
+ return -EINVAL;
+ }
+ }
+
+ cr2 |= STM32F4_I2C_CR2_FREQ(freq);
+ writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
+
+ return 0;
+}
+
+static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
+ u32 trise;
+
+ /*
+ * These bits must be programmed with the maximum SCL rise time given in
+ * the I2C bus specification, incremented by 1.
+ *
+ * In standard mode, the maximum allowed SCL rise time is 1000 ns.
+ * If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
+ * 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
+ * programmed with 0x9. (1000 ns / 125 ns + 1)
+ * So, for I2C standard mode TRISE = FREQ[5:0] + 1
+ *
+ * In fast mode, the maximum allowed SCL rise time is 300 ns.
+ * If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
+ * 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
+ * programmed with 0x3. (300 ns / 125 ns + 1)
+ * So, for I2C fast mode TRISE = FREQ[5:0] * 300 / 1000 + 1
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that parent rate
+ * is not higher than 46 MHz . As a result trise is at most 4 bits wide
+ * and so fits into the TRISE bits [5:0].
+ */
+ if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD)
+ trise = freq + 1;
+ else
+ trise = freq * 3 / 10 + 1;
+
+ writel_relaxed(STM32F4_I2C_TRISE_VALUE(trise),
+ i2c_dev->base + STM32F4_I2C_TRISE);
+}
+
+static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 val;
+ u32 ccr = 0;
+
+ if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
+ /*
+ * In standard mode:
+ * t_scl_high = t_scl_low = CCR * I2C parent clk period
+ * So to reach 100 kHz, we have:
+ * CCR = I2C parent rate / 100 kHz >> 1
+ *
+ * For example with parent rate = 2 MHz:
+ * CCR = 2000000 / (100000 << 1) = 10
+ * t_scl_high = t_scl_low = 10 * (1 / 2000000) = 5000 ns
+ * t_scl_high + t_scl_low = 10000 ns so 100 kHz is reached
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that
+ * parent rate is not higher than 46 MHz . As a result val
+ * is@most 8 bits wide and so fits into the CCR bits [11:0].
+ */
+ val = i2c_dev->parent_rate / (100000 << 1);
+ } else {
+ /*
+ * In fast mode, we compute CCR with duty = 0 as with low
+ * frequencies we are not able to reach 400 kHz.
+ * In that case:
+ * t_scl_high = CCR * I2C parent clk period
+ * t_scl_low = 2 * CCR * I2C parent clk period
+ * So, CCR = I2C parent rate / (400 kHz * 3)
+ *
+ * For example with parent rate = 6 MHz:
+ * CCR = 6000000 / (400000 * 3) = 5
+ * t_scl_high = 5 * (1 / 6000000) = 833 ns > 600 ns
+ * t_scl_low = 2 * 5 * (1 / 6000000) = 1667 ns > 1300 ns
+ * t_scl_high + t_scl_low = 2500 ns so 400 kHz is reached
+ *
+ * Function stm32f4_i2c_set_periph_clk_freq made sure that
+ * parent rate is not higher than 46 MHz . As a result val
+ * is at most 6 bits wide and so fits into the CCR bits [11:0].
+ */
+ val = DIV_ROUND_UP(i2c_dev->parent_rate, 400000 * 3);
+
+ /* Select Fast mode */
+ ccr |= STM32F4_I2C_CCR_FS;
+ }
+
+ ccr |= STM32F4_I2C_CCR_CCR(val);
+ writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
+}
+
+/**
+ * stm32f4_i2c_hw_config() - Prepare I2C block
+ * @i2c_dev: Controller's private data
+ */
+static int stm32f4_i2c_hw_config(struct stm32f4_i2c_dev *i2c_dev)
+{
+ int ret;
+
+ ret = stm32f4_i2c_set_periph_clk_freq(i2c_dev);
+ if (ret)
+ return ret;
+
+ stm32f4_i2c_set_rise_time(i2c_dev);
+
+ stm32f4_i2c_set_speed_mode(i2c_dev);
+
+ /* Enable I2C */
+ writel_relaxed(STM32F4_I2C_CR1_PE, i2c_dev->base + STM32F4_I2C_CR1);
+
+ return 0;
+}
+
+static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 status;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
+ status,
+ !(status & STM32F4_I2C_SR2_BUSY),
+ 10, 1000);
+ if (ret) {
+ dev_dbg(i2c_dev->dev, "bus not free\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_write_ byte() - Write a byte in the data register
+ * @i2c_dev: Controller's private data
+ * @byte: Data to write in the register
+ */
+static void stm32f4_i2c_write_byte(struct stm32f4_i2c_dev *i2c_dev, u8 byte)
+{
+ writel_relaxed(byte, i2c_dev->base + STM32F4_I2C_DR);
+}
+
+/**
+ * stm32f4_i2c_write_msg() - Fill the data register in write mode
+ * @i2c_dev: Controller's private data
+ *
+ * This function fills the data register with I2C transfer buffer
+ */
+static void stm32f4_i2c_write_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+
+ stm32f4_i2c_write_byte(i2c_dev, *msg->buf++);
+ msg->count--;
+}
+
+static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 rbuf;
+
+ rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
+ *msg->buf++ = rbuf;
+ msg->count--;
+}
+
+static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ stm32f4_i2c_disable_irq(i2c_dev);
+
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ complete(&i2c_dev->complete);
+}
+
+/**
+ * stm32f4_i2c_handle_write() - Handle FIFO empty interrupt in case of write
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_write(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ if (msg->count) {
+ stm32f4_i2c_write_msg(i2c_dev);
+ if (!msg->count) {
+ /*
+ * Disable buffer interrupts for RX not empty and TX
+ * empty events
+ */
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ }
+ } else {
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
+ * @i2c_dev: Controller's private data
+ *
+ * This function is called when a new data is received in data register
+ */
+static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ switch (msg->count) {
+ case 1:
+ stm32f4_i2c_disable_irq(i2c_dev);
+ stm32f4_i2c_read_msg(i2c_dev);
+ complete(&i2c_dev->complete);
+ break;
+ /*
+ * For 2-byte reception, 3-byte reception and for Data N-2, N-1 and N
+ * for N-byte reception with N > 3, we do not have to read the data
+ * register when RX not empty event occurs as we have to wait for byte
+ * transferred finished event before reading data.
+ * So, here we just disable buffer interrupt in order to avoid another
+ * system preemption due to RX not empty event.
+ */
+ case 2:
+ case 3:
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ break;
+ /*
+ * For N byte reception with N > 3 we directly read data register
+ * until N-2 data.
+ */
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_done() - Handle byte transfer finished interrupt
+ * in case of read
+ * @i2c_dev: Controller's private data
+ *
+ * This function is called when a new data is received in the shift register
+ * but data register has not been read yet.
+ */
+static void stm32f4_i2c_handle_rx_done(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 mask;
+ int i;
+
+ switch (msg->count) {
+ case 2:
+ /*
+ * In order to correctly send the Stop or Repeated Start
+ * condition on the I2C bus, the STOP/START bit has to be set
+ * before reading the last two bytes (data N-1 and N).
+ * After that, we could read the last two bytes, disable
+ * remaining interrupts and notify the end of xfer to the
+ * client
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ for (i = 2; i > 0; i--)
+ stm32f4_i2c_read_msg(i2c_dev);
+
+ reg = i2c_dev->base + STM32F4_I2C_CR2;
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_clr_bits(reg, mask);
+
+ complete(&i2c_dev->complete);
+ break;
+ case 3:
+ /*
+ * In order to correctly generate the NACK pulse after the last
+ * received data byte, we have to enable NACK before reading N-2
+ * data
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
+ stm32f4_i2c_read_msg(i2c_dev);
+ break;
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
+ * master receiver
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 cr1;
+
+ switch (msg->count) {
+ case 0:
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+
+ /* Clear ADDR flag */
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ case 1:
+ /*
+ * Single byte reception:
+ * Enable NACK and reset POS (Acknowledge position).
+ * Then, clear ADDR flag and set STOP or RepSTART.
+ * In that way, the NACK and STOP or RepStart pulses will be
+ * sent as soon as the byte will be received in shift register
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 &= ~(STM32F4_I2C_CR1_ACK | STM32F4_I2C_CR1_POS);
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+
+ if (msg->stop)
+ cr1 |= STM32F4_I2C_CR1_STOP;
+ else
+ cr1 |= STM32F4_I2C_CR1_START;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+ break;
+ case 2:
+ /*
+ * 2-byte reception:
+ * Enable NACK, set POS (NACK position) and clear ADDR flag.
+ * In that way, NACK will be sent for the next byte which will
+ * be received in the shift register instead of the current
+ * one.
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 &= ~STM32F4_I2C_CR1_ACK;
+ cr1 |= STM32F4_I2C_CR1_POS;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+
+ default:
+ /*
+ * N-byte reception:
+ * Enable ACK, reset POS (ACK postion) and clear ADDR flag.
+ * In that way, ACK will be sent as soon as the current byte
+ * will be received in the shift register
+ */
+ cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
+ cr1 |= STM32F4_I2C_CR1_ACK;
+ cr1 &= ~STM32F4_I2C_CR1_POS;
+ writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
+
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ }
+}
+
+/**
+ * stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 possible_status = STM32F4_I2C_SR1_ITEVTEN_MASK;
+ u32 status, ien, event, cr2;
+
+ cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ ien = cr2 & STM32F4_I2C_CR2_IRQ_MASK;
+
+ /* Update possible_status if buffer interrupt is enabled */
+ if (ien & STM32F4_I2C_CR2_ITBUFEN)
+ possible_status |= STM32F4_I2C_SR1_ITBUFEN_MASK;
+
+ status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+ event = status & possible_status;
+ if (!event) {
+ dev_dbg(i2c_dev->dev,
+ "spurious evt irq (status=0x%08x, ien=0x%08x)\n",
+ status, ien);
+ return IRQ_NONE;
+ }
+
+ /* Start condition generated */
+ if (event & STM32F4_I2C_SR1_SB)
+ stm32f4_i2c_write_byte(i2c_dev, msg->addr);
+
+ /* I2C Address sent */
+ if (event & STM32F4_I2C_SR1_ADDR) {
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_addr(i2c_dev);
+ else
+ readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+
+ /*
+ * Enable buffer interrupts for RX not empty and TX empty
+ * events
+ */
+ cr2 |= STM32F4_I2C_CR2_ITBUFEN;
+ writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
+ }
+
+ /* TX empty */
+ if ((event & STM32F4_I2C_SR1_TXE) && !(msg->addr & I2C_M_RD))
+ stm32f4_i2c_handle_write(i2c_dev);
+
+ /* RX not empty */
+ if ((event & STM32F4_I2C_SR1_RXNE) && (msg->addr & I2C_M_RD))
+ stm32f4_i2c_handle_read(i2c_dev);
+
+ /*
+ * The BTF (Byte Transfer finished) event occurs when:
+ * - in reception : a new byte is received in the shift register
+ * but the previous byte has not been read yet from data register
+ * - in transmission: a new byte should be sent but the data register
+ * has not been written yet
+ */
+ if (event & STM32F4_I2C_SR1_BTF) {
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_done(i2c_dev);
+ else
+ stm32f4_i2c_handle_write(i2c_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_i2c_isr_error() - Interrupt routine for I2C bus error
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_error(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 status;
+
+ status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+
+ /* Arbitration lost */
+ if (status & STM32F4_I2C_SR1_ARLO) {
+ status &= ~STM32F4_I2C_SR1_ARLO;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EAGAIN;
+ }
+
+ /*
+ * Acknowledge failure:
+ * In master transmitter mode a Stop must be generated by software
+ */
+ if (status & STM32F4_I2C_SR1_AF) {
+ if (!(msg->addr & I2C_M_RD)) {
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ }
+ status &= ~STM32F4_I2C_SR1_AF;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EIO;
+ }
+
+ /* Bus error */
+ if (status & STM32F4_I2C_SR1_BERR) {
+ status &= ~STM32F4_I2C_SR1_BERR;
+ writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
+ msg->result = -EIO;
+ }
+
+ stm32f4_i2c_disable_irq(i2c_dev);
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_i2c_xfer_msg() - Transfer a single I2C message
+ * @i2c_dev: Controller's private data
+ * @msg: I2C message to transfer
+ * @is_first: first message of the sequence
+ * @is_last: last message of the sequence
+ */
+static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, bool is_first,
+ bool is_last)
+{
+ struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
+ unsigned long timeout;
+ u32 mask;
+ int ret;
+
+ f4_msg->addr = i2c_8bit_addr_from_msg(msg);
+ f4_msg->buf = msg->buf;
+ f4_msg->count = msg->len;
+ f4_msg->result = 0;
+ f4_msg->stop = is_last;
+
+ reinit_completion(&i2c_dev->complete);
+
+ /* Enable events and errors interrupts */
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_set_bits(i2c_dev->base + STM32F4_I2C_CR2, mask);
+
+ if (is_first) {
+ ret = stm32f4_i2c_wait_free_bus(i2c_dev);
+ if (ret)
+ return ret;
+
+ /* START generation */
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+ }
+
+ timeout = wait_for_completion_timeout(&i2c_dev->complete,
+ i2c_dev->adap.timeout);
+ ret = f4_msg->result;
+
+ if (!timeout)
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_xfer() - Transfer combined I2C message
+ * @i2c_adap: Adapter pointer to the controller
+ * @msgs: Pointer to data to be written.
+ * @num: Number of messages to be executed
+ */
+static int stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+ int ret, i;
+
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ for (i = 0; i < num && !ret; i++)
+ ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
+ i == num - 1);
+
+ clk_disable(i2c_dev->clk);
+
+ return (ret < 0) ? ret : num;
+}
+
+static u32 stm32f4_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm stm32f4_i2c_algo = {
+ .master_xfer = stm32f4_i2c_xfer,
+ .functionality = stm32f4_i2c_func,
+};
+
+static int stm32f4_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct stm32f4_i2c_dev *i2c_dev;
+ struct resource *res;
+ u32 irq_event, irq_error, clk_rate;
+ struct i2c_adapter *adap;
+ struct reset_control *rst;
+ int ret;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c_dev->base))
+ return PTR_ERR(i2c_dev->base);
+
+ irq_event = irq_of_parse_and_map(np, 0);
+ if (!irq_event) {
+ dev_err(&pdev->dev, "IRQ event missing or invalid\n");
+ return -EINVAL;
+ }
+
+ irq_error = irq_of_parse_and_map(np, 1);
+ if (!irq_error) {
+ dev_err(&pdev->dev, "IRQ error missing or invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(&pdev->dev, "Error: Missing controller clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n");
+ return ret;
+ }
+
+ rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Error: Missing controller reset\n");
+ ret = PTR_ERR(rst);
+ goto clk_free;
+ }
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+
+ i2c_dev->speed = STM32F4_I2C_SPEED_STANDARD;
+ ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
+ if (!ret && clk_rate >= 400000)
+ i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
+
+ i2c_dev->dev = &pdev->dev;
+
+ ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq event %i\n",
+ irq_event);
+ goto clk_free;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0,
+ pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq error %i\n",
+ irq_error);
+ goto clk_free;
+ }
+
+ ret = stm32f4_i2c_hw_config(i2c_dev);
+ if (ret)
+ goto clk_free;
+
+ adap = &i2c_dev->adap;
+ i2c_set_adapdata(adap, i2c_dev);
+ snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
+ adap->owner = THIS_MODULE;
+ adap->timeout = 2 * HZ;
+ adap->retries = 0;
+ adap->algo = &stm32f4_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&i2c_dev->complete);
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ goto clk_free;
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ clk_disable(i2c_dev->clk);
+
+ dev_info(i2c_dev->dev, "STM32F4 I2C driver registered\n");
+
+ return 0;
+
+clk_free:
+ clk_disable_unprepare(i2c_dev->clk);
+ return ret;
+}
+
+static int stm32f4_i2c_remove(struct platform_device *pdev)
+{
+ struct stm32f4_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c_dev->adap);
+
+ clk_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static const struct of_device_id stm32f4_i2c_match[] = {
+ { .compatible = "st,stm32f4-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
+
+static struct platform_driver stm32f4_i2c_driver = {
+ .driver = {
+ .name = "stm32f4-i2c",
+ .of_match_table = stm32f4_i2c_match,
+ },
+ .probe = stm32f4_i2c_probe,
+ .remove = stm32f4_i2c_remove,
+};
+
+module_platform_driver(stm32f4_i2c_driver);
+
+MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32F4 I2C driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v10 1/5] dt-bindings: Document the STM32 I2C bindings
From: M'boumba Cedric Madianga @ 2017-01-19 13:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484832316-5594-1-git-send-email-cedric.madianga@gmail.com>
This patch adds documentation of device tree bindings for the STM32 I2C
controller.
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/i2c/i2c-stm32.txt | 33 ++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-stm32.txt
diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
new file mode 100644
index 0000000..78eaf7b
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
@@ -0,0 +1,33 @@
+* I2C controller embedded in STMicroelectronics STM32 I2C platform
+
+Required properties :
+- compatible : Must be "st,stm32f4-i2c"
+- reg : Offset and length of the register set for the device
+- interrupts : Must contain the interrupt id for I2C event and then the
+ interrupt id for I2C error.
+- resets: Must contain the phandle to the reset controller.
+- clocks: Must contain the input clock of the I2C instance.
+- A pinctrl state named "default" must be defined to set pins in mode of
+ operation for I2C transfer
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties :
+- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
+ the default 100 kHz frequency will be used. As only Normal and Fast modes
+ are supported, possible values are 100000 and 400000.
+
+Example :
+
+ i2c at 40005400 {
+ compatible = "st,stm32f4-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40005400 0x400>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc 277>;
+ clocks = <&rcc 0 149>;
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
+ pinctrl-names = "default";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v10 0/5] Add support for the STM32F4 I2C
From: M'boumba Cedric Madianga @ 2017-01-19 13:25 UTC (permalink / raw)
To: linux-arm-kernel
This patchset adds support for the I2C controller embedded in STM32F4xx SoC.
It enables I2C transfer in interrupt mode with Standard-mode and Fast-mode bus
speed.
Changes since v9:
- Fix minor typo in some comments
- Add some comments to explain how the driver check TRISE and CCR value have
no chance of overflow
Changes since v8:
- Rework I2C Clock Control Register computation (Uwe)
- Save register accesses as often as possible (Uwe)
- Don't use mask before saving rx buffer (Uwe)
- Add more comments to explain hardware way of working (Uwe)
- Rename stm32f4_i2c_handle_rx_btf function by stm32f4_i2c_handle_rx_done (Uwe)
- Set/Clear Ack position bit during address match phase
Changes since v7:
- Remove unneeded parenthesis in some macro definitions (Uwe)
- Fix some typo (s/KhzkHZ, s/PEC/POC) (Uwe)
- Fix alignment issues in some structures declaration (Uwe)
- Clarify comments to argue i2c_timing values chosen (Uwe)
- Raise an error if parent clk rate is out of scope during I2C hw config (Uwe)
- Use dev_dbg instead of dev_err message when I2C bus is busy (Uwe)
- Add more comments about stuff done by stm32f4_i2c_handle_rx_btf() (Uwe)
- Simplify stm32f4_i2c_isr_error() routine implementation by removing possible
status checking (Uwe)
- Rework stm32f4_i2c_isr_error() routine by removing the loop to check which
status occured (Uwe)
- Add open-drain property for SCL pins (Uwe)
- Rework unneeded mul_ccr field from i2c_timing structure
- Remove min_ccr field from i2c_timing structure as default scl_period is chosen
to have a correct minimal ccr value
- Execute hw_config once during probe
- Remove soft_reset after an I2C error as all errors are now handled and
hw_config is done once during probe
- Generate STOP by software when Acknowledge failure occurs
- Set the max speed mode for I2C pins
- Add bias-disable property for I2C pins
- Use intrinsic limitation of APB bus to set I2C max input clk
Changes since v6:
- Add commit message for the patches in defconfig, .dtsi and .dts files (Alex)
- Order I2C instance base address in .dtsi file (Alex)
- Add commit message for the patch in stm32429i-eval.dts (Alex)
- Add link to the STM32F4 Soc ref manual where I2C device is described (Uwe)
- Use more usal way to define constants with several lines (Uwe)
- Remove rate variable from stm32f4_i2c_timings as it is not used (Uwe)
- Remove irq variable from stm32f4_i2c_dev struct are they are only needed
during probe (Uwe)
- Add comment from datasheet to explain stm32f4_i2c_timings values (Uwe)
- Rework i2c soft_reset implementation (Uwe)
- Replace "it" by "irq" as it is a more usual abbreviation for interrupt (Uwe)
- Add comment from datasheet to explain periph clk freq calculation (Uwe)
- Use DIV_ROUND_UP instead of plain division when required (Uwe)
- Add comment from datasheet to explain timing rise calculation (Uwe)
- Rework timing rise calculation by using shorter computation (Uwe)
- Remove (u8) cast when reading I2C data register (Uwe)
- Rework isr_event routine to handle several events during one call of the
routine (Uwe)
- Precise which type of irq is failed when a irq request error occurs (Uwe)
- Use devm_request_irq() instead of devm_request_threaded_irq() to avoid
spurious evt irq when clearing status registers in threaded context
Changes since v5:
- Change commit header from "ARM: dts:" to "ARM: dts: stm32:" (Alex)
- Change commit header from "ARM: configs:" to "ARM: configs: stm32:" (Alex)
- Fix warnings due to variable set but unused (Wolfram)
- Remove double space in Kconfig (Wolfram)
- Fix warning due to bad type parameter when using clamp() function
(build-bot)
Changes since v4:
- Use clamp() function to use a value in a given range as it was missed in V4
Changes since v3 after Wolfram's review:
- Add COMPILE_TEST flag in Kconfig
- Use correct driver name in Kconfig i.e i2c-stm32f4 instead of i2c-st
- Use more comprehensible name stm32f4_i2c_msg for client specific data
- Don't store reset control node as just needed in probe
- Use clamp() function to test value between 2 ranges
- Use new "i2c_8bit_addr_from_msg() function to build I2C address
- Don't write error messages for timeout
- Remove error message when i2c_add_adapter() fails as it is already handled by
the i2c core driver
Changes since v2:
- remove interrupt configuration management from DT
- remove FIFO configuration management from DT except threshold as it is very
hard to handle it in the driver due to many possible combinations according
to burst and bus width
- update DMA client message in DT documentation file
- specify the order to be used to set per-channel DMA interrupts in the DT
- remove unused enumerations for channel and request ids
- keep as soon as possible 80 lines char for more readability
- replace unsigned int by u32
- return error if burst is not supported in stm32_dma_get_burst()
- return error if bus_width is not supported in stm32_dma_get_width()
- add FIFO configuration management inside the driver except for threshold
- add interrupt configuration management inside the driver
- rework stm32_dma_chan_irq() to handle error interrupt in one way
- rework stm32_dma_set_xfer_param() to be easier to read
- update stm32_dma_tx_status() to always return status from dma_cookie_status()
- disable clk if we don't manage to stop the DMA channel during channel
resources allocation
- set driver as built-in as DMA will be required by other built-in driver
Changes since v1:
- use compatible st,stm32f4-i2c instead of st,i2c-stm32f4 (Rob)
- fix typo s/enmpty/empty (Maxime)
- use one function to handle TX fifo empty and byte xfer finished IT (Maxime)
- set duty cycle in timing struct in Fast mode
- Rework clock management (call prepare/unprepare at probe and remove, call
clk_enable/clk_disable for each I2C transfer)
M'boumba Cedric Madianga (5):
dt-bindings: Document the STM32 I2C bindings
i2c: Add STM32F4 I2C driver
ARM: dts: stm32: Add I2C1 support for STM32F429 SoC
ARM: dts: stm32: Add I2C1 support for STM32429 eval board
ARM: configs: stm32: Add I2C support for STM32 defconfig
.../devicetree/bindings/i2c/i2c-stm32.txt | 33 +
arch/arm/boot/dts/stm32429i-eval.dts | 6 +
arch/arm/boot/dts/stm32f429.dtsi | 23 +
arch/arm/configs/stm32_defconfig | 3 +
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-stm32f4.c | 897 +++++++++++++++++++++
7 files changed, 973 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-stm32.txt
create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
--
1.9.1
^ permalink raw reply
* [PATCH 1/4] ARM: mmu: decouple VECTORS_BASE from Kconfig
From: Afzal Mohammed @ 2017-01-19 13:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170118203739.6400-1-afzal.mohd.ma@gmail.com>
+ Marvell Berlin SoC maintainers - Sebastian, Jisheng
On Thu, Jan 19, 2017 at 02:07:39AM +0530, afzal mohammed wrote:
> For MMU configurations, VECTORS_BASE is always 0xffff0000, a macro
> definition will suffice.
>
> Once exception address is handled dynamically for no-MMU also (this
> would involve taking care of region setup too), VECTORS_BASE can be
> removed from Kconfig.
>
> Suggested-by: Russell King <rmk+kernel@arm.linux.org.uk>
> Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
> ---
>
> Though there was no build error without inclusion of asm/memory.h, to
> be on the safer side it has been added, to reduce chances of build
> breakage in random configurations.
>
> arch/arm/include/asm/memory.h | 2 ++
> arch/arm/mach-berlin/platsmp.c | 3 ++-
> arch/arm/mm/dump.c | 5 +++--
> arch/arm/mm/init.c | 4 ++--
> 4 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index 76cbd9c674df..9cc9f1dbc88e 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -83,6 +83,8 @@
> #define IOREMAP_MAX_ORDER 24
> #endif
>
> +#define VECTORS_BASE 0xffff0000
> +
> #else /* CONFIG_MMU */
>
> /*
> diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c
> index 93f90688db18..578d41031abf 100644
> --- a/arch/arm/mach-berlin/platsmp.c
> +++ b/arch/arm/mach-berlin/platsmp.c
> @@ -15,6 +15,7 @@
>
> #include <asm/cacheflush.h>
> #include <asm/cp15.h>
> +#include <asm/memory.h>
> #include <asm/smp_plat.h>
> #include <asm/smp_scu.h>
>
> @@ -75,7 +76,7 @@ static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
> if (!cpu_ctrl)
> goto unmap_scu;
>
> - vectors_base = ioremap(CONFIG_VECTORS_BASE, SZ_32K);
> + vectors_base = ioremap(VECTORS_BASE, SZ_32K);
> if (!vectors_base)
> goto unmap_scu;
>
> diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
> index 9fe8e241335c..21192d6eda40 100644
> --- a/arch/arm/mm/dump.c
> +++ b/arch/arm/mm/dump.c
> @@ -18,6 +18,7 @@
> #include <linux/seq_file.h>
>
> #include <asm/fixmap.h>
> +#include <asm/memory.h>
> #include <asm/pgtable.h>
>
> struct addr_marker {
> @@ -31,8 +32,8 @@ static struct addr_marker address_markers[] = {
> { 0, "vmalloc() Area" },
> { VMALLOC_END, "vmalloc() End" },
> { FIXADDR_START, "Fixmap Area" },
> - { CONFIG_VECTORS_BASE, "Vectors" },
> - { CONFIG_VECTORS_BASE + PAGE_SIZE * 2, "Vectors End" },
> + { VECTORS_BASE, "Vectors" },
> + { VECTORS_BASE + PAGE_SIZE * 2, "Vectors End" },
> { -1, NULL },
> };
>
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 370581aeb871..cf47f86f79ed 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -27,6 +27,7 @@
> #include <asm/cp15.h>
> #include <asm/mach-types.h>
> #include <asm/memblock.h>
> +#include <asm/memory.h>
> #include <asm/prom.h>
> #include <asm/sections.h>
> #include <asm/setup.h>
> @@ -521,8 +522,7 @@ void __init mem_init(void)
> " .data : 0x%p" " - 0x%p" " (%4td kB)\n"
> " .bss : 0x%p" " - 0x%p" " (%4td kB)\n",
>
> - MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
> - (PAGE_SIZE)),
> + MLK(UL(VECTORS_BASE), UL(VECTORS_BASE) + (PAGE_SIZE)),
> #ifdef CONFIG_HAVE_TCM
> MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
> MLK(ITCM_OFFSET, (unsigned long) itcm_end),
> --
> 2.11.0
^ permalink raw reply
* [PATCH 3/4] ARM: nommu: display vectors base
From: Afzal Mohammed @ 2017-01-19 13:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170118221315.GP27312@n2100.armlinux.org.uk>
Hi,
On Wed, Jan 18, 2017 at 10:13:15PM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 19, 2017 at 02:08:37AM +0530, afzal mohammed wrote:
> > + MLK_ROUNDUP(vectors_base, vectors_base + PAGE_SIZE),
>
> I think MLK() will do here - no need to use the rounding-up version
> as PAGE_SIZE is a multiple of 1k.
Yes, i will replace it.
Earlier, used MLK(), got some build error, now checking again, no
build error, i should have messed up something at that time.
Regards
afzal
^ permalink raw reply
* [linux-sunxi] [PATCH 1/2] drivers: pinctrl: add driver for Allwinner H5 SoC
From: Icenowy Zheng @ 2017-01-19 13:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACRpkdaTVY7Of5bKyk81xA2kUnZVMQ8LnWEJosg7Ns3s5nAEYQ@mail.gmail.com>
19.01.2017, 17:23, "Linus Walleij" <linus.walleij@linaro.org>:
> On Wed, Jan 18, 2017 at 10:44 AM, Andre Przywara <andre.przywara@arm.com> wrote:
>
>> ?Any future SoCs could then just use that compatible and would describe
>> ?the SoC details in the DT, like it's meant to be and like we do already,
>> ?but extended by putting the mux value in there as well.
>> ?So the only kernel contribution would then be the DT, really, (...)
>
> Your different positions have existed since the inception of the
> pinctrl subsystem:
>
> - One camp (myself included) wanted to describe the hardware mostly
> ??in the driver: functions, groups etc are tables in the driver file.
>
> - Another camp (OMAP included) think that the device tree should take
> ??store most things: groups functions, etc.
>
> What we know for sure should be described in DT is how different
> IP blocks are connected in an SoC (e.g. interrupts, clocks, DMA
> channels, regulators) and on the of course outside of the SoC, on
> the board.
>
> The question here is whether the way a hardware has instantiated
> a certain IP block when doing physical compilation in their
> Verilog, VHDL or SystemC files, is something that should be
> described in DT.
>
> Many companies have developed tools to
> extract this data from their hardware design files and provide
> it to developers as a blob och incomprehensible data, such was
> the situation for OMAP for example. So to them it made most
> sense to implement pinctrl-single, just parsing that data into
> DTS(I) files.
>
> Other companies (such as STMicroelectronics) instead put a
> team of people to write a datasheet with a special chapter
> on how pins etc are connected, and programmers are given
> this datasheet and need to again type in the data and define
> groups etc.
>
> Whether parametrization of a HW block should be done in the
> driver file from the compatible string or with custom attributes
> in the node is not a simple answer to the question. OF is vague
> on this kind of things: both solutions exist.
>
> Allwinner and Qualcomm authors faced a situation such as that
> they were given a code dump and no datasheet and no data
> tables either. That creates an especially complicated situation
> where none of the above scenarios apply.
Allwinner do give user manual about the pin controller, and they're
used when we write the pinctrl-sunxi driver.
>
> What we/you need to ask: what is most helpful for the Allwinner
> community? What makes the barrier low for new contributions,
> and makes it easiest to cooperate?
>
> I try to live by this motto from IETF:
>
> ???"rough consensus and running code"
>
> Please do the same.
>
> Yours,
> Linus Walleij
^ permalink raw reply
* [arm:phy-cleanup 10/10] arch/mips/cavium-octeon/octeon-platform.c:1064:15: error: expected declaration specifiers or '...' before string constant
From: kbuild test robot @ 2017-01-19 13:08 UTC (permalink / raw)
To: linux-arm-kernel
tree: git://git.armlinux.org.uk/~rmk/linux-arm.git phy-cleanup
head: ef8cb7d5f838770f22cae0e20fee8d1157fc88fd
commit: ef8cb7d5f838770f22cae0e20fee8d1157fc88fd [10/10] net: dsa: remove unnecessary phy*.h includes
config: mips-cavium_octeon_defconfig (attached as .config)
compiler: mips64-linux-gnuabi64-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout ef8cb7d5f838770f22cae0e20fee8d1157fc88fd
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
>> arch/mips/cavium-octeon/octeon-platform.c:1064:15: error: expected declaration specifiers or '...' before string constant
MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/mips/cavium-octeon/octeon-platform.c:1065:16: error: expected declaration specifiers or '...' before string constant
MODULE_LICENSE("GPL");
^~~~~
arch/mips/cavium-octeon/octeon-platform.c:1066:20: error: expected declaration specifiers or '...' before string constant
MODULE_DESCRIPTION("Platform driver for Octeon SOC");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +1064 arch/mips/cavium-octeon/octeon-platform.c
d617f9e9 David Daney 2013-12-03 1048 break;
d617f9e9 David Daney 2013-12-03 1049 default:
d617f9e9 David Daney 2013-12-03 1050 break;
d617f9e9 David Daney 2013-12-03 1051 }
d617f9e9 David Daney 2013-12-03 1052 }
d617f9e9 David Daney 2013-12-03 1053 }
d617f9e9 David Daney 2013-12-03 1054
7ed18152 David Daney 2012-07-05 1055 return 0;
7ed18152 David Daney 2012-07-05 1056 }
7ed18152 David Daney 2012-07-05 1057
7ed18152 David Daney 2012-07-05 1058 static int __init octeon_publish_devices(void)
7ed18152 David Daney 2012-07-05 1059 {
7ed18152 David Daney 2012-07-05 1060 return of_platform_bus_probe(NULL, octeon_ids, NULL);
7ed18152 David Daney 2012-07-05 1061 }
8074d782 Aaro Koskinen 2016-08-23 1062 arch_initcall(octeon_publish_devices);
7ed18152 David Daney 2012-07-05 1063
512254ba David Daney 2009-09-16 @1064 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
512254ba David Daney 2009-09-16 1065 MODULE_LICENSE("GPL");
512254ba David Daney 2009-09-16 1066 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
:::::: The code at line 1064 was first introduced by commit
:::::: 512254ba8383c5dd7eca6819d0da1ce2fe9ede47 MIPS: Octeon: Move some platform device registration to its own file.
:::::: TO: David Daney <ddaney@caviumnetworks.com>
:::::: CC: Ralf Baechle <ralf@linux-mips.org>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 15852 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170119/93fef9e0/attachment-0001.gz>
^ permalink raw reply
* [PATCH 3/3] ARM: configs: omap2plus_defconfig: Enable support for RTC M41T80
From: Teresa Remmet @ 2017-01-19 13:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484831270-7251-1-git-send-email-t.remmet@phytec.de>
The phyCORE-AM335x SoM has a RV4162 RTC populated which is supported
by the M41T80 driver. Enabled it so make the RTC support on the SoM
available.
Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
---
arch/arm/configs/omap2plus_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 0c2bf2d..75b5b73 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -414,6 +414,7 @@ CONFIG_LEDS_TRIGGER_GPIO=m
CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_M41T80=m
CONFIG_RTC_DRV_TWL92330=y
CONFIG_RTC_DRV_TWL4030=m
CONFIG_RTC_DRV_PALMAS=m
--
1.9.1
^ permalink raw reply related
* [PATCH 2/3] ARM: configs: omap2plus_defconfig: Enable support for micrell phys
From: Teresa Remmet @ 2017-01-19 13:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484831270-7251-1-git-send-email-t.remmet@phytec.de>
The phyCORE-AM335x SoM with PCM-953 carrierboard has a
KSZ9021 phy mounted. To add support for this we need to enable
the micrell phy driver in the config.
Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
---
arch/arm/configs/omap2plus_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 195c98b..0c2bf2d 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -168,6 +168,7 @@ CONFIG_TI_CPTS=y
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_NET_VENDOR_WIZNET is not set
CONFIG_AT803X_PHY=y
+CONFIG_MICREL_PHY=y
CONFIG_SMSC_PHY=y
CONFIG_USB_USBNET=m
CONFIG_USB_NET_SMSC75XX=m
--
1.9.1
^ permalink raw reply related
* [PATCH 1/3] ARM: dts: Add support for phyCORE-AM335x PCM-953 carrier board
From: Teresa Remmet @ 2017-01-19 13:07 UTC (permalink / raw)
To: linux-arm-kernel
The phyCORE-AM335x development kit is a combination of the
phyCORE-AM335x SoM and a PCM-953 carrier board. The features
of the PCM-953 are:
* ETH phy on carrier board: 1x RGMII
* 1x CAN
* Up to 4x UART
* USB0 (otg)
* USB1 (host)
* SD slot
* User gpio-keys
* User LEDs
Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
Reviewed-by: Wadim Egorov <w.egorov@phytec.de>
---
.../devicetree/bindings/arm/omap/omap.txt | 3 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/am335x-pcm-953.dtsi | 303 +++++++++++++++++++++
arch/arm/boot/dts/am335x-phycore-rdk.dts | 27 ++
4 files changed, 334 insertions(+)
create mode 100644 arch/arm/boot/dts/am335x-pcm-953.dtsi
create mode 100644 arch/arm/boot/dts/am335x-phycore-rdk.dts
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 05f95c3..8219b2c 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -151,6 +151,9 @@ Boards:
- AM335X SBC-T335 : single board computer, built around the Sitara AM3352/4
compatible = "compulab,sbc-t335", "compulab,cm-t335", "ti,am33xx"
+- AM335X phyCORE-AM335x: Development kit
+ compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx"
+
- OMAP5 EVM : Evaluation Module
compatible = "ti,omap5-evm", "ti,omap5"
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 7327250..dd71afe 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -573,6 +573,7 @@ dtb-$(CONFIG_SOC_AM33XX) += \
am335x-lxm.dtb \
am335x-nano.dtb \
am335x-pepper.dtb \
+ am335x-phycore-rdk.dtb \
am335x-shc.dtb \
am335x-sbc-t335.dtb \
am335x-sl50.dtb \
diff --git a/arch/arm/boot/dts/am335x-pcm-953.dtsi b/arch/arm/boot/dts/am335x-pcm-953.dtsi
new file mode 100644
index 0000000..54a171d
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-pcm-953.dtsi
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2014-2017 Phytec Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ * Teresa Remmet <t.remmet@phytec.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Phytec AM335x PCM-953";
+ compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx";
+
+ user_leds: user_leds {
+ compatible = "gpio-leds";
+ };
+
+ user_buttons: user_buttons {
+ compatible = "gpio-keys";
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ vcc3v3: fixedregulator at 1 {
+ compatible = "regulator-fixed";
+ };
+
+ vcc1v8: fixedregulator at 2 {
+ compatible = "regulator-fixed";
+ };
+ };
+};
+
+/* CAN */
+&am33xx_pinmux {
+ dcan1_pins: pinmux_dcan1 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x980, PIN_OUTPUT_PULLUP | MUX_MODE2) /* uart1_rxd.dcan1_tx_mux2 */
+ AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_txd.dcan1_rx_mux2 */
+ >;
+ };
+};
+
+&dcan1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcan1_pins>;
+ status = "okay";
+};
+
+/* Ethernet */
+&am33xx_pinmux {
+ ethernet1_pins: pinmux_ethernet1 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x840, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a0.rgmii2_tctl */
+ AM33XX_IOPAD(0x844, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a1.rgmii2_rctl */
+ AM33XX_IOPAD(0x848, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a2.rgmii2_td3 */
+ AM33XX_IOPAD(0x84c, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a3.rgmii2_td2 */
+ AM33XX_IOPAD(0x850, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a4.rgmii2_td1 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a5.rgmii2_td0 */
+ AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* gpmc_a6.rgmii2_tclk */
+ AM33XX_IOPAD(0x85c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a7.rgmii2_rclk */
+ AM33XX_IOPAD(0x860, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a8.rgmii2_rd3 */
+ AM33XX_IOPAD(0x864, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a9.rgmii2_rd2 */
+ AM33XX_IOPAD(0x868, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a10.rgmii2_rd1 */
+ AM33XX_IOPAD(0x86c, PIN_INPUT_PULLDOWN | MUX_MODE2) /* gpmc_a11.rgmii2_rd0 */
+ >;
+ };
+};
+
+&cpsw_emac1 {
+ phy-handle = <&phy1>;
+ phy-mode = "rgmii-id";
+ dual_emac_res_vlan = <2>;
+ status = "okay";
+};
+
+&davinci_mdio {
+ phy1: ethernet-phy at 1 {
+ reg = <2>;
+
+ /* Register 260 (104h) ? RGMII Clock and Control Pad Skew */
+ rxc-skew-ps = <1400>;
+ rxdv-skew-ps = <0>;
+ txc-skew-ps = <1400>;
+ txen-skew-ps = <0>;
+ /* Register 261 (105h) ? RGMII RX Data Pad Skew */
+ rxd3-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd0-skew-ps = <0>;
+ /* Register 262 (106h) ? RGMII TX Data Pad Skew */
+ txd3-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd0-skew-ps = <0>;
+ };
+};
+
+&mac {
+ slaves = <2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <ðernet0_pins ðernet1_pins>;
+ dual_emac;
+};
+
+/* Misc */
+&am33xx_pinmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&cb_gpio_pins>;
+
+ cb_gpio_pins: pinmux_cb_gpio {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x968, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* uart0_ctsn.gpio1_8 */
+ AM33XX_IOPAD(0x96c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* uart0_rtsn.gpio1_9 */
+ >;
+ };
+};
+
+/* MMC */
+&am33xx_pinmux {
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x8f0, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+ AM33XX_IOPAD(0x8f4, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+ AM33XX_IOPAD(0x8f8, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+ AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+ AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+ AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+ AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE7) /* spi0_cs1.mmc0_sdcd */
+ >;
+ };
+};
+
+&mmc1 {
+ vmmc-supply = <&vcc3v3>;
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+/* Power */
+&vcc3v3 {
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+};
+
+&vcc1v8 {
+ regulator-name = "vcc1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+};
+
+/* UARTs */
+&am33xx_pinmux {
+ uart0_pins: pinmux_uart0 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ >;
+ };
+
+ uart1_pins: pinmux_uart1 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rxd.uart1_rxd */
+ AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_txd.uart1_txd */
+ AM33XX_IOPAD(0x978, PIN_INPUT | MUX_MODE0) /* uart1_ctsn.uart1_ctsn */
+ AM33XX_IOPAD(0x97c, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart1_rtsn.uart1_rtsn */
+ >;
+ };
+
+ uart2_pins: pinmux_uart2 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_tx_clk.uart2_rxd */
+ AM33XX_IOPAD(0x930, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_rx_clk.uart2_txd */
+ >;
+ };
+
+ uart3_pins: pinmux_uart3 {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE1) /* mii1_rxd3.uart3_rxd */
+ AM33XX_IOPAD(0x938, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd2.uart3_txd */
+ >;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ status = "okay";
+};
+
+/* USB */
+&cppi41dma {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+/* User IO */
+&am33xx_pinmux {
+ user_buttons_pins: pinmux_user_buttons {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x9e4, PIN_INPUT_PULLDOWN | MUX_MODE7) /* emu0.gpio3_7 */
+ AM33XX_IOPAD(0x9e8, PIN_INPUT_PULLDOWN | MUX_MODE7) /* emu1.gpio3_8 */
+ >;
+ };
+
+ user_leds_pins: pinmux_user_leds {
+ pinctrl-single,pins = <
+ AM33XX_IOPAD(0x880, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn1.gpio1_30 */
+ AM33XX_IOPAD(0x884, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.gpio1_31 */
+ >;
+ };
+};
+
+&user_buttons {
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_buttons_pins>;
+ status = "okay";
+
+ button at 0 {
+ label = "home";
+ linux,code = <KEY_HOME>;
+ gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+ gpio-key,wakeup;
+ };
+
+ button at 1 {
+ label = "menu";
+ linux,code = <KEY_MENU>;
+ gpios = <&gpio3 8 GPIO_ACTIVE_HIGH>;
+ gpio-key,wakeup;
+ };
+};
+
+&user_leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_leds_pins>;
+ status = "okay";
+
+ green {
+ label = "green:user";
+ gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "gpio";
+ default-state = "on";
+ };
+
+ yellow {
+ label = "yellow:user";
+ gpios = <&gpio1 31 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "gpio";
+ default-state = "on";
+ };
+};
diff --git a/arch/arm/boot/dts/am335x-phycore-rdk.dts b/arch/arm/boot/dts/am335x-phycore-rdk.dts
new file mode 100644
index 0000000..305f0b3
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-phycore-rdk.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+
+#include "am335x-phycore-som.dtsi"
+#include "am335x-pcm-953.dtsi"
+
+/* SoM */
+&i2c_eeprom {
+ status = "okay";
+};
+
+&i2c_rtc {
+ status = "okay";
+};
+
+&serial_flash {
+ status = "okay";
+
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 09/13] sata: ahci: export ahci_do_hardreset() locally
From: Tejun Heo @ 2017-01-19 12:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMpxmJULuF3cB7+Vy_qeWkTjooHvx8yk70w59Q=XNd0aAREcuw@mail.gmail.com>
On Thu, Jan 19, 2017 at 11:55:24AM +0100, Bartosz Golaszewski wrote:
> 2017-01-18 19:28 GMT+01:00 Tejun Heo <tj@kernel.org>:
> > Hello, Bartosz.
> >
> > On Wed, Jan 18, 2017 at 02:19:57PM +0100, Bartosz Golaszewski wrote:
> >> We need a way to retrieve the information about the online state of
> >> the link in the ahci-da850 driver.
> >>
> >> Create a new function: ahci_do_hardreset() which is called from
> >> ahci_hardreset() for backwards compatibility, but has an additional
> >> argument: 'online' - which can be used to check if the link is online
> >> after this function returns.
> >
> > Please just add @online to ahci_hardreset() and update the callers.
> > Other than that, the sata changes look good to me.
> >
>
> Are you sure? There are 23 places in drivers/ata/ where the .hardreset
> callback is assigned. I'd prefer not to change the drivers I can't
> test. Besides all other **reset callbacks take three arguments -
> should we really only change one of them for a single driver's needs?
Ah, didn't realize this was the callback, sorry. What you did is
perfect. Please disregard my comment.
Thanks.
--
tejun
^ permalink raw reply
* [PATCH] ARM: dts: fix SolidRun iMX6 platforms
From: Russell King @ 2017-01-19 12:44 UTC (permalink / raw)
To: linux-arm-kernel
Removal of skeleton.dtsi from imx6qdl.dtsi caused a regression on
SolidRun platforms as the /chosen and /memory nodes are no longer
populated. Fix this by adding the nodes into the platform .dtsi
files.
Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0x0
Linux version 4.10.0-rc3+ (rmk at rmk-PC.arm.linux.org.uk) (gcc version 4.7.4 (GCC) ) #2066 SMP Thu Jan 19 12:31:19 GMT 2017
CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
OF: fdt:Machine model: SolidRun Cubox-i Dual/Quad
INITRD: 0x20000000+0x001cd000 is not a memory region - disabling initrd
cma: Failed to reserve 256 MiB
Memory policy: Data cache writealloc
Kernel panic - not syncing: ERROR: Failed to allocate 0x2000 bytes below 0x0.
CPU: 0 PID: 0 Comm: swapper Not tainted 4.10.0-rc3+ #2066
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
Backtrace: invalid frame pointer 0xc09e5e44c
---[ end Kernel panic - not syncing: ERROR: Failed to allocate 0x2000 bytes below 0x0.
Fixes: 7f107887d199 ("ARM: dts: imx: Remove skeleton.dtsi")
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 6 ++++++
arch/arm/boot/dts/imx6qdl-hummingboard.dtsi | 2 ++
2 files changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
index ff41f83551de..69e3a848ee74 100644
--- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
@@ -44,6 +44,12 @@
#include <dt-bindings/gpio/gpio.h>
/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory { device_type = "memory"; reg = <0 0>; };
+
ir_recv: ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio3 9 1>;
diff --git a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
index a5e5356cdc6a..ae2feb882193 100644
--- a/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
@@ -46,6 +46,8 @@
stdout-path = &uart1;
};
+ memory { device_type = "memory"; reg = <0 0>; };
+
ir_recv: ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
--
2.7.4
^ permalink raw reply related
* [PATCH v20 16/17] clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped timer
From: Hanjun Guo @ 2017-01-19 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CADyBb7tpDynA0EEUkFZXpUAksjvXeUzuoC82GnbVA2O1w2T22g@mail.gmail.com>
On 2017/1/19 18:02, Fu Wei wrote:
> Hi Hanjun,
>
> On 19 January 2017 at 17:16, Hanjun Guo <hanjun.guo@linaro.org> wrote:
>> On 2017/1/18 21:25, fu.wei at linaro.org wrote:
>>>
>>> From: Fu Wei <fu.wei@linaro.org>
>>>
>>> The patch add memory-mapped timer register support by using the
>>> information provided by the new GTDT driver of ACPI.
>>>
>>> Signed-off-by: Fu Wei <fu.wei@linaro.org>
>>> ---
>>> drivers/clocksource/arm_arch_timer.c | 35
>>> ++++++++++++++++++++++++++++++++---
>>> 1 file changed, 32 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/clocksource/arm_arch_timer.c
>>> b/drivers/clocksource/arm_arch_timer.c
>>> index 79dc004..7ca2da7 100644
>>> --- a/drivers/clocksource/arm_arch_timer.c
>>> +++ b/drivers/clocksource/arm_arch_timer.c
>>> @@ -1077,10 +1077,36 @@ CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem,
>>> "arm,armv7-timer-mem",
>>> arch_timer_mem_of_init);
>>>
>>> #ifdef CONFIG_ACPI_GTDT
>>> -/* Initialize per-processor generic timer */
>>> +static int __init arch_timer_mem_acpi_init(int platform_timer_count)
>>> +{
>>> + struct arch_timer_mem *timer_mem;
>>> + int timer_count, i, ret;
>>> +
>>
>>
>> if (!platform_timer_count)
>> return 0;
>>
>> Did I miss something?
>
> Ah, thanks, I guess I miss this check below.
>
>>
>> Thanks
>> Hanjun
>>
>>
>>> + timer_mem = kcalloc(platform_timer_count, sizeof(*timer_mem),
>>> + GFP_KERNEL);
>>> + if (!timer_mem)
>>> + return -ENOMEM;
>>> +
>>> + ret = acpi_arch_timer_mem_init(timer_mem, &timer_count);
>>> + if (ret || !timer_count)
>>> + goto error;
>>> +
>>> + for (i = 0; i < timer_count; i++) {
>>> + ret = arch_timer_mem_init(timer_mem);
>>> + if (!ret)
>>> + break;
>>> + timer_mem++;
>>> + }
>>> +
>>> +error:
>>> + kfree(timer_mem);
>>> + return ret;
>>> +}
>>> +
>>> +/* Initialize per-processor generic timer and memory-mapped timer(if
>>> present) */
>>> static int __init arch_timer_acpi_init(struct acpi_table_header *table)
>>> {
>>> - int ret;
>>> + int ret, platform_timer_count;
>>>
>>> if (arch_timers_present & ARCH_TIMER_TYPE_CP15) {
>>> pr_warn("already initialized, skipping\n");
>>> @@ -1089,7 +1115,7 @@ static int __init arch_timer_acpi_init(struct
>>> acpi_table_header *table)
>>>
>>> arch_timers_present |= ARCH_TIMER_TYPE_CP15;
>>>
>>> - ret = acpi_gtdt_init(table, NULL);
>>> + ret = acpi_gtdt_init(table, &platform_timer_count);
>>> if (ret) {
>>> pr_err("Failed to init GTDT table.\n");
>>> return ret;
>>> @@ -1122,6 +1148,9 @@ static int __init arch_timer_acpi_init(struct
>>> acpi_table_header *table)
>>> if (ret)
>>> return ret;
>>>
>>> + if (arch_timer_mem_acpi_init(platform_timer_count))
>
> + if (platform_timer_count &&
> + arch_timer_mem_acpi_init(platform_timer_count))
It's better.
Thanks
Hanjun
^ permalink raw reply
* [PATCH v20 08/17] clocksource/drivers/arm_arch_timer: Rework counter frequency detection.
From: Hanjun Guo @ 2017-01-19 12:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CADyBb7uGVu6Po4hCD45WOrQvWYwZgtSbE5z9rbRa7gZ1P5-4tg@mail.gmail.com>
On 2017/1/19 17:44, Fu Wei wrote:
> Hi Hanjun,
>
> On 19 January 2017 at 16:02, Hanjun Guo <hanjun.guo@linaro.org> wrote:
>> Hi Fuwei,
>>
>> One comments below.
>>
>>
>> On 2017/1/18 21:25, fu.wei at linaro.org wrote:
>>>
>>> From: Fu Wei <fu.wei@linaro.org>
>>>
>>> The counter frequency detection call(arch_timer_detect_rate) combines two
>>> ways to get counter frequency: system coprocessor register and MMIO timer.
>>> But in a specific timer init code, we only need one way to try:
>>> getting frequency from MMIO timer register will be needed only when we
>>> init MMIO timer; getting frequency from system coprocessor register will
>>> be needed only when we init arch timer.
>>>
>>> This patch separates paths to determine frequency:
>>> Separate out the MMIO frequency and the sysreg frequency detection call,
>>> and use the appropriate one for the counter.
>>>
>>> Signed-off-by: Fu Wei <fu.wei@linaro.org>
>>> ---
>>> drivers/clocksource/arm_arch_timer.c | 40
>>> ++++++++++++++++++++++--------------
>>> 1 file changed, 25 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/clocksource/arm_arch_timer.c
>>> b/drivers/clocksource/arm_arch_timer.c
>>> index 6484f84..9482481 100644
>>> --- a/drivers/clocksource/arm_arch_timer.c
>>> +++ b/drivers/clocksource/arm_arch_timer.c
>>> @@ -488,23 +488,33 @@ static int arch_timer_starting_cpu(unsigned int cpu)
>>> return 0;
>>> }
>>>
>>> -static void arch_timer_detect_rate(void __iomem *cntbase)
>>> +static void __arch_timer_determine_rate(u32 rate)
>>> {
>>> - /* Who has more than one independent system counter? */
>>> - if (arch_timer_rate)
>>> - return;
>>> + /* Check the timer frequency. */
>>> + if (!arch_timer_rate) {
>>> + if (rate)
>>> + arch_timer_rate = rate;
>>> + else
>>> + pr_warn("frequency not available\n");
>>> + } else if (rate && arch_timer_rate != rate) {
>>
>> ^
>> Typo? I think it's "&" here.
>
> Not a typo, It's definitely a ?&&? :-)
>
> Here arch_timer_rate is not zero.
>
> If rate is not zero(that means we got a valid rate), and
> arch_timer_rate != rate ,
> we will print warning message.
Ah, misreading the code, thanks for clarify :)
Hanjun
^ permalink raw reply
* [PATCH V10 2/3] ACPI: Add support for ResourceSource/IRQ domain mapping
From: Lorenzo Pieralisi @ 2017-01-19 12:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAHp75Vem=mCOGVoOpCJFYHcO17mJ9gexsQxa0Pjf4Lbt3hibRA@mail.gmail.com>
On Wed, Jan 18, 2017 at 09:45:56PM +0200, Andy Shevchenko wrote:
[...]
> > +/**
> > + * acpi_irq_get - Look for the ACPI IRQ resource with the given index and
> > + * use it to initialize the given Linux IRQ resource.
> > + * @handle ACPI device handle
> > + * @index ACPI IRQ resource index to lookup
> > + * @res Linux IRQ resource to initialize
>
> Ah, you missed colons after field names:
> * @field1:
>
> > + *
> > + * Return:
>
> Next line: 0 on success
>
> > + * -EINVAL if an error occurs
> > + * -EPROBE_DEFER if the IRQ lookup/conversion failed
> > + */
> > +int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res)
> > +{
>
> > + int rc;
>
> Put this last in the definition block.
>
> > + struct irq_fwspec fwspec;
> > + struct irq_domain *domain;
> > + unsigned long flags;
> > +
> > + rc = acpi_irq_parse_one(handle, index, &fwspec, &flags);
> > + if (rc)
> > + return rc;
> > +
> > + domain = irq_find_matching_fwnode(fwspec.fwnode, DOMAIN_BUS_ANY);
> > + if (!domain)
> > + return -EPROBE_DEFER;
>
> Hmm... Could it be other issues here?
That's a good point. Here probing should be deferred only if we know a
driver capable of handling fwspec.fwnode will have a chance to be
probed/initialized eventually right (which basically means it is
compiled in the kernel and we hope it will probed successfully) ? I am
not sure there is an easy way to detect that in ACPI at the moment, I
suspect it is time we added a linker section (or augment the existing
one used for irqchip early MADT parsing - IRQCHIP_ACPI_DECLARE) for this
purpose I do not see any other option (apart from leaving devices in the
deferred probe list if a driver for the irqchip represented by
fwspec.fwnode is not present in the kernel, which is a bit sloppy, or
resorting to checking Kconfig entries to detect compile time enabled
irqchip drivers).
> > +
> > + rc = irq_create_fwspec_mapping(&fwspec);
> > + if (rc <= 0)
> > + return -EINVAL;
> > +
>
> > + res->start = rc;
> > + res->end = rc;
> > + res->flags = flags;
>
> Perhaps struct resource *r should be a parameter to acpi_irq_parse_one().
Yeah but then you would end up with flags initialized in
acpi_irq_parse_one() and the other resource params (ie start, end) here,
I do not think it is nicer.
Thanks,
Lorenzo
>
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(acpi_irq_get);
> > +
> > +/**
> > * acpi_set_irq_model - Setup the GSI irqdomain information
> > * @model: the value assigned to acpi_irq_model
> > * @fwnode: the irq_domain identifier for mapping and looking up
> > diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> > index c4af003..61423d2 100644
> > --- a/drivers/base/platform.c
> > +++ b/drivers/base/platform.c
> > @@ -102,6 +102,14 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
> > }
> >
> > r = platform_get_resource(dev, IORESOURCE_IRQ, num);
> > + if (r && r->flags & IORESOURCE_DISABLED && ACPI_COMPANION(&dev->dev)) {
>
> has_acpi_companion() ?
>
> > + int ret;
> > +
> > + ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
> > + if (ret)
> > + return ret;
> > + }
>
> > @@ -1450,4 +1458,3 @@ void __init early_platform_cleanup(void)
> > memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
> > }
> > }
> > -
>
> It doesn't belong here.
>
> --
> With Best Regards,
> Andy Shevchenko
^ permalink raw reply
* [PATCH v20 13/17] acpi/arm64: Add GTDT table parse driver
From: Fu Wei @ 2017-01-19 12:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170119111628.GC11176@leverpostej>
Hi Mark,
On 19 January 2017 at 19:16, Mark Rutland <mark.rutland@arm.com> wrote:
> On Thu, Jan 19, 2017 at 06:32:55PM +0800, Fu Wei wrote:
>> On 19 January 2017 at 17:11, Hanjun Guo <hanjun.guo@linaro.org> wrote:
>> > On 2017/1/18 21:25, fu.wei at linaro.org wrote:
>> >> From: Fu Wei <fu.wei@linaro.org>
>
>> >> + else if (!gtdt->platform_timer_count)
>> >> + pr_debug("No Platform Timer.\n");
>> >> + else
>> >> + timer_count = gtdt->platform_timer_count;
>> >> +
>> >> + if (timer_count) {
>> >> + platform_timer = (void *)gtdt +
>> >> gtdt->platform_timer_offset;
>> >> + if (platform_timer < (void *)table +
>> >> + sizeof(struct acpi_table_gtdt)) {
>> >> + pr_err(FW_BUG "invalid timer data.\n");
>> >
>> >
>> > It's ok but I didn't see other ACPI tables parsing did this check,
>> > maybe we can just remove it :)
>>
>> here, I want to make sure the FW is valid.
>> Once there is a FW bug, we could just return with error. :-)
>
> Yes, please keep the check!
Yes, we will keep this check :-)
Thanks!
>
> If anything, it would be nicer for the other ACPI code to verify things
> a little more stringently.
>
> Thanks,
> Mark.
--
Best regards,
Fu Wei
Software Engineer
Red Hat
^ permalink raw reply
* [PATCH 4/6] arm64: dts: mt8173: add reference clock for usb
From: Matthias Brugger @ 2017-01-19 12:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170119093747.GA17213@kroah.com>
On 19/01/17 10:37, Greg Kroah-Hartman wrote:
> On Wed, Jan 18, 2017 at 02:08:25PM +0800, Chunfeng Yun wrote:
>> add 26M reference clock for ssusb and xhci nodes
>>
>> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
>> ---
>> arch/arm64/boot/dts/mediatek/mt8173.dtsi | 6 ++++--
>> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> This patch doesn't apply to my tree :(
>
This patch should go through my tree, but take into account my comment
on patch 3/6. From my point of view this series is not ready to be merged.
Regards,
Matthias
^ permalink raw reply
* [PATCH 2/6] usb: mtu3: add reference clock
From: Matthias Brugger @ 2017-01-19 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484719707-12107-2-git-send-email-chunfeng.yun@mediatek.com>
On 18/01/17 07:08, Chunfeng Yun wrote:
> usually, the reference clock comes from 26M oscillator directly,
> but some SoCs are not, add it for compatibility.
>
> Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
> ---
> drivers/usb/mtu3/mtu3.h | 1 +
> drivers/usb/mtu3/mtu3_plat.c | 21 +++++++++++++++++++--
> 2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
> index ba9df71..aa6fd6a 100644
> --- a/drivers/usb/mtu3/mtu3.h
> +++ b/drivers/usb/mtu3/mtu3.h
> @@ -225,6 +225,7 @@ struct ssusb_mtk {
> /* common power & clock */
> struct regulator *vusb33;
> struct clk *sys_clk;
> + struct clk *ref_clk;
> /* otg */
> struct otg_switch_mtk otg_switch;
> enum usb_dr_mode dr_mode;
> diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
> index 6344859..19a345d 100644
> --- a/drivers/usb/mtu3/mtu3_plat.c
> +++ b/drivers/usb/mtu3/mtu3_plat.c
> @@ -123,7 +123,13 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
> ret = clk_prepare_enable(ssusb->sys_clk);
> if (ret) {
> dev_err(ssusb->dev, "failed to enable sys_clk\n");
> - goto clk_err;
> + goto sys_clk_err;
> + }
> +
> + ret = clk_prepare_enable(ssusb->ref_clk);
> + if (ret) {
> + dev_err(ssusb->dev, "failed to enable ref_clk\n");
> + goto ref_clk_err;
> }
>
> ret = ssusb_phy_init(ssusb);
> @@ -143,8 +149,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
> phy_err:
> ssusb_phy_exit(ssusb);
> phy_init_err:
> + clk_disable_unprepare(ssusb->ref_clk);
> +ref_clk_err:
> clk_disable_unprepare(ssusb->sys_clk);
> -clk_err:
> +sys_clk_err:
> regulator_disable(ssusb->vusb33);
> vusb33_err:
>
> @@ -154,6 +162,7 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
> static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
> {
> clk_disable_unprepare(ssusb->sys_clk);
> + clk_disable_unprepare(ssusb->ref_clk);
> regulator_disable(ssusb->vusb33);
> ssusb_phy_power_off(ssusb);
> ssusb_phy_exit(ssusb);
> @@ -216,6 +225,12 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
> return PTR_ERR(ssusb->sys_clk);
> }
>
> + ssusb->ref_clk = devm_clk_get(dev, "ref_ck");
> + if (IS_ERR(ssusb->ref_clk)) {
> + dev_err(dev, "failed to get ref clock\n");
> + return PTR_ERR(ssusb->ref_clk);
> + }
> +
That would break older dts bindings, right?
ref_ck must be optional for the code.
Regards,
Matthias
^ permalink raw reply
* [PATCH RESEND v8 1/4] arm64: arch_timer: Add device tree binding for hisilicon-161010101 erratum
From: Ding Tianhong @ 2017-01-19 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170119121008.GE11176@leverpostej>
On 2017/1/19 20:10, Mark Rutland wrote:
> On Thu, Jan 19, 2017 at 07:46:43PM +0800, Ding Tianhong wrote:
>> This erratum describes a bug in logic outside the core, so MIDR can't be
>> used to identify its presence, and reading an SoC-specific revision
>> register from common arch timer code would be awkward. So, describe it
>> in the device tree.
>>
>> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
>> Acked-by: Rob Herring <robh@kernel.org>
>> ---
>> Documentation/devicetree/bindings/arm/arch_timer.txt | 8 ++++++++
>> 1 file changed, 8 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
>> index ad440a2..9116934 100644
>> --- a/Documentation/devicetree/bindings/arm/arch_timer.txt
>> +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
>> @@ -31,6 +31,14 @@ to deliver its interrupts via SPIs.
>> This also affects writes to the tval register, due to the implicit
>> counter read.
>>
>> +- hisilicon,erratum-161010101 : A boolean property. Indicates the presence of
>> + erratum 161010101, which says that reading the counter is unreliable unless
>> + reading twice on the register and the value of the second read is larger
>> + than the first by less than 32. If the verification is unsuccessful, then
>> + discard the value of this read and repeat this procedure until the verification
>> + is successful. This also affects writes to the tval register, due to the
>> + implicit counter read.
>
> This describes the workaround, which shouldn't be necessary.
>
> My understanding (from the cover letter) is that reads of the
> {virtual,physical} counters may return a value precisely 32 above the
> true value.
>
> So it would be better to say:
>
> - hisilicon,erratum-161010101 : A boolean property. Indicates the
> presence of Hisilicon erratum 161010101, which says that reading the
> counters is unreliable in some cases, and reads may return a value 32
> beyond the correct value. This also affects writes to the tval
> registers, due to the implicit counter read.
>
> Thanks,
> Mark.
Looks more accurate.
Thanks.
Ding
>
> .
>
^ permalink raw reply
* [PATCH v8 2/4] arm64: arch_timer: Introduce a generic erratum handing mechanism for fsl-a008585
From: Ding Tianhong @ 2017-01-19 12:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <eeab7907-77c3-163c-f489-319012a13913@arm.com>
On 2017/1/19 19:59, Marc Zyngier wrote:
> On 19/01/17 11:14, Ding Tianhong wrote:
>> The workaround for hisilicon,161010101 will check the return value of the system counter
>> by different way, in order to distinguish with the fsl-a008585 workaround, introduce
>> a new generic erratum handing mechanism for fsl-a008585 and rename some functions.
>>
>> After discussion with Marc and Will, a consensus decision was made to remove the commandline
>> parameter for enabling fsl,erratum-a008585 erratum.
>>
>> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
>> ---
>> Documentation/admin-guide/kernel-parameters.txt | 9 --
>> arch/arm64/include/asm/arch_timer.h | 38 +++------
>> drivers/clocksource/Kconfig | 8 ++
>> drivers/clocksource/arm_arch_timer.c | 105 ++++++++++++++----------
>> 4 files changed, 84 insertions(+), 76 deletions(-)
>>
>> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
>> index 21e2d88..76437ad 100644
>> --- a/Documentation/admin-guide/kernel-parameters.txt
>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>> @@ -539,15 +539,6 @@
>> loops can be debugged more effectively on production
>> systems.
>>
>> - clocksource.arm_arch_timer.fsl-a008585=
>> - [ARM64]
>> - Format: <bool>
>> - Enable/disable the workaround of Freescale/NXP
>> - erratum A-008585. This can be useful for KVM
>> - guests, if the guest device tree doesn't show the
>> - erratum. If unspecified, the workaround is
>> - enabled based on the device tree.
>> -
>> clearcpuid=BITNUM [X86]
>> Disable CPUID feature X for the kernel. See
>> arch/x86/include/asm/cpufeatures.h for the valid bit
>> diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
>> index eaa5bbe..b4b3400 100644
>> --- a/arch/arm64/include/asm/arch_timer.h
>> +++ b/arch/arm64/include/asm/arch_timer.h
>> @@ -29,41 +29,29 @@
>>
>> #include <clocksource/arm_arch_timer.h>
>>
>> -#if IS_ENABLED(CONFIG_FSL_ERRATUM_A008585)
>> +#if IS_ENABLED(CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND)
>> extern struct static_key_false arch_timer_read_ool_enabled;
>> -#define needs_fsl_a008585_workaround() \
>> +#define needs_unstable_timer_counter_workaround() \
>> static_branch_unlikely(&arch_timer_read_ool_enabled)
>> #else
>> -#define needs_fsl_a008585_workaround() false
>> +#define needs_unstable_timer_counter_workaround() false
>> #endif
>>
>> -u32 __fsl_a008585_read_cntp_tval_el0(void);
>> -u32 __fsl_a008585_read_cntv_tval_el0(void);
>> -u64 __fsl_a008585_read_cntvct_el0(void);
>>
>> -/*
>> - * The number of retries is an arbitrary value well beyond the highest number
>> - * of iterations the loop has been observed to take.
>> - */
>> -#define __fsl_a008585_read_reg(reg) ({ \
>> - u64 _old, _new; \
>> - int _retries = 200; \
>> - \
>> - do { \
>> - _old = read_sysreg(reg); \
>> - _new = read_sysreg(reg); \
>> - _retries--; \
>> - } while (unlikely(_old != _new) && _retries); \
>> - \
>> - WARN_ON_ONCE(!_retries); \
>> - _new; \
>> -})
>> +struct arch_timer_erratum_workaround {
>> + const char *id; /* Indicate the Erratum ID */
>> + u32 (*read_cntp_tval_el0)(void);
>> + u32 (*read_cntv_tval_el0)(void);
>> + u64 (*read_cntvct_el0)(void);
>> +};
>> +
>> +extern const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround;
>>
>> #define arch_timer_reg_read_stable(reg) \
>> ({ \
>> u64 _val; \
>> - if (needs_fsl_a008585_workaround()) \
>> - _val = __fsl_a008585_read_##reg(); \
>> + if (needs_unstable_timer_counter_workaround()) \
>> + _val = timer_unstable_counter_workaround->read_##reg();\
>> else \
>> _val = read_sysreg(reg); \
>> _val; \
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 4866f7a..04c2b93 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -325,10 +325,18 @@ config ARM_ARCH_TIMER_EVTSTREAM
>> This must be disabled for hardware validation purposes to detect any
>> hardware anomalies of missing events.
>>
>> +config ARM_ARCH_TIMER_OOL_WORKAROUND
>> + bool "Workaround for arm arch timer unstable counter"
>
> Please drop the message. We don't want that option to be selectable by a
> user, but only selected if an erratum that depends on it is enabled.
>
OK
Thanks
Ding
>> + depends on FSL_ERRATUM_A008585
>> + help
>> + This option would only be enabled by Freescale/NXP Erratum A-008585
>> + or something else chip has similar erratum.
>> +
>> config FSL_ERRATUM_A008585
>> bool "Workaround for Freescale/NXP Erratum A-008585"
>> default y
>> depends on ARM_ARCH_TIMER && ARM64
>> + select ARM_ARCH_TIMER_OOL_WORKAROUND
>> help
>> This option enables a workaround for Freescale/NXP Erratum
>> A-008585 ("ARM generic timer may contain an erroneous
>
> Thanks,
>
> M.
>
^ permalink raw reply
* [PATCH RESEND v8 1/4] arm64: arch_timer: Add device tree binding for hisilicon-161010101 erratum
From: Mark Rutland @ 2017-01-19 12:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484826406-16348-2-git-send-email-dingtianhong@huawei.com>
On Thu, Jan 19, 2017 at 07:46:43PM +0800, Ding Tianhong wrote:
> This erratum describes a bug in logic outside the core, so MIDR can't be
> used to identify its presence, and reading an SoC-specific revision
> register from common arch timer code would be awkward. So, describe it
> in the device tree.
>
> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
> Documentation/devicetree/bindings/arm/arch_timer.txt | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
> index ad440a2..9116934 100644
> --- a/Documentation/devicetree/bindings/arm/arch_timer.txt
> +++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
> @@ -31,6 +31,14 @@ to deliver its interrupts via SPIs.
> This also affects writes to the tval register, due to the implicit
> counter read.
>
> +- hisilicon,erratum-161010101 : A boolean property. Indicates the presence of
> + erratum 161010101, which says that reading the counter is unreliable unless
> + reading twice on the register and the value of the second read is larger
> + than the first by less than 32. If the verification is unsuccessful, then
> + discard the value of this read and repeat this procedure until the verification
> + is successful. This also affects writes to the tval register, due to the
> + implicit counter read.
This describes the workaround, which shouldn't be necessary.
My understanding (from the cover letter) is that reads of the
{virtual,physical} counters may return a value precisely 32 above the
true value.
So it would be better to say:
- hisilicon,erratum-161010101 : A boolean property. Indicates the
presence of Hisilicon erratum 161010101, which says that reading the
counters is unreliable in some cases, and reads may return a value 32
beyond the correct value. This also affects writes to the tval
registers, due to the implicit counter read.
Thanks,
Mark.
^ permalink raw reply
* [PATCH] ARM: smp: Remove CPU: shutdown notice
From: Sergey Senozhatsky @ 2017-01-19 12:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1041c46f-13e7-4446-33e0-75eee9ffb91f@gmail.com>
On (01/18/17 11:56), Florian Fainelli wrote:
[..]
> >>> CPU hotplug isn't a fast operation anyway - it's also fairly disruptive
> >>> in that it uses stop_machine() to halt activity everywhere while taking
> >>> the CPU offline.
> >>
> >> We have a test that consists in shutting down all CPUs as frequently as
> >> we can and do this for about 2 million iterations which takes roughly
> >> 24h, and this printk slows thing down by a reasonable amount. Here are
> >> some numbers on 500 hotplug operations:
> >>
> >> w/ printk:
> >> real 0m9.997s
> >> user 0m0.725s
> >> sys 0m3.030s
> >> #
> >>
> >> w/o printk:
> >> real 0m8.547s
> >> user 0m0.436s
> >> sys 0m1.838s
> >
> > I am curious that a single printk() might make such a big difference.
>
> It does, because of how printk() is implemented (there is nothing wrong
> with it, just slow by nature and how the UART gets written to as well).
>
> >
> > One reason might be that the messages are pushed to a "slow" console.
>
> 115200 UART, yes that's slow, but not unusual.
>
> >
> > Another reason might be that there are many other messages printed
> > on the system and there is a contention on logbuf_lock or other
> > console related locks.
>
> The other messages being printed are those from the hotplug script that
> I run which just checkpoints its running every 50 instances, so it does
> not occur that often, the console really is not busy, which really
> extracts the overhead of printing "CPU: shutdown".
there is also console_cpu_notify(), which basically serializes all
CPU hotplug events. and that's a sleepable console_lock(), followed
by a potentially long console_unlock(). for hotplug each notification.
static int console_cpu_notify(unsigned int cpu)
{
if (!cpuhp_tasks_frozen) {
console_lock();
console_unlock();
}
return 0;
}
out of curiosity, does the change below improve anything in your test?
---
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7180088cbb23..72e86e06c4e4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2035,8 +2035,9 @@ void resume_console(void)
static int console_cpu_notify(unsigned int cpu)
{
if (!cpuhp_tasks_frozen) {
- console_lock();
- console_unlock();
+ /* If trylock fails, someone else is doing the printing */
+ if (console_trylock())
+ console_unlock();
}
return 0;
}
^ permalink raw reply related
* [PATCH 4/4] ARM: dts: imx7: Add "LPSR" to LPSR iomux pin names
From: Fabio Estevam @ 2017-01-19 12:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170119090924.19636-5-s.hauer@pengutronix.de>
On Thu, Jan 19, 2017 at 7:09 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> The i.MX7 has two iomux controllers. the iomuxc and the iomuxc_lpsr.
> In a board dts we have to make sure that both controllers are supplied
> with the correct pins. It's way too easy to do this wrong since only
> a look into the reference manual can reveal which pins belong to which
> controller. To make this clearer add "LPSR" to the pin names which
> belong to the LPSR controller.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
I like this idea!
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH 3/4] ARM: dts: imx7d-cl-som: Fix OTG power pinctrl
From: Fabio Estevam @ 2017-01-19 12:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170119090924.19636-4-s.hauer@pengutronix.de>
On Thu, Jan 19, 2017 at 7:09 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> GPIO01_IO05 is controlled by the LPSR iomux controller, so attach
> the corresponding pin to this controller.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox