Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cpufreq: s3c64xx: remove incorrect __init annotation
From: Arnd Bergmann @ 2016-12-16  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

s3c64xx_cpufreq_config_regulator is incorrectly annotated
as __init, since the caller is also not init:

WARNING: vmlinux.o(.text+0x92fe1c): Section mismatch in reference from the function s3c64xx_cpufreq_driver_init() to the function .init.text:s3c64xx_cpufreq_config_regulator()

With modern gcc versions, the function gets inline, so we don't
see the warning, this only happens with gcc-4.6 and older.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/cpufreq/s3c64xx-cpufreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 176e84cc3991..0cb9040eca49 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -107,7 +107,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
 }
 
 #ifdef CONFIG_REGULATOR
-static void __init s3c64xx_cpufreq_config_regulator(void)
+static void s3c64xx_cpufreq_config_regulator(void)
 {
 	int count, v, i, found;
 	struct cpufreq_frequency_table *freq;
-- 
2.9.0

^ permalink raw reply related

* [PATCH] ARM: imx: remove unused device definitions
From: Arnd Bergmann @ 2016-12-16  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

I stumbled over these during build testing, they are evidently
not referenced anywhere any more.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm/mach-imx/devices/platform-flexcan.c         |  9 ---------
 arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c | 10 ----------
 2 files changed, 19 deletions(-)

diff --git a/arch/arm/mach-imx/devices/platform-flexcan.c b/arch/arm/mach-imx/devices/platform-flexcan.c
index 55d61eaf63c6..8a1a2fc4ce10 100644
--- a/arch/arm/mach-imx/devices/platform-flexcan.c
+++ b/arch/arm/mach-imx/devices/platform-flexcan.c
@@ -19,15 +19,6 @@
 #define imx_flexcan_data_entry(soc, _id, _hwid, _size)			\
 	[_id] = imx_flexcan_data_entry_single(soc, _id, _hwid, _size)
 
-#ifdef CONFIG_SOC_IMX25
-const struct imx_flexcan_data imx25_flexcan_data[] __initconst = {
-#define imx25_flexcan_data_entry(_id, _hwid)				\
-	imx_flexcan_data_entry(MX25, _id, _hwid, SZ_16K)
-	imx25_flexcan_data_entry(0, 1),
-	imx25_flexcan_data_entry(1, 2),
-};
-#endif /* ifdef CONFIG_SOC_IMX25 */
-
 #ifdef CONFIG_SOC_IMX35
 const struct imx_flexcan_data imx35_flexcan_data[] __initconst = {
 #define imx35_flexcan_data_entry(_id, _hwid)				\
diff --git a/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c b/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c
index 3d039ef021e0..466c9ccc6675 100644
--- a/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c
+++ b/arch/arm/mach-imx/devices/platform-sdhci-esdhc-imx.c
@@ -22,16 +22,6 @@
 #define imx_sdhci_esdhc_imx_data_entry(soc, devid, id, hwid)	\
 	[id] = imx_sdhci_esdhc_imx_data_entry_single(soc, devid, id, hwid)
 
-#ifdef CONFIG_SOC_IMX25
-const struct imx_sdhci_esdhc_imx_data
-imx25_sdhci_esdhc_imx_data[] __initconst = {
-#define imx25_sdhci_esdhc_imx_data_entry(_id, _hwid)			\
-	imx_sdhci_esdhc_imx_data_entry(MX25, "sdhci-esdhc-imx25", _id, _hwid)
-	imx25_sdhci_esdhc_imx_data_entry(0, 1),
-	imx25_sdhci_esdhc_imx_data_entry(1, 2),
-};
-#endif /* ifdef CONFIG_SOC_IMX25 */
-
 #ifdef CONFIG_SOC_IMX35
 const struct imx_sdhci_esdhc_imx_data
 imx35_sdhci_esdhc_imx_data[] __initconst = {
-- 
2.9.0

^ permalink raw reply related

* [PATCHv2 8/8] ARM: configs: stm32: Add RTC support in STM32 defconfig
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch adds STM32 RTC support in stm32_defconfig file.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/configs/stm32_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index be19e09..0acff9e 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -57,6 +57,8 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_STM32=y
 CONFIG_DMADEVICES=y
 CONFIG_STM32_DMA=y
 # CONFIG_FILE_LOCKING is not set
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 7/8] ARM: dts: stm32: enable RTC on stm32429i-eval
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32429i-eval with default LSE clock source.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32429i-eval.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
index 8b158f9..5007da9 100644
--- a/arch/arm/boot/dts/stm32429i-eval.dts
+++ b/arch/arm/boot/dts/stm32429i-eval.dts
@@ -134,6 +134,10 @@
 	};
 };
 
+&rtc {
+	status = "okay";
+};
+
 &usart1 {
 	pinctrl-0 = <&usart1_pins_a>;
 	pinctrl-names = "default";
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 6/8] ARM: dts: stm32: enable RTC on stm32f469-disco
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32f469-disco with default LSE clock source.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f469-disco.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
index 8a163d7..af57dd5 100644
--- a/arch/arm/boot/dts/stm32f469-disco.dts
+++ b/arch/arm/boot/dts/stm32f469-disco.dts
@@ -78,6 +78,10 @@
 	clock-frequency = <8000000>;
 };
 
+&rtc {
+	status = "okay";
+};
+
 &usart3 {
 	status = "okay";
 };
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 5/8] ARM: dts: stm32: enable RTC on stm32f429-disco
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch enables RTC on stm32f429-disco with LSI as clock source because
X2 crystal for LSE is not fitted by default.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429-disco.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
index b6e63d8..49eddf6 100644
--- a/arch/arm/boot/dts/stm32f429-disco.dts
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -94,6 +94,12 @@
 	clock-frequency = <8000000>;
 };
 
+&rtc {
+	assigned-clocks = <&rcc 1 CLK_RTC>;
+	assigned-clock-parents = <&rcc 1 CLK_LSI>;
+	status = "okay";
+};
+
 &usart1 {
 	pinctrl-0 = <&usart1_pins_a>;
 	pinctrl-names = "default";
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 4/8] ARM: dts: stm32: Add RTC support for STM32F429 MCU
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch adds STM32 RTC bindings for STM32F429.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index d195ccf..d181025 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -125,6 +125,20 @@
 			status = "disabled";
 		};
 
+		rtc: rtc at 40002800 {
+			compatible = "st,stm32-rtc";
+			reg = <0x40002800 0x400>;
+			clocks = <&rcc 1 CLK_RTC>;
+			clock-names = "ck_rtc";
+			assigned-clocks = <&rcc 1 CLK_RTC>;
+			assigned-clock-parents = <&rcc 1 CLK_LSE>;
+			interrupt-parent = <&exti>;
+			interrupts = <17 1>;
+			interrupt-names = "alarm";
+			st,syscfg = <&pwrcfg>;
+			status = "disabled";
+		};
+
 		usart2: serial at 40004400 {
 			compatible = "st,stm32-usart", "st,stm32-uart";
 			reg = <0x40004400 0x400>;
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 3/8] rtc: add STM32 RTC driver
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch adds support for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 drivers/rtc/Kconfig     |  11 +
 drivers/rtc/Makefile    |   1 +
 drivers/rtc/rtc-stm32.c | 776 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 788 insertions(+)
 create mode 100644 drivers/rtc/rtc-stm32.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d14..11eb28a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1706,6 +1706,17 @@ config RTC_DRV_PIC32
 	   This driver can also be built as a module. If so, the module
 	   will be called rtc-pic32
 
+config RTC_DRV_STM32
+	tristate "STM32 RTC"
+	select REGMAP_MMIO
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	   If you say yes here you get support for the STM32 On-Chip
+	   Real Time Clock.
+
+	   This driver can also be built as a module, if so, the module
+	   will be called "rtc-stm32".
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a..87bd9cc 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS)	+= rtc-snvs.o
 obj-$(CONFIG_RTC_DRV_SPEAR)	+= rtc-spear.o
 obj-$(CONFIG_RTC_DRV_STARFIRE)	+= rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_STM32) 	+= rtc-stm32.o
 obj-$(CONFIG_RTC_DRV_STMP)	+= rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_ST_LPC)	+= rtc-st-lpc.o
 obj-$(CONFIG_RTC_DRV_SUN4V)	+= rtc-sun4v.o
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
new file mode 100644
index 0000000..6ce0f5a
--- /dev/null
+++ b/drivers/rtc/rtc-stm32.c
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) Amelie Delaunay 2016
+ * Author:  Amelie Delaunay <amelie.delaunay@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "stm32_rtc"
+
+/* STM32 RTC registers */
+#define STM32_RTC_TR		0x00
+#define STM32_RTC_DR		0x04
+#define STM32_RTC_CR		0x08
+#define STM32_RTC_ISR		0x0C
+#define STM32_RTC_PRER		0x10
+#define STM32_RTC_ALRMAR	0x1C
+#define STM32_RTC_WPR		0x24
+
+/* STM32_RTC_TR bit fields  */
+#define STM32_RTC_TR_SEC_SHIFT		0
+#define STM32_RTC_TR_SEC		GENMASK(6, 0)
+#define STM32_RTC_TR_MIN_SHIFT		8
+#define STM32_RTC_TR_MIN		GENMASK(14, 8)
+#define STM32_RTC_TR_HOUR_SHIFT		16
+#define STM32_RTC_TR_HOUR		GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DR_DATE_SHIFT		0
+#define STM32_RTC_DR_DATE		GENMASK(5, 0)
+#define STM32_RTC_DR_MONTH_SHIFT	8
+#define STM32_RTC_DR_MONTH		GENMASK(12, 8)
+#define STM32_RTC_DR_WDAY_SHIFT		13
+#define STM32_RTC_DR_WDAY		GENMASK(15, 13)
+#define STM32_RTC_DR_YEAR_SHIFT		16
+#define STM32_RTC_DR_YEAR		GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT		BIT(6)
+#define STM32_RTC_CR_ALRAE		BIT(8)
+#define STM32_RTC_CR_ALRAIE		BIT(12)
+
+/* STM32_RTC_ISR bit fields */
+#define STM32_RTC_ISR_ALRAWF		BIT(0)
+#define STM32_RTC_ISR_INITS		BIT(4)
+#define STM32_RTC_ISR_RSF		BIT(5)
+#define STM32_RTC_ISR_INITF		BIT(6)
+#define STM32_RTC_ISR_INIT		BIT(7)
+#define STM32_RTC_ISR_ALRAF		BIT(8)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT	0
+#define STM32_RTC_PRER_PRED_S		GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT	16
+#define STM32_RTC_PRER_PRED_A		GENMASK(22, 16)
+
+/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
+#define STM32_RTC_ALRMXR_SEC_SHIFT	0
+#define STM32_RTC_ALRMXR_SEC		GENMASK(6, 0)
+#define STM32_RTC_ALRMXR_SEC_MASK	BIT(7)
+#define STM32_RTC_ALRMXR_MIN_SHIFT	8
+#define STM32_RTC_ALRMXR_MIN		GENMASK(14, 8)
+#define STM32_RTC_ALRMXR_MIN_MASK	BIT(15)
+#define STM32_RTC_ALRMXR_HOUR_SHIFT	16
+#define STM32_RTC_ALRMXR_HOUR		GENMASK(21, 16)
+#define STM32_RTC_ALRMXR_PM		BIT(22)
+#define STM32_RTC_ALRMXR_HOUR_MASK	BIT(23)
+#define STM32_RTC_ALRMXR_DATE_SHIFT	24
+#define STM32_RTC_ALRMXR_DATE		GENMASK(29, 24)
+#define STM32_RTC_ALRMXR_WDSEL		BIT(30)
+#define STM32_RTC_ALRMXR_WDAY_SHIFT	24
+#define STM32_RTC_ALRMXR_WDAY		GENMASK(27, 24)
+#define STM32_RTC_ALRMXR_DATE_MASK	BIT(31)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY			0xCA
+#define RTC_WPR_2ND_KEY			0x53
+#define RTC_WPR_WRONG_KEY		0xFF
+
+/*
+ * RTC registers are protected agains parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR				0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP			BIT(8)
+
+static struct regmap *dbp;
+
+struct stm32_rtc {
+	struct rtc_device *rtc_dev;
+	void __iomem *base;
+	struct clk *ck_rtc;
+	spinlock_t lock; /* Protects registers accesses */
+	int irq_alarm;
+};
+
+static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
+	writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
+{
+	writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	if (!(isr & STM32_RTC_ISR_INITF)) {
+		isr |= STM32_RTC_ISR_INIT;
+		writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+		/*
+		 * It takes around 2 ck_rtc clock cycles to enter in
+		 * initialization phase mode (and have INITF flag set). As
+		 * slowest ck_rtc frequency may be 32kHz and highest should be
+		 * 1MHz, we poll every 10 us with a timeout of 100ms.
+		 */
+		return readl_relaxed_poll_timeout_atomic(
+					rtc->base + STM32_RTC_ISR,
+					isr, (isr & STM32_RTC_ISR_INITF),
+					10, 100000);
+	}
+
+	return 0;
+}
+
+static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_INIT;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
+{
+	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	isr &= ~STM32_RTC_ISR_RSF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	/*
+	 * Wait for RSF to be set to ensure the calendar registers are
+	 * synchronised, it takes around 2 ck_rtc clock cycles
+	 */
+	return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+						 isr,
+						 (isr & STM32_RTC_ISR_RSF),
+						 10, 100000);
+}
+
+static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
+{
+	struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
+	unsigned int isr, cr;
+
+	mutex_lock(&rtc->rtc_dev->ops_lock);
+
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	if ((isr & STM32_RTC_ISR_ALRAF) &&
+	    (cr & STM32_RTC_CR_ALRAIE)) {
+		/* Alarm A flag - Alarm interrupt */
+		dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
+
+		/* Pass event to the kernel */
+		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+		/* Clear event flag, otherwise new events won't be received */
+		writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
+			       rtc->base + STM32_RTC_ISR);
+	}
+
+	mutex_unlock(&rtc->rtc_dev->ops_lock);
+
+	return IRQ_HANDLED;
+}
+
+/* Convert rtc_time structure from bin to bcd format */
+static void tm2bcd(struct rtc_time *tm)
+{
+	tm->tm_sec = bin2bcd(tm->tm_sec);
+	tm->tm_min = bin2bcd(tm->tm_min);
+	tm->tm_hour = bin2bcd(tm->tm_hour);
+
+	tm->tm_mday = bin2bcd(tm->tm_mday);
+	tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+	tm->tm_year = bin2bcd(tm->tm_year - 100);
+	/*
+	 * Number of days since Sunday
+	 * - on kernel side, 0=Sunday...6=Saturday
+	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
+	 */
+	tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
+}
+
+/* Convert rtc_time structure from bcd to bin format */
+static void bcd2tm(struct rtc_time *tm)
+{
+	tm->tm_sec = bcd2bin(tm->tm_sec);
+	tm->tm_min = bcd2bin(tm->tm_min);
+	tm->tm_hour = bcd2bin(tm->tm_hour);
+
+	tm->tm_mday = bcd2bin(tm->tm_mday);
+	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+	tm->tm_year = bcd2bin(tm->tm_year) + 100;
+	/*
+	 * Number of days since Sunday
+	 * - on kernel side, 0=Sunday...6=Saturday
+	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
+	 */
+	tm->tm_wday %= 7;
+}
+
+static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int tr, dr;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	/* Time and Date in BCD format */
+	tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+	dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+	tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+	tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+	tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+	tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+	tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+	tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
+
+	/* We don't report tm_yday and tm_isdst */
+
+	bcd2tm(tm);
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned int tr, dr;
+	unsigned long irqflags;
+	int ret = 0;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+		return -EINVAL;
+	}
+
+	tm2bcd(tm);
+
+	/* Time in BCD format */
+	tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
+	     ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
+	     ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
+
+	/* Date in BCD format */
+	dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
+	     ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
+	     ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
+	     ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	ret = stm32_rtc_enter_init_mode(rtc);
+	if (ret) {
+		dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
+		goto end;
+	}
+
+	writel_relaxed(tr, rtc->base + STM32_RTC_TR);
+	writel_relaxed(dr, rtc->base + STM32_RTC_DR);
+
+	stm32_rtc_exit_init_mode(rtc);
+
+	ret = stm32_rtc_wait_sync(rtc);
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time;
+	unsigned int alrmar, cr, isr;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
+		/*
+		 * Date/day doesn't matter in Alarm comparison so alarm
+		 * triggers every day
+		 */
+		tm->tm_mday = -1;
+		tm->tm_wday = -1;
+	} else {
+		if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
+			/* Alarm is set to a day of week */
+			tm->tm_mday = -1;
+			tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
+				      STM32_RTC_ALRMXR_WDAY_SHIFT;
+			tm->tm_wday %= 7;
+		} else {
+			/* Alarm is set to a day of month */
+			tm->tm_wday = -1;
+			tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
+				       STM32_RTC_ALRMXR_DATE_SHIFT;
+		}
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
+		/* Hours don't matter in Alarm comparison */
+		tm->tm_hour = -1;
+	} else {
+		tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
+			       STM32_RTC_ALRMXR_HOUR_SHIFT;
+		if (alrmar & STM32_RTC_ALRMXR_PM)
+			tm->tm_hour += 12;
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
+		/* Minutes don't matter in Alarm comparison */
+		tm->tm_min = -1;
+	} else {
+		tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
+			      STM32_RTC_ALRMXR_MIN_SHIFT;
+	}
+
+	if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
+		/* Seconds don't matter in Alarm comparison */
+		tm->tm_sec = -1;
+	} else {
+		tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
+			      STM32_RTC_ALRMXR_SEC_SHIFT;
+	}
+
+	bcd2tm(tm);
+
+	alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
+	alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
+
+	return 0;
+}
+
+static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long irqflags;
+	unsigned int isr, cr;
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	/* We expose Alarm A to the kernel */
+	if (enabled)
+		cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+	else
+		cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/* Clear event irqflags, otherwise new events won't be received */
+	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+	isr &= ~STM32_RTC_ISR_ALRAF;
+	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return 0;
+}
+
+static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
+{
+	unsigned int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
+	unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+	unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+
+	cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+	cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+	cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+	cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+	cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+	cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+	/*
+	 * Assuming current date is M-D-Y H:M:S.
+	 * RTC alarm can't be set on a specific month and year.
+	 * So the valid alarm range is:
+	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
+	 * with a specific case for December...
+	 */
+	if ((((tm->tm_year > cur_year) &&
+	      (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
+	     ((tm->tm_year == cur_year) &&
+	      (tm->tm_mon <= cur_mon + 1))) &&
+	    ((tm->tm_mday < cur_day) ||
+	     ((tm->tm_mday == cur_day) &&
+	     ((tm->tm_hour < cur_hour) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min < cur_min)) ||
+	      ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
+	       (tm->tm_sec <= cur_sec))))))
+		return 0;
+
+	return -EINVAL;
+}
+
+static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	struct rtc_time *tm = &alrm->time;
+	unsigned long irqflags;
+	unsigned int cr, isr, alrmar;
+	int ret = 0;
+
+	if (rtc_valid_tm(tm)) {
+		dev_err(dev, "Alarm time not valid.\n");
+		return -EINVAL;
+	}
+
+	tm2bcd(tm);
+
+	/*
+	 * RTC alarm can't be set on a specific date, unless this date is
+	 * up to the same day of month next month.
+	 */
+	if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
+		dev_err(dev, "Alarm can be set only on upcoming month.\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	/* Disable Alarm */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	/*
+	 * Poll Alarm write flag to be sure that Alarm update is allowed: it
+	 * takes around 2 ck_rtc clock cycles
+	 */
+	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+						isr,
+						(isr & STM32_RTC_ISR_ALRAWF),
+						10, 100000);
+
+	if (ret) {
+		dev_err(dev, "Alarm update not allowed\n");
+		goto end;
+	}
+
+	alrmar = 0;
+	/* tm_year and tm_mon are not used because not supported by RTC */
+	alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
+		  STM32_RTC_ALRMXR_DATE;
+	/* 24-hour format */
+	alrmar &= ~STM32_RTC_ALRMXR_PM;
+	alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
+		  STM32_RTC_ALRMXR_HOUR;
+	alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
+		  STM32_RTC_ALRMXR_MIN;
+	alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
+		  STM32_RTC_ALRMXR_SEC;
+
+	/* Write to Alarm register */
+	writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR);
+
+	if (alrm->enabled)
+		stm32_rtc_alarm_irq_enable(dev, 1);
+	else
+		stm32_rtc_alarm_irq_enable(dev, 0);
+
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static const struct rtc_class_ops stm32_rtc_ops = {
+	.read_time	= stm32_rtc_read_time,
+	.set_time	= stm32_rtc_set_time,
+	.read_alarm	= stm32_rtc_read_alarm,
+	.set_alarm	= stm32_rtc_set_alarm,
+	.alarm_irq_enable = stm32_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_rtc_of_match[] = {
+	{ .compatible = "st,stm32-rtc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
+#endif
+
+static int stm32_rtc_init(struct platform_device *pdev,
+			  struct stm32_rtc *rtc)
+{
+	unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+	unsigned int rate;
+	unsigned long irqflags;
+	int ret = 0;
+
+	rate = clk_get_rate(rtc->ck_rtc);
+
+	/* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+	pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+	pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+	for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
+		pred_s = (rate / (pred_a + 1)) - 1;
+
+		if (((pred_s + 1) * (pred_a + 1)) == rate)
+			break;
+	}
+
+	/*
+	 * Can't find a 1Hz, so give priority to RTC power consumption
+	 * by choosing the higher possible value for prediv_a
+	 */
+	if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
+		pred_a = pred_a_max;
+		pred_s = (rate / (pred_a + 1)) - 1;
+
+		dev_warn(&pdev->dev, "ck_rtc is %s\n",
+			 (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
+			 "fast" : "slow");
+	}
+
+	spin_lock_irqsave(&rtc->lock, irqflags);
+
+	stm32_rtc_wpr_unlock(rtc);
+
+	ret = stm32_rtc_enter_init_mode(rtc);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Can't enter in init mode. Prescaler config failed.\n");
+		goto end;
+	}
+
+	prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+
+	/* Force 24h time format */
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_FMT;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+	stm32_rtc_exit_init_mode(rtc);
+
+	ret = stm32_rtc_wait_sync(rtc);
+end:
+	stm32_rtc_wpr_lock(rtc);
+
+	spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+	return ret;
+}
+
+static int stm32_rtc_probe(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc;
+	struct resource *res;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	rtc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rtc->base))
+		return PTR_ERR(rtc->base);
+
+	dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
+	if (IS_ERR(dbp)) {
+		dev_err(&pdev->dev, "no st,syscfg\n");
+		return PTR_ERR(dbp);
+	}
+
+	spin_lock_init(&rtc->lock);
+
+	rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(rtc->ck_rtc)) {
+		dev_err(&pdev->dev, "no ck_rtc clock");
+		return PTR_ERR(rtc->ck_rtc);
+	}
+
+	ret = clk_prepare_enable(rtc->ck_rtc);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+	/*
+	 * After a system reset, RTC_ISR.INITS flag can be read to check if
+	 * the calendar has been initalized or not. INITS flag is reset by a
+	 * power-on reset (no vbat, no power-supply). It is not reset if
+	 * ck_rtc parent clock has changed (so RTC prescalers need to be
+	 * changed). That's why we cannot rely on this flag to know if RTC
+	 * init has to be done.
+	 */
+	ret = stm32_rtc_init(pdev, rtc);
+	if (ret)
+		goto err;
+
+	rtc->irq_alarm = platform_get_irq(pdev, 0);
+	if (rtc->irq_alarm <= 0) {
+		dev_err(&pdev->dev, "no alarm irq\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	ret = device_init_wakeup(&pdev->dev, true);
+	if (ret)
+		dev_warn(&pdev->dev,
+			 "alarm won't be able to wake up the system");
+
+	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+			&stm32_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc_dev)) {
+		ret = PTR_ERR(rtc->rtc_dev);
+		dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
+			ret);
+		goto err;
+	}
+
+	/* Handle RTC alarm interrupts */
+	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
+					stm32_rtc_alarm_irq,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					pdev->name, rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
+			rtc->irq_alarm);
+		goto err;
+	}
+
+	/*
+	 * If INITS flag is reset (calendar year field set to 0x00), calendar
+	 * must be initialized
+	 */
+	if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
+		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
+
+	return 0;
+err:
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+	device_init_wakeup(&pdev->dev, false);
+
+	return ret;
+}
+
+static int __exit stm32_rtc_remove(struct platform_device *pdev)
+{
+	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+	unsigned int cr;
+
+	/* Disable interrupts */
+	stm32_rtc_wpr_unlock(rtc);
+	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+	cr &= ~STM32_RTC_CR_ALRAIE;
+	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+	stm32_rtc_wpr_lock(rtc);
+
+	clk_disable_unprepare(rtc->ck_rtc);
+
+	/* Enable backup domain write protection */
+	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_rtc_suspend(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(rtc->irq_alarm);
+
+	return 0;
+}
+
+static int stm32_rtc_resume(struct device *dev)
+{
+	struct stm32_rtc *rtc = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = stm32_rtc_wait_sync(rtc);
+	if (ret < 0)
+		return ret;
+
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(rtc->irq_alarm);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
+			 stm32_rtc_suspend, stm32_rtc_resume);
+
+static struct platform_driver stm32_rtc_driver = {
+	.probe		= stm32_rtc_probe,
+	.remove		= stm32_rtc_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.pm	= &stm32_rtc_pm_ops,
+		.of_match_table = stm32_rtc_of_match,
+	},
+};
+
+module_platform_driver(stm32_rtc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 2/8] dt-bindings: document the STM32 RTC bindings
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch adds documentation of device tree bindings for the STM32 RTC.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 .../devicetree/bindings/rtc/st,stm32-rtc.txt       | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt

diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
new file mode 100644
index 0000000..e2837b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
@@ -0,0 +1,27 @@
+STM32 Real Time Clock
+
+Required properties:
+- compatible: "st,stm32-rtc".
+- reg: address range of rtc register set.
+- clocks: reference to the clock entry ck_rtc.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  (RTC registers) write protection.
+
+Optional properties (to override default ck_rtc parent clock):
+- assigned-clocks: reference to the ck_rtc clock entry.
+- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+
+Example:
+
+	rtc: rtc at 40002800 {
+		compatible = "st,stm32-rtc";
+		reg = <0x40002800 0x400>;
+		clocks = <&rcc 1 CLK_RTC>;
+		assigned-clocks = <&rcc 1 CLK_RTC>;
+		assigned-clock-parents = <&rcc 1 CLK_LSE>;
+		interrupt-parent = <&exti>;
+		interrupts = <17 1>;
+		st,syscfg = <&pwrcfg>;
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 1/8] ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481878257-29163-1-git-send-email-amelie.delaunay@st.com>

This patch set HSE_RTC clock frequency to 1 MHz, as the clock supplied to
the RTC must be 1 MHz.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index b077f99..d195ccf 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -371,6 +371,8 @@
 			reg = <0x40023800 0x400>;
 			clocks = <&clk_hse>, <&clk_i2s_ckin>;
 			st,syscfg = <&pwrcfg>;
+			assigned-clocks = <&rcc 1 CLK_HSE_RTC>;
+			assigned-clock-rates = <1000000>;
 		};
 
 		dma1: dma-controller at 40026000 {
-- 
1.9.1

^ permalink raw reply related

* [PATCHv2 0/8] Add support for STM32 RTC
From: Amelie Delaunay @ 2016-12-16  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

v2:
- remove clock-names and interrupt-names from bindings
- remove unuseful headers
- clean stm32_rtc structure
- replace stm32_rtc_readl/_writel by readl/writel_relaxed
- use threaded IRQ
- rework set_alarm
- add various comments
- select COMPILE_TEST and REGMAP_MMIO

This patchset adds support for the STM32 Real-Time Clock.
This RTC is an independent BCD timer/counter and provides a time-of-day
clock/calendar with programmable alarm interrupt.
RTC calendar can be driven by three clock sources LSE, LSI or HSE.

Amelie Delaunay (8):
  ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
  dt-bindings: document the STM32 RTC bindings
  rtc: add STM32 RTC driver
  ARM: dts: stm32: Add RTC support for STM32F429 MCU
  ARM: dts: stm32: enable RTC on stm32f429-disco
  ARM: dts: stm32: enable RTC on stm32f469-disco
  ARM: dts: stm32: enable RTC on stm32429i-eval
  ARM: configs: stm32: Add RTC support in STM32 defconfig

 .../devicetree/bindings/rtc/st,stm32-rtc.txt       |  27 +
 arch/arm/boot/dts/stm32429i-eval.dts               |   4 +
 arch/arm/boot/dts/stm32f429-disco.dts              |   6 +
 arch/arm/boot/dts/stm32f429.dtsi                   |  16 +
 arch/arm/boot/dts/stm32f469-disco.dts              |   4 +
 arch/arm/configs/stm32_defconfig                   |   2 +
 drivers/rtc/Kconfig                                |  11 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-stm32.c                            | 776 +++++++++++++++++++++
 9 files changed, 847 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
 create mode 100644 drivers/rtc/rtc-stm32.c

-- 
1.9.1

^ permalink raw reply

* [PATCH 2/2] remoteproc: Remove firmware_loading_complete
From: loic pallardy @ 2016-12-16  8:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481846632-4778-2-git-send-email-spjoshi@codeaurora.org>



On 12/16/2016 01:03 AM, Sarangdhar Joshi wrote:
> rproc_del() waits on firmware_loading_complete in order to
> make sure rproc_add() completed successfully before calling
> rproc_shutdown().  However since rproc_add() will always be
> called before rproc_del(), we do not need to wait on
> firmware_loading_complete. Drop this completion variable
> altogether.
>
Hi,

firmware_loading_complete is used to synchronize all operations on rproc 
with parallel work launched by request_firmware_nowait.
rproc_add could be done and firmware loading still pending. In that case 
rproc_del mustn't be called before end of the procedure.

If you decide to remove this synchronization you need either to modify 
rproc boot sequence or to replace it by something else.

Regards,
Loic

> Signed-off-by: Sarangdhar Joshi <spjoshi@codeaurora.org>
> ---
>
> Sending this patch again since I had missed usage of
> firmware_loading_complete in drivers/soc/ti/wkup_m3_ipc.c
>
>  drivers/remoteproc/remoteproc_core.c | 12 +-----------
>  include/linux/remoteproc.h           |  2 --
>  2 files changed, 1 insertion(+), 13 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 953ee29..862fa4e 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -975,17 +975,12 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
>  		rproc_boot(rproc);
>
>  	release_firmware(fw);
> -	/* allow rproc_del() contexts, if any, to proceed */
> -	complete_all(&rproc->firmware_loading_complete);
>  }
>
>  static int rproc_add_virtio_devices(struct rproc *rproc)
>  {
>  	int ret;
>
> -	/* rproc_del() calls must wait until async loader completes */
> -	init_completion(&rproc->firmware_loading_complete);
> -
>  	/*
>  	 * We must retrieve early virtio configuration info from
>  	 * the firmware (e.g. whether to register a virtio device,
> @@ -997,10 +992,8 @@ static int rproc_add_virtio_devices(struct rproc *rproc)
>  	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
>  				      rproc->firmware, &rproc->dev, GFP_KERNEL,
>  				      rproc, rproc_fw_config_virtio);
> -	if (ret < 0) {
> +	if (ret < 0)
>  		dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret);
> -		complete_all(&rproc->firmware_loading_complete);
> -	}
>
>  	return ret;
>  }
> @@ -1483,9 +1476,6 @@ int rproc_del(struct rproc *rproc)
>  	if (!rproc)
>  		return -EINVAL;
>
> -	/* if rproc is just being registered, wait */
> -	wait_for_completion(&rproc->firmware_loading_complete);
> -
>  	/* if rproc is marked always-on, rproc_add() booted it */
>  	/* TODO: make sure this works with rproc->power > 1 */
>  	if (rproc->auto_boot)
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index e2f3a32..19d84a0 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -397,7 +397,6 @@ enum rproc_crash_type {
>   * @num_traces: number of trace buffers
>   * @carveouts: list of physically contiguous memory allocations
>   * @mappings: list of iommu mappings we initiated, needed on shutdown
> - * @firmware_loading_complete: marks e/o asynchronous firmware loading
>   * @bootaddr: address of first instruction to boot rproc with (optional)
>   * @rvdevs: list of remote virtio devices
>   * @subdevs: list of subdevices, to following the running state
> @@ -428,7 +427,6 @@ struct rproc {
>  	int num_traces;
>  	struct list_head carveouts;
>  	struct list_head mappings;
> -	struct completion firmware_loading_complete;
>  	u32 bootaddr;
>  	struct list_head rvdevs;
>  	struct list_head subdevs;
>

^ permalink raw reply

* [PATCH] ARM: dts: Add missing CPU frequencies for Exynos5422/5800
From: Krzysztof Kozlowski @ 2016-12-16  7:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD=FV=W6R8cNuR+gTnNRF6d-TNgzUeYTwuCp27efoMsd0YOH3g@mail.gmail.com>

On Thu, Dec 15, 2016 at 04:52:58PM -0800, Doug Anderson wrote:
> > [ I added Arjun to Cc:, maybe he can help in explaining this issue
> >   (unfortunately Inderpal's email is no longer working). ]
> >
> > Please also note that on Exynos5422/5800 SoCs the same ARM rail
> > voltage is used for 1.9 GHz & 2.0 GHz OPPs as for the 1.8 GHz one.
> > IOW if the problem exists it is already present in the mainline
> > kernel.
> 
> Interesting.  In the ChromeOS tree I see significantly higher voltages
> needed...  Note that one might naively look at
> <https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-3.8/drivers/cpufreq/exynos5420-cpufreq.c#178>.
> 
> 1362500, /* L0  2100 */
> 1312500, /* L1  2000 */
> 
> ..but, amazingly enough those voltages aren't used at all.  Surprise!
> 
> I believe that the above numbers are actually not used and the ASV
> numbers are used instead.  See
> <https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-3.8/arch/arm/mach-exynos/include/mach/asv-exynos542x.h#452>
> 
> { 2100000,
> 1350000, 1350000, 1350000, 1350000, 1350000,
> 1337500, 1325000, 1312500, 1300000, 1287500,
> 1275000, 1262500, 1250000, 1237500 },
> 
> I believe that interpretation there is: some bins of the CPU can run
> at 2.1 GHz just fine at 1.25 V but others need up to 1.35V.

That is definitely the case. One could just look at vendors ASV table
(for 1.9 GHz):
{ 1900000, 1300000, 1287500, 1262500, 1237500, 1225000, 1212500,
                    1200000, 1187500, 1175000, 1162500, 1150000,
		             1137500, 1125000, 1112500, 1112500},

The theoretical difference is up to 1.875V! From my experiments I saw
BIN1 chips which should be the same... but some working on 1.2V, some on
1.225V (@1.9 GHz). I didn't see any requiring higher voltages but that
does not mean that there aren't such...

> ...so if you're running at 2.1 GHz at 1.25V then perhaps you're just
> running on a CPU from a nice bin?

Would be nice to see a dump of PKG_ID and AUX_INFO chipid registers
along with name of tested board. Because the "Tested on XU3" is not
sufficient.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH v2 3/3] clk: zte: add audio clocks for zx296718
From: Shawn Guo @ 2016-12-16  7:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481873207-22929-1-git-send-email-shawnguo@kernel.org>

From: Jun Nie <jun.nie@linaro.org>

The audio related clock support is missing from the existing zx296718
clock driver.  Let's add it, so that the upstream ZX SPDIF driver can
work for HDMI audio support.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/clk/zte/clk-zx296718.c | 127 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/zte/clk.c          | 127 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/zte/clk.h          |  21 +++++++
 3 files changed, 275 insertions(+)

diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
index 026310708aea..c7db7418367c 100644
--- a/drivers/clk/zte/clk-zx296718.c
+++ b/drivers/clk/zte/clk-zx296718.c
@@ -897,10 +897,137 @@ static int __init lsp1_clocks_init(struct device_node *np)
 	return 0;
 }
 
+PNAME(audio_wclk_common_p) = {
+	"audio_99m",
+	"audio_24m",
+};
+
+PNAME(audio_timer_p) = {
+	"audio_24m",
+	"audio_32k",
+};
+
+static struct zx_clk_mux audio_mux_clk[] = {
+	MUX(0, "i2s0_wclk_mux", audio_wclk_common_p, AUDIO_I2S0_CLK, 0, 1),
+	MUX(0, "i2s1_wclk_mux", audio_wclk_common_p, AUDIO_I2S1_CLK, 0, 1),
+	MUX(0, "i2s2_wclk_mux", audio_wclk_common_p, AUDIO_I2S2_CLK, 0, 1),
+	MUX(0, "i2s3_wclk_mux", audio_wclk_common_p, AUDIO_I2S3_CLK, 0, 1),
+	MUX(0, "i2c0_wclk_mux", audio_wclk_common_p, AUDIO_I2C0_CLK, 0, 1),
+	MUX(0, "spdif0_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF0_CLK, 0, 1),
+	MUX(0, "spdif1_wclk_mux", audio_wclk_common_p, AUDIO_SPDIF1_CLK, 0, 1),
+	MUX(0, "timer_wclk_mux", audio_timer_p, AUDIO_TIMER_CLK, 0, 1),
+};
+
+struct clk_zx_audio_divider audio_adiv_clk[] = {
+	AUDIO_DIV(0, "i2s0_wclk_div", "i2s0_wclk_mux", AUDIO_I2S0_DIV_CFG1),
+	AUDIO_DIV(0, "i2s1_wclk_div", "i2s1_wclk_mux", AUDIO_I2S1_DIV_CFG1),
+	AUDIO_DIV(0, "i2s2_wclk_div", "i2s2_wclk_mux", AUDIO_I2S2_DIV_CFG1),
+	AUDIO_DIV(0, "i2s3_wclk_div", "i2s3_wclk_mux", AUDIO_I2S3_DIV_CFG1),
+	AUDIO_DIV(0, "spdif0_wclk_div", "spdif0_wclk_mux", AUDIO_SPDIF0_DIV_CFG1),
+	AUDIO_DIV(0, "spdif1_wclk_div", "spdif1_wclk_mux", AUDIO_SPDIF1_DIV_CFG1),
+};
+
+struct zx_clk_div audio_div_clk[] = {
+	DIV_T(0, "tdm_wclk_div", "audio_16m384", AUDIO_TDM_CLK, 8, 4, 0, common_div_table),
+};
+
+struct zx_clk_gate audio_gate_clk[] = {
+	GATE(AUDIO_I2S0_WCLK, "i2s0_wclk", "i2s0_wclk_div", AUDIO_I2S0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S1_WCLK, "i2s1_wclk", "i2s1_wclk_div", AUDIO_I2S1_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S2_WCLK, "i2s2_wclk", "i2s2_wclk_div", AUDIO_I2S2_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2S3_WCLK, "i2s3_wclk", "i2s3_wclk_div", AUDIO_I2S3_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_I2C0_WCLK, "i2c0_wclk", "i2c0_wclk_mux", AUDIO_I2C0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_SPDIF0_WCLK, "spdif0_wclk", "spdif0_wclk_div", AUDIO_SPDIF0_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_SPDIF1_WCLK, "spdif1_wclk", "spdif1_wclk_div", AUDIO_SPDIF1_CLK, 9, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_TDM_WCLK, "tdm_wclk", "tdm_wclk_div", AUDIO_TDM_CLK, 17, CLK_SET_RATE_PARENT, 0),
+	GATE(AUDIO_TS_PCLK, "tempsensor_pclk", "clk49m5", AUDIO_TS_CLK, 1, 0, 0),
+};
+
+static struct clk_hw_onecell_data audio_hw_onecell_data = {
+	.num = AUDIO_NR_CLKS,
+	.hws = {
+		[AUDIO_NR_CLKS - 1] = NULL,
+	},
+};
+
+static int __init audio_clocks_init(struct device_node *np)
+{
+	void __iomem *reg_base;
+	int i, ret;
+
+	reg_base = of_iomap(np, 0);
+	if (!reg_base) {
+		pr_err("%s: Unable to map audio clk base\n", __func__);
+		return -ENXIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(audio_mux_clk); i++) {
+		if (audio_mux_clk[i].id)
+			audio_hw_onecell_data.hws[audio_mux_clk[i].id] =
+					&audio_mux_clk[i].mux.hw;
+
+		audio_mux_clk[i].mux.reg += (uintptr_t)reg_base;
+		ret = clk_hw_register(NULL, &audio_mux_clk[i].mux.hw);
+		if (ret) {
+			pr_warn("audio clk %s init error!\n",
+				audio_mux_clk[i].mux.hw.init->name);
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(audio_adiv_clk); i++) {
+		if (audio_adiv_clk[i].id)
+			audio_hw_onecell_data.hws[audio_adiv_clk[i].id] =
+					&audio_adiv_clk[i].hw;
+
+		audio_adiv_clk[i].reg_base += (uintptr_t)reg_base;
+		ret = clk_hw_register(NULL, &audio_adiv_clk[i].hw);
+		if (ret) {
+			pr_warn("audio clk %s init error!\n",
+				audio_adiv_clk[i].hw.init->name);
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(audio_div_clk); i++) {
+		if (audio_div_clk[i].id)
+			audio_hw_onecell_data.hws[audio_div_clk[i].id] =
+					&audio_div_clk[i].div.hw;
+
+		audio_div_clk[i].div.reg += (uintptr_t)reg_base;
+		ret = clk_hw_register(NULL, &audio_div_clk[i].div.hw);
+		if (ret) {
+			pr_warn("audio clk %s init error!\n",
+				audio_div_clk[i].div.hw.init->name);
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(audio_gate_clk); i++) {
+		if (audio_gate_clk[i].id)
+			audio_hw_onecell_data.hws[audio_gate_clk[i].id] =
+					&audio_gate_clk[i].gate.hw;
+
+		audio_gate_clk[i].gate.reg += (uintptr_t)reg_base;
+		ret = clk_hw_register(NULL, &audio_gate_clk[i].gate.hw);
+		if (ret) {
+			pr_warn("audio clk %s init error!\n",
+				audio_gate_clk[i].gate.hw.init->name);
+		}
+	}
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				     &audio_hw_onecell_data);
+	if (ret) {
+		pr_err("failed to register audio clk provider: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static const struct of_device_id zx_clkc_match_table[] = {
 	{ .compatible = "zte,zx296718-topcrm", .data = &top_clocks_init },
 	{ .compatible = "zte,zx296718-lsp0crm", .data = &lsp0_clocks_init },
 	{ .compatible = "zte,zx296718-lsp1crm", .data = &lsp1_clocks_init },
+	{ .compatible = "zte,zx296718-audiocrm", .data = &audio_clocks_init },
 	{ }
 };
 
diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c
index c4c1251bc1e7..878d879b23ff 100644
--- a/drivers/clk/zte/clk.c
+++ b/drivers/clk/zte/clk.c
@@ -9,6 +9,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/err.h>
+#include <linux/gcd.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/slab.h>
@@ -310,3 +311,129 @@ struct clk *clk_register_zx_audio(const char *name,
 
 	return clk;
 }
+
+#define CLK_AUDIO_DIV_FRAC	BIT(0)
+#define CLK_AUDIO_DIV_INT	BIT(1)
+#define CLK_AUDIO_DIV_UNCOMMON	BIT(1)
+
+#define CLK_AUDIO_DIV_FRAC_NSHIFT	16
+#define CLK_AUDIO_DIV_INT_FRAC_RE	BIT(16)
+#define CLK_AUDIO_DIV_INT_FRAC_MAX	(0xffff)
+#define CLK_AUDIO_DIV_INT_FRAC_MIN	(0x2)
+#define CLK_AUDIO_DIV_INT_INT_SHIFT	24
+#define CLK_AUDIO_DIV_INT_INT_WIDTH	4
+
+struct zx_clk_audio_div_table {
+	unsigned long rate;
+	unsigned int int_reg;
+	unsigned int frac_reg;
+};
+
+#define to_clk_zx_audio_div(_hw) container_of(_hw, struct clk_zx_audio_divider, hw)
+
+static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
+				     u32 reg_frac, u32 reg_int,
+				     unsigned long parent_rate)
+{
+	unsigned long rate, m, n;
+
+	m = reg_frac & 0xffff;
+	n = (reg_frac >> 16) & 0xffff;
+
+	m = (reg_int & 0xffff) * n + m;
+	rate = (parent_rate * n) / m;
+
+	return rate;
+}
+
+static void audio_calc_reg(struct clk_zx_audio_divider *audio_div,
+			   struct zx_clk_audio_div_table *div_table,
+			   unsigned long rate, unsigned long parent_rate)
+{
+	unsigned int reg_int, reg_frac;
+	unsigned long m, n, div;
+
+	reg_int = parent_rate / rate;
+
+	if (reg_int > CLK_AUDIO_DIV_INT_FRAC_MAX)
+		reg_int = CLK_AUDIO_DIV_INT_FRAC_MAX;
+	else if (reg_int < CLK_AUDIO_DIV_INT_FRAC_MIN)
+		reg_int = 0;
+	m = parent_rate - rate * reg_int;
+	n = rate;
+
+	div = gcd(m, n);
+	m = m / div;
+	n = n / div;
+
+	if ((m >> 16) || (n >> 16)) {
+		if (m > n) {
+			n = n * 0xffff / m;
+			m = 0xffff;
+		} else {
+			m = m * 0xffff / n;
+			n = 0xffff;
+		}
+	}
+	reg_frac = m | (n << 16);
+
+	div_table->rate = parent_rate * n / (reg_int * n + m);
+	div_table->int_reg = reg_int;
+	div_table->frac_reg = reg_frac;
+}
+
+static unsigned long zx_audio_div_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+	u32 reg_frac, reg_int;
+
+	reg_frac = readl_relaxed(zx_audio_div->reg_base);
+	reg_int = readl_relaxed(zx_audio_div->reg_base + 0x4);
+
+	return audio_calc_rate(zx_audio_div, reg_frac, reg_int, parent_rate);
+}
+
+static long zx_audio_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+	struct zx_clk_audio_div_table divt;
+
+	audio_calc_reg(zx_audio_div, &divt, rate, *prate);
+
+	return audio_calc_rate(zx_audio_div, divt.frac_reg, divt.int_reg, *prate);
+}
+
+static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
+	struct zx_clk_audio_div_table divt;
+	unsigned int val;
+
+	audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
+	if (divt.rate != rate)
+		pr_debug("the real rate is:%ld", divt.rate);
+
+	writel_relaxed(divt.frac_reg, zx_audio_div->reg_base);
+
+	val = readl_relaxed(zx_audio_div->reg_base + 0x4);
+	val &= ~0xffff;
+	val |= divt.int_reg | CLK_AUDIO_DIV_INT_FRAC_RE;
+	writel_relaxed(val, zx_audio_div->reg_base + 0x4);
+
+	mdelay(1);
+
+	val = readl_relaxed(zx_audio_div->reg_base + 0x4);
+	val &= ~CLK_AUDIO_DIV_INT_FRAC_RE;
+	writel_relaxed(val, zx_audio_div->reg_base + 0x4);
+
+	return 0;
+}
+
+const struct clk_ops zx_audio_div_ops = {
+	.recalc_rate = zx_audio_div_recalc_rate,
+	.round_rate = zx_audio_div_round_rate,
+	.set_rate = zx_audio_div_set_rate,
+};
diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h
index 0df3474b2cf3..84a55a3e2bd4 100644
--- a/drivers/clk/zte/clk.h
+++ b/drivers/clk/zte/clk.h
@@ -153,6 +153,25 @@ struct zx_clk_div {
 	.id = _id,							\
 }
 
+struct clk_zx_audio_divider {
+	struct clk_hw				hw;
+	void __iomem				*reg_base;
+	unsigned int				rate_count;
+	spinlock_t				*lock;
+	u16					id;
+};
+
+#define AUDIO_DIV(_id, _name, _parent, _reg)				\
+{									\
+	.reg_base	= (void __iomem *) _reg,			\
+	.lock		= &clk_lock,					\
+	.hw.init	= CLK_HW_INIT(_name,				\
+				      _parent,				\
+				      &zx_audio_div_ops,		\
+				      0),				\
+	.id = _id,							\
+}
+
 struct clk *clk_register_zx_pll(const char *name, const char *parent_name,
 	unsigned long flags, void __iomem *reg_base,
 	const struct zx_pll_config *lookup_table, int count, spinlock_t *lock);
@@ -167,4 +186,6 @@ struct clk *clk_register_zx_audio(const char *name,
 				  unsigned long flags, void __iomem *reg_base);
 
 extern const struct clk_ops zx_pll_ops;
+extern const struct clk_ops zx_audio_div_ops;
+
 #endif
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 2/3] dt-bindings: zx296718-clk: add compatible for audio clock controller
From: Shawn Guo @ 2016-12-16  7:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481873207-22929-1-git-send-email-shawnguo@kernel.org>

From: Shawn Guo <shawn.guo@linaro.org>

It adds the compatible string for zx296718 audio clock controller.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/clock/zx296718-clk.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/zx296718-clk.txt b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
index 8c18b7b237bf..4ad703808407 100644
--- a/Documentation/devicetree/bindings/clock/zx296718-clk.txt
+++ b/Documentation/devicetree/bindings/clock/zx296718-clk.txt
@@ -13,6 +13,9 @@ Required properties:
 	"zte,zx296718-lsp1crm":
 		zx296718 device level clock selection and gating
 
+	"zte,zx296718-audiocrm":
+		zx296718 audio clock selection, divider and gating
+
 - reg: Address and length of the register set
 
 The clock consumer should specify the desired clock by having the clock
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 1/3] clk: zx296718: do not panic on failure
From: Shawn Guo @ 2016-12-16  7:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481873207-22929-1-git-send-email-shawnguo@kernel.org>

From: Shawn Guo <shawn.guo@linaro.org>

Instead of using panic, we should give an error message and return error
code when of_clk_add_hw_provider() call fails.

Since we have error prompt for failures, the "init over" pr_info output
isn't really necessary but becomes a debug noise.  So let's clean it up
along the way.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/clk/zte/clk-zx296718.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/zte/clk-zx296718.c b/drivers/clk/zte/clk-zx296718.c
index 707d62956e9b..026310708aea 100644
--- a/drivers/clk/zte/clk-zx296718.c
+++ b/drivers/clk/zte/clk-zx296718.c
@@ -610,9 +610,12 @@ static int __init top_clocks_init(struct device_node *np)
 		}
 	}
 
-	if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &top_hw_onecell_data))
-		panic("could not register clk provider\n");
-	pr_info("top clk init over, nr:%d\n", TOP_NR_CLKS);
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				     &top_hw_onecell_data);
+	if (ret) {
+		pr_err("failed to register top clk provider: %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
@@ -776,9 +779,12 @@ static int __init lsp0_clocks_init(struct device_node *np)
 		}
 	}
 
-	if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp0_hw_onecell_data))
-		panic("could not register clk provider\n");
-	pr_info("lsp0-clk init over:%d\n", LSP0_NR_CLKS);
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				     &lsp0_hw_onecell_data);
+	if (ret) {
+		pr_err("failed to register lsp0 clk provider: %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
@@ -881,9 +887,12 @@ static int __init lsp1_clocks_init(struct device_node *np)
 		}
 	}
 
-	if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &lsp1_hw_onecell_data))
-		panic("could not register clk provider\n");
-	pr_info("lsp1-clk init over, nr:%d\n", LSP1_NR_CLKS);
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				     &lsp1_hw_onecell_data);
+	if (ret) {
+		pr_err("failed to register lsp1 clk provider: %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 0/3] Add audio clocks support for ZTE ZX296718
From: Shawn Guo @ 2016-12-16  7:26 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shawn Guo <shawn.guo@linaro.org>

It adds missing audio related clocks for ZTE SoC ZX296718.  With these
clocks added, we can get HDMI audio work through SPDIF interface.

Changes for v2:
 - Add a patch to clean up existing driver code.
 - Clean up unused divider configuration lookup table.
 - Use uintptr_t instead of u64 to cast 'reg_base' for summation.
 - Instead of panic, give an error message and return error code when
   of_clk_add_hw_provider() call fails.
 - Drop unnecessary ulong type cast.
 - Use pr_debug instead of pr_info to avoid noisy messages

Jun Nie (1):
  clk: zte: add audio clocks for zx296718

Shawn Guo (2):
  clk: zx296718: do not panic on failure
  dt-bindings: zx296718-clk: add compatible for audio clock controller

 .../devicetree/bindings/clock/zx296718-clk.txt     |   3 +
 drivers/clk/zte/clk-zx296718.c                     | 154 +++++++++++++++++++--
 drivers/clk/zte/clk.c                              | 127 +++++++++++++++++
 drivers/clk/zte/clk.h                              |  21 +++
 4 files changed, 296 insertions(+), 9 deletions(-)

-- 
1.9.1

^ permalink raw reply

* Linux fails to start secondary cores when system resumes from Suspend-to-RAM
From: Mason @ 2016-12-16  7:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CADjb_WQ8ZTtcXYQ_3iobLCW7+rnG8FqyFQ1E47AZVGxP0JyB0w@mail.gmail.com>

On 16/12/2016 06:14, Yu Chen wrote:

> On Thu, Dec 15, 2016 at 11:18 PM, Mason wrote:
>
>> I'm playing with suspend-to-RAM on the tango platform:
>>
>>   http://lxr.free-electrons.com/source/arch/arm/mach-tango/platsmp.c
>>
>> When the system is suspended, the CPU is completely powered down
>> (receives no power whatsoever). When the system receives a wake-up
>> event, the CPU is powered up, and starts up exactly the same way
>> as for a cold boot (I think).
>>
>> However, while Linux successfully starts the secondary cores when
>> the system first boots, it fails when the system resumes from "S3".
>>
>> I added printascii() calls inside secondary_start_kernel() and I can
>> see that the following instruction are "properly" run:
>>
>>         cpu_switch_mm(mm->pgd, mm);
>>         local_flush_bp_all();
>>         enter_lazy_tlb(mm, current);
>>
>> but it seems local_flush_tlb_all(); never returns... :-(
>>
>>   http://lxr.free-electrons.com/source/arch/arm/include/asm/tlbflush.h#L332
>>
>>
>> Looking more closely at that function, it seems to be failing in:
>>
>>         tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
>>
>> (meaning: I get a log before, but not after)
>>
>> On my system, tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
>> resolves to:
>>
>> c010ce18:       e3170602        tst     r7, #2097152    ; 0x200000
>> c010ce1c:       1e086f17        mcrne   15, 0, r6, cr8, cr7, {0}
>>
>> What could be happening?
>> Can a core "hang" on this instruction?
>> Can a core "crash" on this instruction (meaning, an exception
>> is raised, and the core loops inside the exception code without
>> Linux noticing... that seems unlikely)
>>
>> I'm stumped. Could someone throw me a clue?
>
> try online/offline the nonboot CPUs via
> /sys/devices/system/cpu/cpuX/online

offline + online secondary core works.

Note: all cores are in the same power domain, so even if all
secondary cores are offline, the CPU block remains powered up
(secondary cores are just held in reset, or spinning in WFI,
depending on the firmware version).

When the system is suspended, the CPU block (as well as 99%
of the system) is powered down. Thus, upon resume, all cores
will run the boot sequence (again).

I'm guessing that something goes wrong during this second
boot sequence. Could there be a race condition between the
primary core and one of the secondary cores?

What is different in the Linux boot sequence between cold
boot and resume? I'm thinking that the state stored in RAM
is in fact incompatible with what Linux expects when it resumes...

Regards.

^ permalink raw reply

* [PATCH 2/2] clk: zte: add audio clocks for zx296718
From: Shawn Guo @ 2016-12-16  6:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161208210453.GH5423@codeaurora.org>

On Thu, Dec 08, 2016 at 01:04:53PM -0800, Stephen Boyd wrote:
> > +	if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &audio_hw_onecell_data))
> > +		panic("could not register clk provider\n");
> 
> Why don't we return error? We returned errors before if we
> couldn't map the ioregion.

Yes.  Rather than panic, we should check return and give an error
message in case of failure.

> 
> > +	pr_info("audio-clk init over, nr:%d\n", AUDIO_NR_CLKS);
> 
> debug noise?

Agreed.  I will just clean it up.

<snip>

> > +static unsigned long audio_calc_rate(struct clk_zx_audio_divider *audio_div,
> > +				     u32 reg_frac, u32 reg_int,
> > +				     unsigned long parent_rate)
> > +{
> > +	unsigned long rate, m, n;
> > +
> > +	if (audio_div->table) {
> > +		const struct zx_clk_audio_div_table *divt = audio_div->table;
> > +
> > +		for (; divt->rate; divt++) {
> > +			if ((divt->int_reg == reg_int) && (divt->frac_reg == reg_frac))
> 
> Please remove extra parenthesis here.

The whole hunk of the code will be dropped, since the divider lookup
table is not actually used.

> 
> > +				return divt->rate;
> > +		}
> > +	}
> > +	if (audio_div->table)
> > +		pr_warn("cannot found the config(int_reg:0x%x, frac_reg:0x%x) in table, we will caculate it\n",
> > +			reg_int, reg_frac);

<snip>

> > +	div_table->rate = (ulong)(parent_rate * n) / ((ulong)reg_int * n + m);
> 
> Please don't use ulong, use unsigned long. Also consider using
> local variables so the line isn't overly long.

It seems to me that none of the type casts is really necessary.  So I
will just drop them.

> 
> > +	div_table->int_reg = reg_int;
> > +	div_table->frac_reg = reg_frac;
> > +}
> [...]
> > +
> > +static int zx_audio_div_set_rate(struct clk_hw *hw, unsigned long rate,
> > +				    unsigned long parent_rate)
> > +{
> > +	struct clk_zx_audio_divider *zx_audio_div = to_clk_zx_audio_div(hw);
> > +	struct zx_clk_audio_div_table divt;
> > +	unsigned int val;
> > +
> > +	audio_calc_reg(zx_audio_div, &divt, rate, parent_rate);
> > +	if (divt.rate != rate)
> > +		pr_info("the real rate is:%ld", divt.rate);
> 
> Debug noise?

I will change it to pr_debug.

Shawn

^ permalink raw reply

* jemalloc testsuite stalls in memset
From: Minchan Kim @ 2016-12-16  6:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <mvm4m2535pc.fsf@hawking.suse.de>

Hello,

On Thu, Dec 15, 2016 at 10:24:47AM +0100, Andreas Schwab wrote:
> On Dez 15 2016, Minchan Kim <minchan@kernel.org> wrote:
> 
> > You mean program itself access the address(ie, 0xffffb7400000) is hang
> > while access the address from the debugger is OK?
> 
> Yes.
> 
> > Can you reproduce it easily?
> 
> 100%
> 
> > Did you test it in real machine or qemu on x86?
> 
> Both real and kvm.
> 
> > Could you show me how I can reproduce it?
> 
> Just run make check.
> 
> > I want to test it in x86 machine, first of all.
> > Unfortunately, I don't have any aarch64 platform now so maybe I have to
> > run it on qemu on x86 until I can set up aarch64 platform if it is reproducible
> > on real machine only.
> >
> >> 
> >> The kernel has been configured with transparent hugepages.
> >> 
> >> CONFIG_TRANSPARENT_HUGEPAGE=y
> >> CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
> >> # CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
> >> CONFIG_TRANSPARENT_HUGE_PAGECACHE=y
> >
> > What's the exact kernel version?
> 
> Anything >= your commit.

Thanks for the info. I cannot setup testing enviroment but when I read code,
it seems we need pmd_wrprotect for non-hardware dirty architecture.

Below helps?

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e10a4fe..dc37c9a 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1611,6 +1611,7 @@ int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
 			tlb->fullmm);
 		orig_pmd = pmd_mkold(orig_pmd);
 		orig_pmd = pmd_mkclean(orig_pmd);
+		orig_pmd = pmd_wrprotect(orig_pmd);
 
 		set_pmd_at(mm, addr, pmd, orig_pmd);
 		tlb_remove_pmd_tlb_entry(tlb, pmd, addr);

^ permalink raw reply related

* Linux fails to start secondary cores when system resumes from Suspend-to-RAM
From: Yu Chen @ 2016-12-16  5:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d4db03ce-80fc-2968-c5c2-84f79272ce8d@free.fr>

On Thu, Dec 15, 2016 at 11:18 PM, Mason <slash.tmp@free.fr> wrote:
> Hello,
>
> I'm playing with suspend-to-RAM on the tango platform:
>
>   http://lxr.free-electrons.com/source/arch/arm/mach-tango/platsmp.c
>
> When the system is suspended, the CPU is completely powered down
> (receives no power whatsoever). When the system receives a wake-up
> event, the CPU is powered up, and starts up exactly the same way
> as for a cold boot (I think).
>
> However, while Linux successfully starts the secondary cores when
> the system first boots, it fails when the system resumes from "S3".
>
> I added printascii() calls inside secondary_start_kernel() and I can
> see that the following instruction are "properly" run:
>
>         cpu_switch_mm(mm->pgd, mm);
>         local_flush_bp_all();
>         enter_lazy_tlb(mm, current);
>
> but it seems local_flush_tlb_all(); never returns... :-(
>
>   http://lxr.free-electrons.com/source/arch/arm/include/asm/tlbflush.h#L332
>
>
> Looking more closely at that function, it seems to be failing in:
>
>         tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
>
> (meaning: I get a log before, but not after)
>
> On my system, tlb_op(TLB_V7_UIS_FULL, "c8, c7, 0", zero);
> resolves to:
>
> c010ce18:       e3170602        tst     r7, #2097152    ; 0x200000
> c010ce1c:       1e086f17        mcrne   15, 0, r6, cr8, cr7, {0}
>
> What could be happening?
> Can a core "hang" on this instruction?
> Can a core "crash" on this instruction (meaning, an exception
> is raised, and the core loops inside the exception code without
> Linux noticing... that seems unlikely)
>
> I'm stumped. Could someone throw me a clue?
try online/offline the nonboot CPUs via
/sys/devices/system/cpu/cpuX/online

^ permalink raw reply

* [PATCH v2] i2c: designware: add reset interface
From: zhangfei @ 2016-12-16  3:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <fd0afd5f-6ee4-a06f-2d03-444f71662c1b@linaro.org>

Hi, Philipp


On 2016?12?16? 10:45, zhangfei wrote:
>
>
> On 2016?12?15? 23:30, Ramiro Oliveira wrote:
>> Hi Andy and Zhangfei
>>
>> On 12/15/2016 12:33 PM, Andy Shevchenko wrote:
>>> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>>>> Some platforms like hi3660 need do reset first to allow accessing
>>>> registers
>>> Patch itself looks good, but would be nice to have it tested.
>>>
>>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>>
>> I tested the patch and it's working for the ARC architecture.
>>
>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>>> ---
>>>>   drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>>>   drivers/i2c/busses/i2c-designware-platdrv.c | 28
>>>> ++++++++++++++++++++++++----
>>>>   2 files changed, 25 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>>> b/drivers/i2c/busses/i2c-designware-core.h
>>>> index 0d44d2a..94b14fa 100644
>>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>>       void __iomem        *base;
>>>>       struct completion    cmd_complete;
>>>>       struct clk        *clk;
>>>> +    struct reset_control    *rst;
>>>>       u32            (*get_clk_rate_khz) (struct
>>>> dw_i2c_dev *dev);
>>>>       struct dw_pci_controller *controller;
>>>>       int            cmd_err;
>>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> index 0b42a12..e9016ae 100644
>>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>>> @@ -38,6 +38,7 @@
>>>>   #include <linux/pm_runtime.h>
>>>>   #include <linux/property.h>
>>>>   #include <linux/io.h>
>>>> +#include <linux/reset.h>
>>>>   #include <linux/slab.h>
>>>>   #include <linux/acpi.h>
>>>>   #include <linux/platform_data/i2c-designware.h>
>>>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>>>> platform_device *pdev)
>>>>       dev->irq = irq;
>>>>       platform_set_drvdata(pdev, dev);
>>>>   +    dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
>> devm_reset_control_get_optional() is deprecated as explained in 
>> linux/reset.h,
>> you should use devm_reset_control_get_optional_exclusive() or
>> devm_reset_control_get_optional_shared() instead, as applicable.
>>
>> I submitted a similar patch earlier today and I made the same mistake.
>
> Thanks Ramiro for the info
> Will use devm_reset_control_get_optional_exclusive instead.
> But should the interface be as simple as possible?
>
> Thanks
Sorry, a bit confused.
Is that mean we should not use devm_reset_control_get_optional()
While driver should decide whether use 
devm_reset_control_get_optional_exclusive() or
devm_reset_control_get_optional_shared()
What if different platform has different requirement?

Looks the difference between _exclusive and _shared is refcount,
How about handle this inside, and not decided by interface?

Thanks

^ permalink raw reply

* [PATCH v2] i2c: designware: add reset interface
From: zhangfei @ 2016-12-16  2:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <fda7e3ef-5bc1-9837-b421-4293baa3de34@synopsys.com>



On 2016?12?15? 23:30, Ramiro Oliveira wrote:
> Hi Andy and Zhangfei
>
> On 12/15/2016 12:33 PM, Andy Shevchenko wrote:
>> On Thu, 2016-12-15 at 16:59 +0800, Zhangfei Gao wrote:
>>> Some platforms like hi3660 need do reset first to allow accessing
>>> registers
>> Patch itself looks good, but would be nice to have it tested.
>>
>> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>>
> I tested the patch and it's working for the ARC architecture.
>
>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>> ---
>>>   drivers/i2c/busses/i2c-designware-core.h    |  1 +
>>>   drivers/i2c/busses/i2c-designware-platdrv.c | 28
>>> ++++++++++++++++++++++++----
>>>   2 files changed, 25 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-designware-core.h
>>> b/drivers/i2c/busses/i2c-designware-core.h
>>> index 0d44d2a..94b14fa 100644
>>> --- a/drivers/i2c/busses/i2c-designware-core.h
>>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>>> @@ -80,6 +80,7 @@ struct dw_i2c_dev {
>>>   	void __iomem		*base;
>>>   	struct completion	cmd_complete;
>>>   	struct clk		*clk;
>>> +	struct reset_control	*rst;
>>>   	u32			(*get_clk_rate_khz) (struct
>>> dw_i2c_dev *dev);
>>>   	struct dw_pci_controller *controller;
>>>   	int			cmd_err;
>>> diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> index 0b42a12..e9016ae 100644
>>> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
>>> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
>>> @@ -38,6 +38,7 @@
>>>   #include <linux/pm_runtime.h>
>>>   #include <linux/property.h>
>>>   #include <linux/io.h>
>>> +#include <linux/reset.h>
>>>   #include <linux/slab.h>
>>>   #include <linux/acpi.h>
>>>   #include <linux/platform_data/i2c-designware.h>
>>> @@ -176,6 +177,14 @@ static int dw_i2c_plat_probe(struct
>>> platform_device *pdev)
>>>   	dev->irq = irq;
>>>   	platform_set_drvdata(pdev, dev);
>>>   
>>> +	dev->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
> devm_reset_control_get_optional() is deprecated as explained in linux/reset.h,
> you should use devm_reset_control_get_optional_exclusive() or
> devm_reset_control_get_optional_shared() instead, as applicable.
>
> I submitted a similar patch earlier today and I made the same mistake.

Thanks Ramiro for the info
Will use devm_reset_control_get_optional_exclusive instead.
But should the interface be as simple as possible?

Thanks

^ permalink raw reply

* [PATCH 2/2] arm64: mm: enable CONFIG_HOLES_IN_ZONE for NUMA
From: Hanjun Guo @ 2016-12-16  1:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161215153930.GA8111@rric.localdomain>

Hi Robert,

On 2016/12/15 23:39, Robert Richter wrote:
> I was going to do some measurements but my kernel crashes now with a
> page fault in efi_rtc_probe():
>
> [   21.663393] Unable to handle kernel paging request at virtual address 20251000
> [   21.663396] pgd = ffff000009090000
> [   21.663401] [20251000] *pgd=0000010ffff90003
> [   21.663402] , *pud=0000010ffff90003
> [   21.663404] , *pmd=0000000fdc030003
> [   21.663405] , *pte=00e8832000250707
>
> The sparsemem config requires the whole section to be initialized.
> Your patches do not address this.

This patch set is running properly on D05, both the boot and
LTP MM stress test are ok, seems it's a different configuration
of memory mappings in firmware, just a stupid question, which
part is related to this problem, is it only the Reserved memory?

Thanks
Hanjun

^ permalink raw reply

* [RFC v3 PATCH 20/25] ARM: i.MX: remove map_io callback
From: Shawn Guo @ 2016-12-16  1:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480691143-19845-21-git-send-email-vladimir.murzin@arm.com>

On Fri, Dec 02, 2016 at 03:05:38PM +0000, Vladimir Murzin wrote:
> There is no need to define map_io only for debug_ll_io_init() since it
> is already called in devicemaps_init() if map_io is NULL.
> 
> Apart from that, for NOMMU build debug_ll_io_init() is a nop which
> leads to following error:
> 
> CC      arch/arm/mach-imx/mach-imx1.o
> arch/arm/mach-imx/mach-imx1.c:40:13: error: 'debug_ll_io_init' undeclared here (not in a function)
>   .map_io  = debug_ll_io_init,
>              ^
> make[1]: *** [arch/arm/mach-imx/mach-imx1.o] Error 1
> 
> Cc: Alexander Shiyan <shc_work@mail.ru>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>

It looks like a cleanup which can be applied separately.

Applied, thanks.

Shawn

> ---
>  arch/arm/mach-imx/mach-imx1.c |    1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/arch/arm/mach-imx/mach-imx1.c b/arch/arm/mach-imx/mach-imx1.c
> index de5ab8d..3a8406e 100644
> --- a/arch/arm/mach-imx/mach-imx1.c
> +++ b/arch/arm/mach-imx/mach-imx1.c
> @@ -37,7 +37,6 @@ static void __init imx1_init_irq(void)
>  };
>  
>  DT_MACHINE_START(IMX1_DT, "Freescale i.MX1 (Device Tree Support)")
> -	.map_io		= debug_ll_io_init,
>  	.init_early	= imx1_init_early,
>  	.init_irq	= imx1_init_irq,
>  	.dt_compat	= imx1_dt_board_compat,
> -- 
> 1.7.9.5
> 

^ permalink raw reply


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