Devicetree
 help / color / mirror / Atom feed
* [PATCH v3 11/13] clocksource: export the clocks_calc_mult_shift to use by timestamp code
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner, John Stultz,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

From: Murali Karicheri <m-karicheri2@ti.com>

The CPSW CPTS driver is capable of doing timestamping on tx/rx packets and
requires to know mult and shift factors for timestamp conversion from raw
value to nanoseconds (ptp clock). Now these mult and shift factors are
calculated manually and provided through DT, which makes very hard to
support of a lot number of platforms, especially if CPTS refclk is not the
same for some kind of boards and depends on efuse settings (Keystone 2
platforms). Hence, export clocks_calc_mult_shift() to allow drivers like
CPSW CPTS (and other ptp drivesr) to benefit from automaitc calculation of
mult and shift factors.

Cc: John Stultz <john.stultz@linaro.org>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 kernel/time/clocksource.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 7e4fad7..150242c 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -89,6 +89,7 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
 	*mult = tmp;
 	*shift = sft;
 }
+EXPORT_SYMBOL_GPL(clocks_calc_mult_shift);
 
 /*[Clocksource internal variables]---------
  * curr_clocksource:
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 10/13] net: ethernet: ti: cpts: move dt props parsing to cpts driver
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
	Richard Cochran
  Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
	Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>

Move DT properties parsing into CPTS driver to simplify CPSW
code and CPTS driver porting on other SoC in the future
(like Keystone 2) - with this change it will not be required
to add the same DT parsing code in Keystone 2 NETCP driver.

Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
 drivers/net/ethernet/ti/cpsw.c | 16 +---------------
 drivers/net/ethernet/ti/cpsw.h |  2 --
 drivers/net/ethernet/ti/cpts.c | 32 +++++++++++++++++++++++++++++---
 drivers/net/ethernet/ti/cpts.h |  5 +++--
 4 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 6c28ef1..ae1ec6a 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2312,18 +2312,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->active_slave = prop;
 
-	if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {
-		dev_err(&pdev->dev, "Missing cpts_clock_mult property in the DT.\n");
-		return -EINVAL;
-	}
-	data->cpts_clock_mult = prop;
-
-	if (of_property_read_u32(node, "cpts_clock_shift", &prop)) {
-		dev_err(&pdev->dev, "Missing cpts_clock_shift property in the DT.\n");
-		return -EINVAL;
-	}
-	data->cpts_clock_shift = prop;
-
 	data->slave_data = devm_kzalloc(&pdev->dev, data->slaves
 					* sizeof(struct cpsw_slave_data),
 					GFP_KERNEL);
@@ -2789,9 +2777,7 @@ static int cpsw_probe(struct platform_device *pdev)
 		goto clean_dma_ret;
 	}
 
-	cpsw->cpts = cpts_create(cpsw->dev, cpts_regs,
-				 cpsw->data.cpts_clock_mult,
-				 cpsw->data.cpts_clock_shift);
+	cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpsw->dev->of_node);
 	if (IS_ERR(cpsw->cpts)) {
 		ret = PTR_ERR(cpsw->cpts);
 		goto clean_ale_ret;
diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h
index 16b54c6..6c3037a 100644
--- a/drivers/net/ethernet/ti/cpsw.h
+++ b/drivers/net/ethernet/ti/cpsw.h
@@ -31,8 +31,6 @@ struct cpsw_platform_data {
 	u32	channels;	/* number of cpdma channels (symmetric) */
 	u32	slaves;		/* number of slave cpgmac ports */
 	u32	active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */
-	u32	cpts_clock_mult;  /* convert input clock ticks to nanoseconds */
-	u32	cpts_clock_shift; /* convert input clock ticks to nanoseconds */
 	u32	ale_entries;	/* ale table size */
 	u32	bd_ram_size;  /*buffer descriptor ram size */
 	u32	mac_control;	/* Mac control register */
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 47831b2..5d5c46d 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -409,10 +409,34 @@ void cpts_unregister(struct cpts *cpts)
 }
 EXPORT_SYMBOL_GPL(cpts_unregister);
 
+static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
+{
+	int ret = -EINVAL;
+	u32 prop;
+
+	if (of_property_read_u32(node, "cpts_clock_mult", &prop))
+		goto  of_error;
+	/* save cc.mult original value as it can be modified
+	 * by cpts_ptp_adjfreq().
+	 */
+	cpts->cc_mult = prop;
+
+	if (of_property_read_u32(node, "cpts_clock_shift", &prop))
+		goto  of_error;
+	cpts->cc.shift = prop;
+
+	return 0;
+
+of_error:
+	dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
+	return ret;
+}
+
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-			 u32 mult, u32 shift)
+			 struct device_node *node)
 {
 	struct cpts *cpts;
+	int ret;
 
 	cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
 	if (!cpts)
@@ -423,6 +447,10 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
 	spin_lock_init(&cpts->lock);
 	INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
 
+	ret = cpts_of_parse(cpts, node);
+	if (ret)
+		return ERR_PTR(ret);
+
 	cpts->refclk = devm_clk_get(dev, "cpts");
 	if (IS_ERR(cpts->refclk)) {
 		dev_err(dev, "Failed to get cpts refclk\n");
@@ -433,8 +461,6 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
 
 	cpts->cc.read = cpts_systim_read;
 	cpts->cc.mask = CLOCKSOURCE_MASK(32);
-	cpts->cc.shift = shift;
-	cpts->cc_mult = mult;
 	cpts->info = cpts_info;
 
 	return cpts;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index e7d857c..5da23af 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -27,6 +27,7 @@
 #include <linux/clocksource.h>
 #include <linux/device.h>
 #include <linux/list.h>
+#include <linux/of.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/skbuff.h>
 #include <linux/timecounter.h>
@@ -133,7 +134,7 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 int cpts_register(struct cpts *cpts);
 void cpts_unregister(struct cpts *cpts);
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-			 u32 mult, u32 shift);
+			 struct device_node *node);
 void cpts_release(struct cpts *cpts);
 
 static inline void cpts_rx_enable(struct cpts *cpts, int enable)
@@ -168,7 +169,7 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 
 static inline
 struct cpts *cpts_create(struct device *dev, void __iomem *regs,
-			 u32 mult, u32 shift)
+			 struct device_node *node)
 {
 	return NULL;
 }
-- 
2.10.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v3 09/13] net: ethernet: ti: cpts: rework initialization/deinitialization
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

The current implementation CPTS initialization and deinitialization
(represented by cpts_register/unregister()) does too many static
initialization from .ndo_open(), which is reasonable to do once at probe
time instead, and also require caller to allocate memory for struct cpts,
which is internal for CPTS driver in general.

This patch splits CPTS initialization and deinitialization on two parts:

- static initializtion cpts_create()/cpts_release() which expected to be
executed when parent driver is probed/removed;

- dynamic part cpts_register/unregister() which expected to be executed
when network device is opened/closed.

As result, current code of CPTS parent driver - CPSW - will be simplified
(and it also will allow simplify adding support for Keystone 2 devices in
the future), plus more initialization errors will be catched earlier. In
addition, this change allows to clean up cpts.h for the case when CPTS is
disabled.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c |  24 +++++-----
 drivers/net/ethernet/ti/cpts.c | 102 ++++++++++++++++++++++++-----------------
 drivers/net/ethernet/ti/cpts.h |  26 +++++++++--
 3 files changed, 95 insertions(+), 57 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a6a93ad..6c28ef1 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1406,9 +1406,7 @@ static int cpsw_ndo_open(struct net_device *ndev)
 		if (ret < 0)
 			goto err_cleanup;
 
-		if (cpts_register(cpsw->dev, cpsw->cpts,
-				  cpsw->data.cpts_clock_mult,
-				  cpsw->data.cpts_clock_shift))
+		if (cpts_register(cpsw->cpts))
 			dev_err(priv->dev, "error registering cpts device\n");
 
 	}
@@ -2596,6 +2594,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	struct cpdma_params		dma_params;
 	struct cpsw_ale_params		ale_params;
 	void __iomem			*ss_regs;
+	void __iomem			*cpts_regs;
 	struct resource			*res, *ss_res;
 	const struct of_device_id	*of_id;
 	struct gpio_descs		*mode;
@@ -2623,12 +2622,6 @@ static int cpsw_probe(struct platform_device *pdev)
 	priv->dev  = &ndev->dev;
 	priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
 	cpsw->rx_packet_max = max(rx_packet_max, 128);
-	cpsw->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
-	if (!cpsw->cpts) {
-		dev_err(&pdev->dev, "error allocating cpts\n");
-		ret = -ENOMEM;
-		goto clean_ndev_ret;
-	}
 
 	mode = devm_gpiod_get_array_optional(&pdev->dev, "mode", GPIOD_OUT_LOW);
 	if (IS_ERR(mode)) {
@@ -2716,7 +2709,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	switch (cpsw->version) {
 	case CPSW_VERSION_1:
 		cpsw->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
-		cpsw->cpts->reg      = ss_regs + CPSW1_CPTS_OFFSET;
+		cpts_regs		= ss_regs + CPSW1_CPTS_OFFSET;
 		cpsw->hw_stats	     = ss_regs + CPSW1_HW_STATS;
 		dma_params.dmaregs   = ss_regs + CPSW1_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW1_STATERAM_OFFSET;
@@ -2730,7 +2723,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	case CPSW_VERSION_3:
 	case CPSW_VERSION_4:
 		cpsw->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
-		cpsw->cpts->reg      = ss_regs + CPSW2_CPTS_OFFSET;
+		cpts_regs		= ss_regs + CPSW2_CPTS_OFFSET;
 		cpsw->hw_stats	     = ss_regs + CPSW2_HW_STATS;
 		dma_params.dmaregs   = ss_regs + CPSW2_CPDMA_OFFSET;
 		dma_params.txhdp     = ss_regs + CPSW2_STATERAM_OFFSET;
@@ -2796,6 +2789,14 @@ static int cpsw_probe(struct platform_device *pdev)
 		goto clean_dma_ret;
 	}
 
+	cpsw->cpts = cpts_create(cpsw->dev, cpts_regs,
+				 cpsw->data.cpts_clock_mult,
+				 cpsw->data.cpts_clock_shift);
+	if (IS_ERR(cpsw->cpts)) {
+		ret = PTR_ERR(cpsw->cpts);
+		goto clean_ale_ret;
+	}
+
 	ndev->irq = platform_get_irq(pdev, 1);
 	if (ndev->irq < 0) {
 		dev_err(priv->dev, "error getting irq resource\n");
@@ -2911,6 +2912,7 @@ static int cpsw_remove(struct platform_device *pdev)
 		unregister_netdev(cpsw->slaves[1].ndev);
 	unregister_netdev(ndev);
 
+	cpts_release(cpsw->cpts);
 	cpsw_ale_destroy(cpsw->ale);
 	cpdma_ctlr_destroy(cpsw->dma);
 	cpsw_remove_dt(pdev);
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index a662c33..47831b2 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -248,24 +248,6 @@ static void cpts_overflow_check(struct work_struct *work)
 	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
 }
 
-static void cpts_clk_init(struct device *dev, struct cpts *cpts)
-{
-	if (!cpts->refclk) {
-		cpts->refclk = devm_clk_get(dev, "cpts");
-		if (IS_ERR(cpts->refclk)) {
-			dev_err(dev, "Failed to get cpts refclk\n");
-			cpts->refclk = NULL;
-			return;
-		}
-	}
-	clk_prepare_enable(cpts->refclk);
-}
-
-static void cpts_clk_release(struct cpts *cpts)
-{
-	clk_disable_unprepare(cpts->refclk);
-}
-
 static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
 		      u16 ts_seqid, u8 ts_msgtype)
 {
@@ -372,34 +354,27 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
 
-int cpts_register(struct device *dev, struct cpts *cpts,
-		  u32 mult, u32 shift)
+int cpts_register(struct cpts *cpts)
 {
 	int err, i;
 
-	cpts->info = cpts_info;
-	spin_lock_init(&cpts->lock);
-
-	cpts->cc.read = cpts_systim_read;
-	cpts->cc.mask = CLOCKSOURCE_MASK(32);
-	cpts->cc_mult = mult;
-	cpts->cc.mult = mult;
-	cpts->cc.shift = shift;
-
 	INIT_LIST_HEAD(&cpts->events);
 	INIT_LIST_HEAD(&cpts->pool);
 	for (i = 0; i < CPTS_MAX_EVENTS; i++)
 		list_add(&cpts->pool_data[i].list, &cpts->pool);
 
-	cpts_clk_init(dev, cpts);
+	clk_enable(cpts->refclk);
+
 	cpts_write32(cpts, CPTS_EN, control);
 	cpts_write32(cpts, TS_PEND_EN, int_enable);
 
+	/* reinitialize cc.mult to original value as it can be modified
+	 * by cpts_ptp_adjfreq().
+	 */
+	cpts->cc.mult = cpts->cc_mult;
 	timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
 
-	INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
-
-	cpts->clock = ptp_clock_register(&cpts->info, dev);
+	cpts->clock = ptp_clock_register(&cpts->info, cpts->dev);
 	if (IS_ERR(cpts->clock)) {
 		err = PTR_ERR(cpts->clock);
 		cpts->clock = NULL;
@@ -412,27 +387,72 @@ int cpts_register(struct device *dev, struct cpts *cpts,
 	return 0;
 
 err_ptp:
-	if (cpts->refclk)
-		cpts_clk_release(cpts);
+	clk_disable(cpts->refclk);
 	return err;
 }
 EXPORT_SYMBOL_GPL(cpts_register);
 
 void cpts_unregister(struct cpts *cpts)
 {
-	if (cpts->clock) {
-		ptp_clock_unregister(cpts->clock);
-		cancel_delayed_work_sync(&cpts->overflow_work);
-	}
+	if (WARN_ON(!cpts->clock))
+		return;
+
+	cancel_delayed_work_sync(&cpts->overflow_work);
+
+	ptp_clock_unregister(cpts->clock);
+	cpts->clock = NULL;
 
 	cpts_write32(cpts, 0, int_enable);
 	cpts_write32(cpts, 0, control);
 
-	if (cpts->refclk)
-		cpts_clk_release(cpts);
+	clk_disable(cpts->refclk);
 }
 EXPORT_SYMBOL_GPL(cpts_unregister);
 
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+			 u32 mult, u32 shift)
+{
+	struct cpts *cpts;
+
+	cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
+	if (!cpts)
+		return ERR_PTR(-ENOMEM);
+
+	cpts->dev = dev;
+	cpts->reg = (struct cpsw_cpts __iomem *)regs;
+	spin_lock_init(&cpts->lock);
+	INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
+
+	cpts->refclk = devm_clk_get(dev, "cpts");
+	if (IS_ERR(cpts->refclk)) {
+		dev_err(dev, "Failed to get cpts refclk\n");
+		return ERR_PTR(PTR_ERR(cpts->refclk));
+	}
+
+	clk_prepare(cpts->refclk);
+
+	cpts->cc.read = cpts_systim_read;
+	cpts->cc.mask = CLOCKSOURCE_MASK(32);
+	cpts->cc.shift = shift;
+	cpts->cc_mult = mult;
+	cpts->info = cpts_info;
+
+	return cpts;
+}
+EXPORT_SYMBOL_GPL(cpts_create);
+
+void cpts_release(struct cpts *cpts)
+{
+	if (!cpts)
+		return;
+
+	if (WARN_ON(!cpts->clock))
+		return;
+
+	clk_unprepare(cpts->refclk);
+}
+EXPORT_SYMBOL_GPL(cpts_release);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("TI CPTS driver");
 MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 29a1e80c..e7d857c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -20,6 +20,8 @@
 #ifndef _TI_CPTS_H_
 #define _TI_CPTS_H_
 
+#if IS_ENABLED(CONFIG_TI_CPTS)
+
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clocksource.h>
@@ -108,10 +110,10 @@ struct cpts_event {
 };
 
 struct cpts {
+	struct device *dev;
 	struct cpsw_cpts __iomem *reg;
 	int tx_enable;
 	int rx_enable;
-#if IS_ENABLED(CONFIG_TI_CPTS)
 	struct ptp_clock_info info;
 	struct ptp_clock *clock;
 	spinlock_t lock; /* protects time registers */
@@ -124,14 +126,15 @@ struct cpts {
 	struct list_head events;
 	struct list_head pool;
 	struct cpts_event pool_data[CPTS_MAX_EVENTS];
-#endif
 };
 
-#if IS_ENABLED(CONFIG_TI_CPTS)
 void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
-int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
+int cpts_register(struct cpts *cpts);
 void cpts_unregister(struct cpts *cpts);
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+			 u32 mult, u32 shift);
+void cpts_release(struct cpts *cpts);
 
 static inline void cpts_rx_enable(struct cpts *cpts, int enable)
 {
@@ -154,6 +157,8 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts)
 }
 
 #else
+struct cpts;
+
 static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
 }
@@ -161,8 +166,19 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
 }
 
+static inline
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+			 u32 mult, u32 shift)
+{
+	return NULL;
+}
+
+static inline void cpts_release(struct cpts *cpts)
+{
+}
+
 static inline int
-cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
+cpts_register(struct cpts *cpts)
 {
 	return 0;
 }
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 08/13] net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

CPTS module and IRQs are always enabled when CPTS is registered,
before starting overflow check work, and disabled during
deregistration, when overflow check work has been canceled already.
So, It doesn't require to (re)enable CPTS module and IRQs in
cpts_overflow_check().

Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpts.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 8266459..a662c33 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -243,8 +243,6 @@ static void cpts_overflow_check(struct work_struct *work)
 	struct timespec64 ts;
 	struct cpts *cpts = container_of(work, struct cpts, overflow_work.work);
 
-	cpts_write32(cpts, CPTS_EN, control);
-	cpts_write32(cpts, TS_PEND_EN, int_enable);
 	cpts_ptp_gettime(&cpts->info, &ts);
 	pr_debug("cpts overflow check at %lld.%09lu\n", ts.tv_sec, ts.tv_nsec);
 	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 07/13] net: ethernet: ti: cpts: clean up event list if event pool is empty
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

From: WingMan Kwok <w-kwok2@ti.com>

When a CPTS user does not exit gracefully by disabling cpts
timestamping and leaving a joined multicast group, the system
continues to receive and timestamps the ptp packets which eventually
occupy all the event list entries.  When this happns, the added code
tries to remove some list entries which are expired.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpts.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index d3c1ac5..8266459 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -57,6 +57,26 @@ static int cpts_fifo_pop(struct cpts *cpts, u32 *high, u32 *low)
 	return -1;
 }
 
+static int cpts_purge_events(struct cpts *cpts)
+{
+	struct list_head *this, *next;
+	struct cpts_event *event;
+	int removed = 0;
+
+	list_for_each_safe(this, next, &cpts->events) {
+		event = list_entry(this, struct cpts_event, list);
+		if (event_expired(event)) {
+			list_del_init(&event->list);
+			list_add(&event->list, &cpts->pool);
+			++removed;
+		}
+	}
+
+	if (removed)
+		dev_dbg(cpts->dev, "cpts: event pool cleaned up %d\n", removed);
+	return removed ? 0 : -1;
+}
+
 /*
  * Returns zero if matching event type was found.
  */
@@ -69,10 +89,12 @@ static int cpts_fifo_read(struct cpts *cpts, int match)
 	for (i = 0; i < CPTS_FIFO_DEPTH; i++) {
 		if (cpts_fifo_pop(cpts, &hi, &lo))
 			break;
-		if (list_empty(&cpts->pool)) {
-			pr_err("cpts: event pool is empty\n");
+
+		if (list_empty(&cpts->pool) && cpts_purge_events(cpts)) {
+			dev_err(cpts->dev, "cpts: event pool empty\n");
 			return -1;
 		}
+
 		event = list_first_entry(&cpts->pool, struct cpts_event, list);
 		event->tmo = jiffies + 2;
 		event->high = hi;
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 06/13] net: ethernet: ti: cpts: disable cpts when unregistered
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

The cpts now is left enabled after unregistration.
Hence, disable it in cpts_unregister().

Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpts.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 3dda6d5..d3c1ac5 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -404,6 +404,10 @@ void cpts_unregister(struct cpts *cpts)
 		ptp_clock_unregister(cpts->clock);
 		cancel_delayed_work_sync(&cpts->overflow_work);
 	}
+
+	cpts_write32(cpts, 0, int_enable);
+	cpts_write32(cpts, 0, control);
+
 	if (cpts->refclk)
 		cpts_clk_release(cpts);
 }
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 05/13] net: ethernet: ti: cpts: fix registration order
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

The ptp clock registered before spinlock, which is protecting it, and
before timecounter and cyclecounter initialization in cpts_register().

So, ensure that ptp clock is registered the last, after everything
else is done.

Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpts.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 61198f1..3dda6d5 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -356,15 +356,8 @@ int cpts_register(struct device *dev, struct cpts *cpts,
 		  u32 mult, u32 shift)
 {
 	int err, i;
-	unsigned long flags;
 
 	cpts->info = cpts_info;
-	cpts->clock = ptp_clock_register(&cpts->info, dev);
-	if (IS_ERR(cpts->clock)) {
-		err = PTR_ERR(cpts->clock);
-		cpts->clock = NULL;
-		return err;
-	}
 	spin_lock_init(&cpts->lock);
 
 	cpts->cc.read = cpts_systim_read;
@@ -382,15 +375,26 @@ int cpts_register(struct device *dev, struct cpts *cpts,
 	cpts_write32(cpts, CPTS_EN, control);
 	cpts_write32(cpts, TS_PEND_EN, int_enable);
 
-	spin_lock_irqsave(&cpts->lock, flags);
 	timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
-	spin_unlock_irqrestore(&cpts->lock, flags);
 
 	INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
-	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
 
+	cpts->clock = ptp_clock_register(&cpts->info, dev);
+	if (IS_ERR(cpts->clock)) {
+		err = PTR_ERR(cpts->clock);
+		cpts->clock = NULL;
+		goto err_ptp;
+	}
 	cpts->phc_index = ptp_clock_index(cpts->clock);
+
+	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+
 	return 0;
+
+err_ptp:
+	if (cpts->refclk)
+		cpts_clk_release(cpts);
+	return err;
 }
 EXPORT_SYMBOL_GPL(cpts_register);
 
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 04/13] net: ethernet: ti: cpts: fix unbalanced clk api usage in cpts_register/unregister
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
	Richard Cochran
  Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
	Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>

There are two issues with TI CPTS code which are reproducible when TI
CPSW ethX device passes few up/down iterations:
- cpts refclk prepare counter continuously incremented after each
up/down iteration;
- devm_clk_get(dev, "cpts") is called many times.

Hence, fix these issues by using clk_disable_unprepare() in
cpts_clk_release() and skipping devm_clk_get() if cpts refclk has been
acquired already.

Acked-by: Richard Cochran <richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
 drivers/net/ethernet/ti/cpts.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 8cb0369..61198f1 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -230,18 +230,20 @@ static void cpts_overflow_check(struct work_struct *work)
 
 static void cpts_clk_init(struct device *dev, struct cpts *cpts)
 {
-	cpts->refclk = devm_clk_get(dev, "cpts");
-	if (IS_ERR(cpts->refclk)) {
-		dev_err(dev, "Failed to get cpts refclk\n");
-		cpts->refclk = NULL;
-		return;
+	if (!cpts->refclk) {
+		cpts->refclk = devm_clk_get(dev, "cpts");
+		if (IS_ERR(cpts->refclk)) {
+			dev_err(dev, "Failed to get cpts refclk\n");
+			cpts->refclk = NULL;
+			return;
+		}
 	}
 	clk_prepare_enable(cpts->refclk);
 }
 
 static void cpts_clk_release(struct cpts *cpts)
 {
-	clk_disable(cpts->refclk);
+	clk_disable_unprepare(cpts->refclk);
 }
 
 static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
-- 
2.10.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v3 03/13] net: ethernet: ti: cpsw: minimize direct access to struct cpts
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

This will provide more flexibility in changing CPTS internals and also
required for further changes.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c | 28 +++++++++++++++-------------
 drivers/net/ethernet/ti/cpts.h | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index f65a4e8..a6a93ad 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1481,7 +1481,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 	}
 
 	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-				cpsw->cpts->tx_enable)
+	    cpts_is_tx_enabled(cpsw->cpts))
 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
 	skb_tx_timestamp(skb);
@@ -1520,7 +1520,8 @@ static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
 	struct cpsw_slave *slave = &cpsw->slaves[cpsw->data.active_slave];
 	u32 ts_en, seq_id;
 
-	if (!cpsw->cpts->tx_enable && !cpsw->cpts->rx_enable) {
+	if (!cpts_is_tx_enabled(cpsw->cpts) &&
+	    !cpts_is_rx_enabled(cpsw->cpts)) {
 		slave_write(slave, 0, CPSW1_TS_CTL);
 		return;
 	}
@@ -1528,10 +1529,10 @@ static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
 	seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
 	ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;
 
-	if (cpsw->cpts->tx_enable)
+	if (cpts_is_tx_enabled(cpsw->cpts))
 		ts_en |= CPSW_V1_TS_TX_EN;
 
-	if (cpsw->cpts->rx_enable)
+	if (cpts_is_rx_enabled(cpsw->cpts))
 		ts_en |= CPSW_V1_TS_RX_EN;
 
 	slave_write(slave, ts_en, CPSW1_TS_CTL);
@@ -1554,20 +1555,20 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
 	case CPSW_VERSION_2:
 		ctrl &= ~CTRL_V2_ALL_TS_MASK;
 
-		if (cpsw->cpts->tx_enable)
+		if (cpts_is_tx_enabled(cpsw->cpts))
 			ctrl |= CTRL_V2_TX_TS_BITS;
 
-		if (cpsw->cpts->rx_enable)
+		if (cpts_is_rx_enabled(cpsw->cpts))
 			ctrl |= CTRL_V2_RX_TS_BITS;
 		break;
 	case CPSW_VERSION_3:
 	default:
 		ctrl &= ~CTRL_V3_ALL_TS_MASK;
 
-		if (cpsw->cpts->tx_enable)
+		if (cpts_is_tx_enabled(cpsw->cpts))
 			ctrl |= CTRL_V3_TX_TS_BITS;
 
-		if (cpsw->cpts->rx_enable)
+		if (cpts_is_rx_enabled(cpsw->cpts))
 			ctrl |= CTRL_V3_RX_TS_BITS;
 		break;
 	}
@@ -1603,7 +1604,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
 
 	switch (cfg.rx_filter) {
 	case HWTSTAMP_FILTER_NONE:
-		cpts->rx_enable = 0;
+		cpts_rx_enable(cpts, 0);
 		break;
 	case HWTSTAMP_FILTER_ALL:
 	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
@@ -1619,14 +1620,14 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
-		cpts->rx_enable = 1;
+		cpts_rx_enable(cpts, 1);
 		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 		break;
 	default:
 		return -ERANGE;
 	}
 
-	cpts->tx_enable = cfg.tx_type == HWTSTAMP_TX_ON;
+	cpts_tx_enable(cpts, cfg.tx_type == HWTSTAMP_TX_ON);
 
 	switch (cpsw->version) {
 	case CPSW_VERSION_1:
@@ -1655,8 +1656,9 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
 		return -EOPNOTSUPP;
 
 	cfg.flags = 0;
-	cfg.tx_type = cpts->tx_enable ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
-	cfg.rx_filter = (cpts->rx_enable ?
+	cfg.tx_type = cpts_is_tx_enabled(cpts) ?
+		      HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+	cfg.rx_filter = (cpts_is_rx_enabled(cpts) ?
 			 HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE);
 
 	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 416ba2c..29a1e80c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -132,6 +132,27 @@ void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
 void cpts_unregister(struct cpts *cpts);
+
+static inline void cpts_rx_enable(struct cpts *cpts, int enable)
+{
+	cpts->rx_enable = enable;
+}
+
+static inline bool cpts_is_rx_enabled(struct cpts *cpts)
+{
+	return !!cpts->rx_enable;
+}
+
+static inline void cpts_tx_enable(struct cpts *cpts, int enable)
+{
+	cpts->tx_enable = enable;
+}
+
+static inline bool cpts_is_tx_enabled(struct cpts *cpts)
+{
+	return !!cpts->tx_enable;
+}
+
 #else
 static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
@@ -149,6 +170,24 @@ cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
 static inline void cpts_unregister(struct cpts *cpts)
 {
 }
+
+static inline void cpts_rx_enable(struct cpts *cpts, int enable)
+{
+}
+
+static inline bool cpts_is_rx_enabled(struct cpts *cpts)
+{
+	return false;
+}
+
+static inline void cpts_tx_enable(struct cpts *cpts, int enable)
+{
+}
+
+static inline bool cpts_is_tx_enabled(struct cpts *cpts)
+{
+	return false;
+}
 #endif
 
 
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 02/13] net: ethernet: ti: allow cpts to be built separately
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

TI CPTS IP is used as part of TI OMAP CPSW driver, but it's also
present as part of NETCP on TI Keystone 2 SoCs. So, It's required
to enable build of CPTS for both this drivers and this can be
achieved by allowing CPTS to be built separately.

Hence, allow cpts to be built separately and convert it to be
a module as both CPSW and NETCP drives can be built as modules.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/Kconfig  |  2 +-
 drivers/net/ethernet/ti/Makefile |  3 ++-
 drivers/net/ethernet/ti/cpsw.c   | 22 +++++++++++++++++-----
 drivers/net/ethernet/ti/cpts.c   | 16 ++++++++--------
 drivers/net/ethernet/ti/cpts.h   | 18 ++++++++++++++----
 5 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 9904d74..ff7f518 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -74,7 +74,7 @@ config TI_CPSW
 	  will be called cpsw.
 
 config TI_CPTS
-	bool "TI Common Platform Time Sync (CPTS) Support"
+	tristate "TI Common Platform Time Sync (CPTS) Support"
 	depends on TI_CPSW
 	select PTP_1588_CLOCK
 	---help---
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index d420d94..1e7c10b 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -12,8 +12,9 @@ obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
 obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
 obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o
 obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o
+obj-$(CONFIG_TI_CPTS) += cpts.o
 obj-$(CONFIG_TI_CPSW) += ti_cpsw.o
-ti_cpsw-y := cpsw.o cpts.o
+ti_cpsw-y := cpsw.o
 
 obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o
 keystone_netcp-y := netcp_core.o
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 58947aa..f65a4e8 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1513,7 +1513,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 	return NETDEV_TX_BUSY;
 }
 
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
 
 static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
 {
@@ -1661,7 +1661,16 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
 
 	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
 }
+#else
+static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
+{
+	return -EOPNOTSUPP;
+}
 
+static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+{
+	return -EOPNOTSUPP;
+}
 #endif /*CONFIG_TI_CPTS*/
 
 static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
@@ -1674,12 +1683,10 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 		return -EINVAL;
 
 	switch (cmd) {
-#ifdef CONFIG_TI_CPTS
 	case SIOCSHWTSTAMP:
 		return cpsw_hwtstamp_set(dev, req);
 	case SIOCGHWTSTAMP:
 		return cpsw_hwtstamp_get(dev, req);
-#endif
 	}
 
 	if (!cpsw->slaves[slave_no].phy)
@@ -1935,10 +1942,10 @@ static void cpsw_set_msglevel(struct net_device *ndev, u32 value)
 	priv->msg_enable = value;
 }
 
+#if IS_ENABLED(CONFIG_TI_CPTS)
 static int cpsw_get_ts_info(struct net_device *ndev,
 			    struct ethtool_ts_info *info)
 {
-#ifdef CONFIG_TI_CPTS
 	struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
 
 	info->so_timestamping =
@@ -1955,7 +1962,12 @@ static int cpsw_get_ts_info(struct net_device *ndev,
 	info->rx_filters =
 		(1 << HWTSTAMP_FILTER_NONE) |
 		(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+	return 0;
+}
 #else
+static int cpsw_get_ts_info(struct net_device *ndev,
+			    struct ethtool_ts_info *info)
+{
 	info->so_timestamping =
 		SOF_TIMESTAMPING_TX_SOFTWARE |
 		SOF_TIMESTAMPING_RX_SOFTWARE |
@@ -1963,9 +1975,9 @@ static int cpsw_get_ts_info(struct net_device *ndev,
 	info->phc_index = -1;
 	info->tx_types = 0;
 	info->rx_filters = 0;
-#endif
 	return 0;
 }
+#endif
 
 static int cpsw_get_settings(struct net_device *ndev,
 			     struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index a42c449..8cb0369 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -31,8 +31,6 @@
 
 #include "cpts.h"
 
-#ifdef CONFIG_TI_CPTS
-
 #define cpts_read32(c, r)	readl_relaxed(&c->reg->r)
 #define cpts_write32(c, v, r)	writel_relaxed(v, &c->reg->r)
 
@@ -334,6 +332,7 @@ void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 	memset(ssh, 0, sizeof(*ssh));
 	ssh->hwtstamp = ns_to_ktime(ns);
 }
+EXPORT_SYMBOL_GPL(cpts_rx_timestamp);
 
 void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
@@ -349,13 +348,11 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 	ssh.hwtstamp = ns_to_ktime(ns);
 	skb_tstamp_tx(skb, &ssh);
 }
-
-#endif /*CONFIG_TI_CPTS*/
+EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
 
 int cpts_register(struct device *dev, struct cpts *cpts,
 		  u32 mult, u32 shift)
 {
-#ifdef CONFIG_TI_CPTS
 	int err, i;
 	unsigned long flags;
 
@@ -391,18 +388,21 @@ int cpts_register(struct device *dev, struct cpts *cpts,
 	schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
 
 	cpts->phc_index = ptp_clock_index(cpts->clock);
-#endif
 	return 0;
 }
+EXPORT_SYMBOL_GPL(cpts_register);
 
 void cpts_unregister(struct cpts *cpts)
 {
-#ifdef CONFIG_TI_CPTS
 	if (cpts->clock) {
 		ptp_clock_unregister(cpts->clock);
 		cancel_delayed_work_sync(&cpts->overflow_work);
 	}
 	if (cpts->refclk)
 		cpts_clk_release(cpts);
-#endif
 }
+EXPORT_SYMBOL_GPL(cpts_unregister);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI CPTS driver");
+MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 69a46b9..416ba2c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -111,7 +111,7 @@ struct cpts {
 	struct cpsw_cpts __iomem *reg;
 	int tx_enable;
 	int rx_enable;
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
 	struct ptp_clock_info info;
 	struct ptp_clock *clock;
 	spinlock_t lock; /* protects time registers */
@@ -127,9 +127,11 @@ struct cpts {
 #endif
 };
 
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
 void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
 void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
+int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
+void cpts_unregister(struct cpts *cpts);
 #else
 static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
@@ -137,9 +139,17 @@ static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
 {
 }
+
+static inline int
+cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
+{
+	return 0;
+}
+
+static inline void cpts_unregister(struct cpts *cpts)
+{
+}
 #endif
 
-int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
-void cpts_unregister(struct cpts *cpts);
 
 #endif
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 01/13] net: ethernet: ti: cpts: switch to readl/writel_relaxed()
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
  Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
	Murali Karicheri, Wingman Kwok, Thomas Gleixner,
	Grygorii Strashko
In-Reply-To: <20161202203023.25526-1-grygorii.strashko@ti.com>

Switch to readl/writel_relaxed() APIs, because this is recommended
API and the CPTS IP is reused on Keystone 2 SoCs
where LE/BE modes are supported.

Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/net/ethernet/ti/cpts.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 85a55b4..a42c449 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -33,8 +33,8 @@
 
 #ifdef CONFIG_TI_CPTS
 
-#define cpts_read32(c, r)	__raw_readl(&c->reg->r)
-#define cpts_write32(c, v, r)	__raw_writel(v, &c->reg->r)
+#define cpts_read32(c, r)	readl_relaxed(&c->reg->r)
+#define cpts_write32(c, v, r)	writel_relaxed(v, &c->reg->r)
 
 static int event_expired(struct cpts_event *event)
 {
-- 
2.10.1

^ permalink raw reply related

* [PATCH v3 00/13] net: ethernet: ti: cpts: update and fixes
From: Grygorii Strashko @ 2016-12-02 20:30 UTC (permalink / raw)
  To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
	Richard Cochran
  Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
	Thomas Gleixner, Grygorii Strashko

It is preparation series intended to clean up and optimize TI CPTS driver to
facilitate further integration with other TI's SoCs like Keystone 2.

Changes in v3:
- patches reordered: fixes and small updates moved first
- added comments in code about cpts->cc_mult
- conversation range (maxsec) limited to 10sec

Changes in v2:
- patch "net: ethernet: ti: cpts: rework initialization/deinitialization"
  was split on 4 patches
- applied comments from Richard Cochran
- dropped patch
  "net: ethernet: ti: cpts: add return value to tx and rx timestamp funcitons"
- new patches added:
  "net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs"
  and "clocksource: export the clocks_calc_mult_shift to use by timestamp code"

Links on prev versions:
v2: http://www.mail-archive.com/linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org/msg1282034.html
v1: http://www.spinics.net/lists/linux-omap/msg131925.html

Grygorii Strashko (11):
  net: ethernet: ti: cpts: switch to readl/writel_relaxed()
  net: ethernet: ti: allow cpts to be built separately
  net: ethernet: ti: cpsw: minimize direct access to struct cpts
  net: ethernet: ti: cpts: fix unbalanced clk api usage in cpts_register/unregister
  net: ethernet: ti: cpts: fix registration order
  net: ethernet: ti: cpts: disable cpts when unregistered
  net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs
  net: ethernet: ti: cpts: rework initialization/deinitialization
  net: ethernet: ti: cpts: move dt props parsing to cpts driver
  net: ethernet: ti: cpts: calc mult and shift from refclk freq
  net: ethernet: ti: cpts: fix overflow check period

Murali Karicheri (1):
  clocksource: export the clocks_calc_mult_shift to use by timestamp code

WingMan Kwok (1):
  net: ethernet: ti: cpts: clean up event list if event pool is empty

 Documentation/devicetree/bindings/net/cpsw.txt |   8 +-
 drivers/net/ethernet/ti/Kconfig                |   2 +-
 drivers/net/ethernet/ti/Makefile               |   3 +-
 drivers/net/ethernet/ti/cpsw.c                 |  84 ++++-----
 drivers/net/ethernet/ti/cpsw.h                 |   2 -
 drivers/net/ethernet/ti/cpts.c                 | 239 +++++++++++++++++++------
 drivers/net/ethernet/ti/cpts.h                 |  80 ++++++++-
 kernel/time/clocksource.c                      |   1 +
 8 files changed, 304 insertions(+), 115 deletions(-)

-- 
2.10.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 4/6] net: ethernet: ti: cpts: add ptp pps support
From: Richard Cochran @ 2016-12-02 19:28 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Murali Karicheri, Wingman Kwok, David S. Miller,
	netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N, Sekhar Nori,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <bfbebf2d-d057-6a21-845c-48f0a9ab0404-l0cyMroinI0@public.gmane.org>

On Fri, Dec 02, 2016 at 11:58:34AM -0600, Grygorii Strashko wrote:
> or I missed smth?

You are missing three important points.

1. Unlike the code you posted, no edges will be lost.

2. The solution using the PWM is implemented in USER SPACE.  If people
   use this way, then they will be forced to understand the inherit
   limitations.  In addition, the behavior of servo will be under
   their control.

3. The update rate of the PHC is not once per second.  It can be any
   rate at all, like 16 Hz for the telecom profile.  You can't just
   blindly pick out an adjustment value once per second.  Using the
   feedback from the time stamped PWM and adjusting THAT at the PWM
   rate (also not necessarily 1 PPS) is the right way.  The second
   reply in that thread is an even better solution, leaving the PHC
   free running and adjusting the timer input clock (probably they
   used a VCO).

Just hacking in some kind of kernel PPS with unknown accuracy is just
asking for trouble later, since people will expect HW accuracy.

So just get the input time stamps working, and make PWM control
available to userspace in mainline (not sure about this, I guess it
isn't), and leave the PPS part to a userspace utility.

Thanks,
Richard



--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/3] Documentation: dt: Add TI SCI clock driver
From: Stephen Boyd @ 2016-12-02 18:58 UTC (permalink / raw)
  To: Rob Herring, Tero Kristo
  Cc: linux-clk, Michael Turquette, Santosh Shilimkar, Nishanth Menon,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org
In-Reply-To: <CAL_JsqKox9WVXh=i1jSCijJDTACC35uiNtS-bg9fdyDrX0svRQ@mail.gmail.com>

On 12/02/2016 10:45 AM, Rob Herring wrote:
> On Fri, Dec 2, 2016 at 2:19 AM, Tero Kristo <t-kristo@ti.com> wrote:
>>
>> Rob, any response on this one? I see you have acked the reset part of the
>> bindings which is doing pretty much the same thing as the clock part is
>> doing here, namely adding child node under the main SCI node. Is it okay to
>> do this same for other parts of the TI SCI?
> Yes. It would be silly to allow for one and not others...
>

I'm expecting a respin for the node name (clocks or clock-controller).
I'll also make a review pass on patch 3 today so please don't respin
until after that.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply

* Re: [PATCH v3 -next 2/2] ARM: dts: sunxi: add support for Orange Pi Zero board
From: Icenowy Zheng @ 2016-12-02 18:52 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: linux-arm-kernel, linux-sunxi, Vishnu Patekar, Rob Herring,
	linux-kernel, Andre Przywara,
		linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Hans de Goede,
	Arnd Bergmann, devicetree, Russell King, Maxime Ripard


2016年12月3日 上午12:41于 Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>写道:
>
> Hi, 
>
> On Fri, Dec 2, 2016 at 11:05 PM, Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org> wrote: 
> > Orange Pi Zero is a board that came with the new Allwinner H2+ SoC and a 
> > SDIO Wi-Fi chip by Allwinner (XR819). 
> > 
> > Add a device tree file for it. 
> > 
> > Signed-off-by: Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org> 
> > --- 
> > Changes since v2: 
> > - Merged SDIO Wi-Fi patch into it. 
> > - SDIO Wi-Fi: add a ethernet1 alias to it, as it has no internal NVRAM. 
> > - SDIO Wi-Fi: changed pinctrl binding to generic pinconf 
> > - removed all gpio pinctrl nodes 
> > - changed h2plus to h2-plus 
> > Changes since v1: 
> > - Convert to generic pinconf bindings. 
> > - SDIO Wi-Fi: add patch. 
> > 
> > Some notes: 
> > - The uart1 and uart2 is available on the unsoldered gpio header. 
> > - The onboard USB connector has its Vbus directly connected to DCIN-5V (the 
> >   power jack) 
> > 
> >  arch/arm/boot/dts/Makefile                        |   1 + 
> >  arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts | 159 ++++++++++++++++++++++ 
> >  2 files changed, 160 insertions(+) 
> >  create mode 100644 arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts 
> > 
> > diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile 
> > index 6447abc..59f6e86 100644 
> > --- a/arch/arm/boot/dts/Makefile 
> > +++ b/arch/arm/boot/dts/Makefile 
> > @@ -844,6 +844,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \ 
> >         sun8i-a33-sinlinx-sina33.dtb \ 
> >         sun8i-a83t-allwinner-h8homlet-v2.dtb \ 
> >         sun8i-a83t-cubietruck-plus.dtb \ 
> > +       sun8i-h2-plus-orangepi-zero.dtb \ 
> >         sun8i-h3-bananapi-m2-plus.dtb \ 
> >         sun8i-h3-nanopi-neo.dtb \ 
> >         sun8i-h3-orangepi-2.dtb \ 
> > diff --git a/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts 
> > new file mode 100644 
> > index 0000000..d18807f 
> > --- /dev/null 
> > +++ b/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts 
> > @@ -0,0 +1,159 @@ 
> > +/* 
> > + * Copyright (C) 2016 Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org> 
> > + * 
> > + * Based on sun8i-h3-orangepi-one.dts, which is: 
> > + *   Copyright (C) 2016 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> 
> > + * 
> > + * This file is dual-licensed: you can use it either under the terms 
> > + * of the GPL or the X11 license, at your option. Note that this dual 
> > + * licensing only applies to this file, and not this project as a 
> > + * whole. 
> > + * 
> > + *  a) This file is free software; you can redistribute it and/or 
> > + *     modify it under the terms of the GNU General Public License as 
> > + *     published by the Free Software Foundation; either version 2 of the 
> > + *     License, or (at your option) any later version. 
> > + * 
> > + *     This file is distributed in the hope that it will be useful, 
> > + *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
> > + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
> > + *     GNU General Public License for more details. 
> > + * 
> > + * Or, alternatively, 
> > + * 
> > + *  b) Permission is hereby granted, free of charge, to any person 
> > + *     obtaining a copy of this software and associated documentation 
> > + *     files (the "Software"), to deal in the Software without 
> > + *     restriction, including without limitation the rights to use, 
> > + *     copy, modify, merge, publish, distribute, sublicense, and/or 
> > + *     sell copies of the Software, and to permit persons to whom the 
> > + *     Software is furnished to do so, subject to the following 
> > + *     conditions: 
> > + * 
> > + *     The above copyright notice and this permission notice shall be 
> > + *     included in all copies or substantial portions of the Software. 
> > + * 
> > + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
> > + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
> > + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
> > + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
> > + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
> > + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
> > + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
> > + *     OTHER DEALINGS IN THE SOFTWARE. 
> > + */ 
> > + 
> > +/dts-v1/; 
> > +#include "sun8i-h3.dtsi" 
> > +#include "sunxi-common-regulators.dtsi" 
> > + 
> > +#include <dt-bindings/gpio/gpio.h> 
> > +#include <dt-bindings/input/input.h> 
> > +#include <dt-bindings/pinctrl/sun4i-a10.h> 
> > + 
> > +/ { 
> > +       model = "Xunlong Orange Pi Zero"; 
> > +       compatible = "xunlong,orangepi-zero", "allwinner,sun8i-h2-plus"; 
> > + 
> > +       aliases { 
> > +               serial0 = &uart0; 
> > +               /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */ 
> > +               ethernet1 = &xr819; 
> > +       }; 
> > + 
> > +       chosen { 
> > +               stdout-path = "serial0:115200n8"; 
> > +       }; 
> > + 
> > +       leds { 
> > +               compatible = "gpio-leds"; 
> > + 
> > +               pwr_led { 
> > +                       label = "orangepi:green:pwr"; 
> > +                       gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; 
> > +                       default-state = "on"; 
> > +               }; 
> > + 
> > +               status_led { 
> > +                       label = "orangepi:red:status"; 
> > +                       gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>; 
> > +               }; 
> > +       }; 
> > + 
> > +       reg_vcc_wifi: reg_vcc_wifi { 
> > +               compatible = "regulator-fixed"; 
> > +               regulator-min-microvolt = <3300000>; 
> > +               regulator-max-microvolt = <3300000>; 
> > +               regulator-name = "vcc-wifi"; 
> > +               enable-active-high; 
> > +               gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>; 
> > +       }; 
> > + 
> > +       wifi_pwrseq: wifi_pwrseq { 
> > +               compatible = "mmc-pwrseq-simple"; 
> > +               reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; 
> > +       }; 
> > +}; 
> > + 
> > +&ehci1 { 
> > +       status = "okay"; 
> > +}; 
> > + 
> > +&mmc0 { 
> > +       pinctrl-names = "default"; 
> > +       pinctrl-0 = <&mmc0_pins_a>; 
> > +       vmmc-supply = <&reg_vcc3v3>; 
> > +       bus-width = <4>; 
> > +       cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ 
> > +       cd-inverted; 
> > +       status = "okay"; 
> > +}; 
> > + 
> > +&mmc1 { 
> > +       pinctrl-names = "default"; 
> > +       pinctrl-0 = <&mmc1_pins_a>; 
> > +       vmmc-supply = <&reg_vcc_wifi>; 
> > +       mmc-pwrseq = <&wifi_pwrseq>; 
> > +       bus-width = <4>; 
> > +       non-removable; 
> > +       status = "okay"; 
> > + 
> > +       /* 
> > +        * Explicitly define the sdio device, so that we can add an ethernet 
> > +        * alias for it (which e.g. makes u-boot set a mac-address). 
> > +        */ 
> > +       xr819: sdio_wifi@1 { 
> > +               reg = <1>; 
> > +       }; 
> > +}; 
> > + 
> > +&mmc1_pins_a { 
> > +       bias-pull-up; 
>
> This is already set in h3.dtsi 

Okay...

>
> > +}; 
> > + 
> > +&ohci1 { 
> > +       status = "okay"; 
> > +}; 
> > + 
> > +&uart0 { 
> > +       pinctrl-names = "default"; 
> > +       pinctrl-0 = <&uart0_pins_a>; 
> > +       status = "okay"; 
> > +}; 
> > + 
> > +&uart1 { 
> > +       pinctrl-names = "default"; 
> > +       pinctrl-0 = <&uart1_pins>; 
> > +       status = "disabled"; 
> > +}; 
> > + 
> > +&uart2 { 
> > +       pinctrl-names = "default"; 
> > +       pinctrl-0 = <&uart2_pins>; 
> > +       status = "disabled"; 
> > +}; 
> > + 
> > +&usbphy { 
> > +       /* USB VBUS is always on */ 
>
> I think this comment could use a little work. 
>
> AFAIK this board doesn't have an actual USB port. 
> It's just the D+/D- pins on the pin header, along 
> with the board-wide 5V, also on the pin header. 

There is a actual port. Additionally there are two pin pairs.

But there's also no regulator for the actual port.

>
> ChenYu 
>
> > +       status = "okay"; 
> > +}; 
> > -- 
> > 2.10.2 
> > 
> > -- 
> > You received this message because you are subscribed to the Google Groups "linux-sunxi" group. 
> > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org 
> > For more options, visit https://groups.google.com/d/optout. 
>
> -- 
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group. 
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org 
> For more options, visit https://groups.google.com/d/optout. 

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH] ARM: omap3: beagleboard-xm: dt: Add ethernet to the device tree
From: Tony Lindgren @ 2016-12-02 18:50 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Benoît Cousson
In-Reply-To: <2173679.ibqUs8Vreg@avalon>

* Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161202 10:39]:
> Hi Tony,
> 
> On Friday 02 Dec 2016 08:53:24 Tony Lindgren wrote:
> > * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161202 05:38]:
> > > On Thursday 01 Dec 2016 17:18:08 Tony Lindgren wrote:
> > >> * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161130 09:58]:
> > >>>  &usbhsehci {
> > >>>  
> > >>>  	phys = <0 &hsusb2_phy>;
> > >>> 
> > >>> +
> > >>> +	#address-cells = <1>;
> > >>> +	#size-cells = <0>;
> > >>> +
> > >>> +	usb2@2 {
> > >> 
> > >> I think this should be usb1@2 instead of usb2@2? That's because it's
> > >> at /sys/bus/usb/devices/1-2 and not at /sys/bus/usb/devices/2-2?
> > >> 
> > >> Or what's the naming standard here?
> > > 
> > > Good question. As far as I know, the node name is irrelevant, only the reg
> > > value is important. Maybe we should call it hub@2 ?
> > 
> > Yeah hub sounds good to me, Rob?
> > 
> > Sohow does the kernel know which instance it is if there
> > are multiple devices? For example, below is a patch for
> > igepv5 (not yet using "hub" naming), note how it has things
> > at 3-2 and 3-2.3. So if it also had something at 1-2 and
> > 1-2.1, how would we name them?
> 
> Every time I have to deal with USB device names I need to look the naming 
> scheme up. The explanation here might not be 100% accurate.
> 
> The first number is the bus number, which more or less identifies a host 
> controller (and its root hub). That's a dynamically allocated ID that thus 
> can't be used by DT, but given that DT USB bindings create node as children of 
> a host controller, we don't need the bus number anyway.

Oh OK so that must be some deferred probe happening here giving
me the 3-2 numbering instead of 1-2 numbering.

> The numbers following the dash identify ports on hubs. 3-2 is thus the device 
> connected on port 2 of the root hub of bus 3 (which is a hub), and 3-2.3 is 
> the device connected on port 3 of the hub connected on port 2 of the root hub 
> of bus 3.
> 
> If you had 1-2 and 1-2.1 it would mean that device on port 2 of the root hub 
> of bus 1 (1-2) is a hub that has device connected on its first port (1-2.1).

OK so 1-2 and 3-2 are both at the root hub port 2 so no issue there.

BTW, considering the various versions of u-boot, just doing
udevadm info /sys/bus/usb/devices/1-2 can be used for debugging
as if configured properly in the dts it will show the three OF_*
related lines.

Seems like the "hub" naming would be good to use though.

Thanks,

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 2/4] phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips
From: Stephen Boyd @ 2016-12-02 18:47 UTC (permalink / raw)
  To: Vivek Gautam
  Cc: kishon, robh+dt, Mark Rutland, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Srinivas Kandagatla, linux-arm-msm
In-Reply-To: <CAFp+6iGdDnTvod7g8FOMWvUv22rrDCC0LL1BWYfiAggiQd+QvA@mail.gmail.com>

On 12/01/2016 12:42 AM, Vivek Gautam wrote:
> On Tue, Nov 29, 2016 at 4:44 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
>> On 11/22, Vivek Gautam wrote:
>>> +     }
>>> +
>>> +     /*
>>> +      * we need to read only one byte here, since the required
>>> +      * parameter value fits in one nibble
>>> +      */
>>> +     val = (u8 *)nvmem_cell_read(cell, &len);
>> Shouldn't need the cast here. Also it would be nice if
>> nvmem_cell_read() didn't require a second argument if we don't
>> care for it. We should update the API to allow NULL there.
> Will remove the u8 pointer cast.
>
> Correct, it makes sense to allow the length pointer to be passed as NULL.
> We don't care about this length. Will update the nvmem API, to allow this.
>
> Also, we should add a check for 'cell' as well. This pointer can be
> NULL, and the first thing that  nvmem_cell_read does is - deference
> the pointer 'cell'

It would be pretty stupid to read a cell and pass NULL as the first
argument. I imagine things would blow up there like we want and we would
see a nice big stacktrace.

>>> +     } else {
>>> +             reset_val |= CLK_REF_SEL;
>>> +     }
>>> +
>>> +     writel_relaxed(reset_val, qphy->base + QUSB2PHY_PLL_TEST);
>>> +
>>> +     /* Make sure that above write is completed to get PLL source clock */
>>> +     wmb();
>>> +
>>> +     /* Required to get PHY PLL lock successfully */
>>> +     usleep_range(100, 110);
>>> +
>>> +     if (!(readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS) &
>>> +                                     PLL_LOCKED)) {
>>> +             dev_err(&phy->dev, "QUSB PHY PLL LOCK fails:%x\n",
>>> +                     readb_relaxed(qphy->base + QUSB2PHY_PLL_STATUS));
>> Would be pretty funny if this was locked now when the error
>> printk runs. Are there other bits in there that are helpful?
> This is the only bit that's there to check the PLL locking status.
> Should we rather poll ?
>

I'm just saying that the printk may have the "correct" status but the
check would have failed earlier making the printk confusing. Perhaps
just save the register value from the first read and print it instead of
reading it again? Polling would probably be a better design anyway?
Hopefully the status bit isn't toggling back and forth during those
100-100us though, which may be the case here and that would explain why
it's not a polling design.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 1/3] Documentation: dt: Add TI SCI clock driver
From: Rob Herring @ 2016-12-02 18:45 UTC (permalink / raw)
  To: Tero Kristo
  Cc: linux-clk, Michael Turquette, Stephen Boyd, Santosh Shilimkar,
	Nishanth Menon, linux-arm-kernel@lists.infradead.org,
	devicetree@vger.kernel.org
In-Reply-To: <8579b123-f214-22f1-0236-e5b98ab51597@ti.com>

On Fri, Dec 2, 2016 at 2:19 AM, Tero Kristo <t-kristo@ti.com> wrote:
> On 21/11/16 10:14, Tero Kristo wrote:
>>
>> On 18/11/16 19:20, Rob Herring wrote:
>>>
>>> On Mon, Oct 31, 2016 at 7:50 AM, Tero Kristo <t-kristo@ti.com> wrote:
>>>>
>>>> On 30/10/16 22:41, Rob Herring wrote:
>>>>>
>>>>>
>>>>> On Fri, Oct 21, 2016 at 03:45:59PM +0300, Tero Kristo wrote:
>>>>>>
>>>>>>
>>>>>> Add a clock implementation, TI SCI clock, that will hook to the common
>>>>>> clock framework, and allow each clock to be controlled via TI SCI
>>>>>> protocol.
>>>>>>
>>>>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>>>>> ---
>>>>>>  .../devicetree/bindings/clock/ti,sci-clk.txt       | 37
>>>>>> ++++++++++++++++++++++
>>>>>>  MAINTAINERS                                        |  1 +
>>>>>>  2 files changed, 38 insertions(+)
>>>>>>  create mode 100644
>>>>>> Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> new file mode 100644
>>>>>> index 0000000..bfc3ca4
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/clock/ti,sci-clk.txt
>>>>>> @@ -0,0 +1,37 @@
>>>>>> +Texas Instruments TI-SCI Clocks
>>>>>> +===============================
>>>>>> +
>>>>>> +All clocks on Texas Instruments' SoCs that contain a System
>>>>>> Controller,
>>>>>> +are only controlled by this entity. Communication between a host
>>>>>> processor
>>>>>> +running an OS and the System Controller happens through a protocol
>>>>>> known
>>>>>> +as TI-SCI[1]. This clock implementation plugs into the common clock
>>>>>> +framework and makes use of the TI-SCI protocol on clock API requests.
>>>>>> +
>>>>>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>>>>>> +
>>>>>> +Required properties:
>>>>>> +-------------------
>>>>>> +- compatible: Must be "ti,k2g-sci-clk"
>>>>>> +- #clock-cells: Shall be 2.
>>>>>> +  In clock consumers, this cell represents the device ID and clock ID
>>>>>> +  exposed by the PM firmware. The assignments can be found in the
>>>>>> header
>>>>>> +  files <dt-bindings/genpd/<soc>.h> (which covers the device IDs) and
>>>>>> +  <dt-bindings/clock/<soc>.h> (which covers the clock IDs), where
>>>>>> <soc>
>>>>>> +  is the SoC involved, for example 'k2g'.
>>>>>> +
>>>>>> +Examples:
>>>>>> +--------
>>>>>> +
>>>>>> +pmmc: pmmc {
>>>>>> +       compatible = "ti,k2g-sci";
>>>>>> +
>>>>>> +       k2g_clks: k2g_clks {
>>>>>
>>>>>
>>>>>
>>>>> Use "clocks" for node name instead.
>>>>>
>>>>>> +               compatible = "ti,k2g-sci-clk";
>>>>>
>>>>>
>>>>>
>>>>> I'm starting to think all these child nodes for SCI are pointless. Is
>>>>> there any reason why the parent node can't be the clock provider (along
>>>>> with all the other providers it acks as)?
>>>>
>>>>
>>>>
>>>> I believe the only reason to keep them separate is to have kernel
>>>> side of
>>>> things modular. If we have separate nodes, the drivers can be probed
>>>> separately.
>>>>
>>>> If not, we need to build one huge blob with all the features in it,
>>>> so the
>>>> main driver can probe everything in one go, with annoying back-and-forth
>>>> callbacks in place (assuming we still want to keep stuff somehow
>>>> modular.)
>>>
>>>
>>> Since when is DT the only way to create a device? The main driver can
>>> create devices for all the sub-functions like clocks. This is the same
>>> as MFDs which have been done both ways.
>>
>>
>> Yes obviously this can be done, my main point was that it will require
>> building some sort of infra within the driver to handle this. With
>> separate nodes, none of this is going to be needed. Also, we will lose
>> any kind of configurability via DT if we don't have separate nodes; now
>> we can select the available clocks / genpds via the compatible string of
>> the clocks/genpd nodes themselves (this isn't clearly evident as of now
>> as we only support a grand total of one device, which is k2g-evm.)
>> Otherwise we need to probe against the main node and add a separate
>> compatible string for every device, and carry this information to the
>> sibling devices also somehow. It is just so much simpler if we can just
>> keep separate nodes for them.
>>
>> Also, plenty of things are doing this kind of stuff already in
>> DT/kernel, having a parent node in place and sub-functions added
>> separately for ease of use, with apparently no visible point for having
>> the nodes within the DT.
>
>
> Rob, any response on this one? I see you have acked the reset part of the
> bindings which is doing pretty much the same thing as the clock part is
> doing here, namely adding child node under the main SCI node. Is it okay to
> do this same for other parts of the TI SCI?

Yes. It would be silly to allow for one and not others...

Rob

^ permalink raw reply

* Re: [PATCH] ARM: omap3: beagleboard-xm: dt: Add ethernet to the device tree
From: Laurent Pinchart @ 2016-12-02 18:39 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Benoît Cousson
In-Reply-To: <20161202165323.GC4705-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>

Hi Tony,

On Friday 02 Dec 2016 08:53:24 Tony Lindgren wrote:
> * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161202 05:38]:
> > On Thursday 01 Dec 2016 17:18:08 Tony Lindgren wrote:
> >> * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161130 09:58]:
> >>>  &usbhsehci {
> >>>  
> >>>  	phys = <0 &hsusb2_phy>;
> >>> 
> >>> +
> >>> +	#address-cells = <1>;
> >>> +	#size-cells = <0>;
> >>> +
> >>> +	usb2@2 {
> >> 
> >> I think this should be usb1@2 instead of usb2@2? That's because it's
> >> at /sys/bus/usb/devices/1-2 and not at /sys/bus/usb/devices/2-2?
> >> 
> >> Or what's the naming standard here?
> > 
> > Good question. As far as I know, the node name is irrelevant, only the reg
> > value is important. Maybe we should call it hub@2 ?
> 
> Yeah hub sounds good to me, Rob?
> 
> Sohow does the kernel know which instance it is if there
> are multiple devices? For example, below is a patch for
> igepv5 (not yet using "hub" naming), note how it has things
> at 3-2 and 3-2.3. So if it also had something at 1-2 and
> 1-2.1, how would we name them?

Every time I have to deal with USB device names I need to look the naming 
scheme up. The explanation here might not be 100% accurate.

The first number is the bus number, which more or less identifies a host 
controller (and its root hub). That's a dynamically allocated ID that thus 
can't be used by DT, but given that DT USB bindings create node as children of 
a host controller, we don't need the bus number anyway.

The numbers following the dash identify ports on hubs. 3-2 is thus the device 
connected on port 2 of the root hub of bus 3 (which is a hub), and 3-2.3 is 
the device connected on port 3 of the hub connected on port 2 of the root hub 
of bus 3.

If you had 1-2 and 1-2.1 it would mean that device on port 2 of the root hub 
of bus 1 (1-2) is a hub that has device connected on its first port (1-2.1).

> 8< ------------------------
> 
> From tony Mon Sep 17 00:00:00 2001
> From: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
> Date: Thu, 1 Dec 2016 17:04:50 -0800
> Subject: [PATCH] ARM: dts: omap5-igep0050: Allow bootloader to configure
>  USB Ethernet MAC
> 
> This is slightly different wiring compared to omap5-uevm or pandaboard:
> 
> /sys/bus/usb/devices/3-2	hub
> /sys/bus/usb/devices/3-2.3	7500
> 
> Signed-off-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
> ---
>  arch/arm/boot/dts/omap5-igep0050.dts | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/omap5-igep0050.dts
> b/arch/arm/boot/dts/omap5-igep0050.dts ---
> a/arch/arm/boot/dts/omap5-igep0050.dts
> +++ b/arch/arm/boot/dts/omap5-igep0050.dts
> @@ -19,6 +19,10 @@
>  		reg = <0x0 0x80000000 0 0x7f000000>;	/* 2032 MB */
>  	};
> 
> +	aliases {
> +		ethernet = &ethernet;
> +	};
> +
>  	gpio_keys {
>  		compatible = "gpio-keys";
>  		pinctrl-0 = <&power_button_pin>;
> @@ -116,3 +120,20 @@
>  		OMAP5_IOPAD(0x1ca, PIN_OUTPUT | MUX_MODE6)	/* 
perslimbus2_clock.gpio5_145
> */
>  	>;
> 
>  };
> +
> +&usbhsehci {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	usb3@2 {
> +		compatible = "usb424,3503";
> +		reg = <2>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		ethernet: usbether@3 {
> +			compatible = "usb424,7500";
> +			reg = <3>;
> +		};
> +	};
> +};

-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 3/8] rtc: add STM32 RTC driver
From: Mathieu Poirier @ 2016-12-02 18:05 UTC (permalink / raw)
  To: Amelie Delaunay
  Cc: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	gabriel.fernandez-qxv4g6HH51o
In-Reply-To: <1480687801-19525-5-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>

On Fri, Dec 02, 2016 at 03:09:56PM +0100, Amelie Delaunay wrote:
> This patch adds support for the STM32 RTC.
> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
> ---
>  drivers/rtc/Kconfig     |  10 +
>  drivers/rtc/Makefile    |   1 +
>  drivers/rtc/rtc-stm32.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++
>  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..dd8b218 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1706,6 +1706,16 @@ 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 On-Chip RTC"
> +	depends on ARCH_STM32
> +	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..9e710ff
> --- /dev/null
> +++ b/drivers/rtc/rtc-stm32.c
> @@ -0,0 +1,777 @@
> +/*
> + * Copyright (C) Amelie Delaunay 2015
> + * Author:  Amelie Delaunay <adelaunay.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_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(11, 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 *pclk;
> +	struct clk *ck_rtc;
> +	unsigned int clksrc;
> +	spinlock_t lock; /* Protects registers accesses */
> +	int irq_alarm;
> +	struct regmap *pwrcr;
> +};

One more thing... What did you want to do with pclk, clksrc and pwrcr?  They
aren't used in the driver.  If this is for future enhancement I suggest you
introduce those when you submit the patches.

> +
> +static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
> +					   unsigned int offset)
> +{
> +	return readl_relaxed(rtc->base + offset);
> +}
> +
> +static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
> +				    unsigned int offset, unsigned int value)
> +{
> +	writel_relaxed(value, rtc->base + offset);
> +}
> +
> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
> +{
> +//	if (dbp)
> +//		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
> +
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
> +}
> +
> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
> +{
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
> +
> +//	if (dbp)
> +//		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +}
> +
> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	if (!(isr & STM32_RTC_ISR_INITF)) {
> +		isr |= STM32_RTC_ISR_INIT;
> +		stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +		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 = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_INIT;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +}
> +
> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr;
> +
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_RSF;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	/* Wait the registers to be synchronised */
> +	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 long irqflags, events = 0;
> +	unsigned int isr, cr;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> +	if ((isr & STM32_RTC_ISR_ALRAF) &&
> +	    (cr & STM32_RTC_CR_ALRAIE)) {
> +		/* Alarm A flag - Alarm interrupt */
> +		events |= RTC_IRQF | RTC_AF;
> +		isr &= ~STM32_RTC_ISR_ALRAF;
> +	}
> +
> +	/* Clear event irqflags, otherwise new events won't be received */
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	if (events) {
> +		dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
> +
> +		/* Pass event to the kernel */
> +		rtc_update_irq(rtc->rtc_dev, 1, events);
> +		return IRQ_HANDLED;
> +	} else {
> +		return IRQ_NONE;
> +	}
> +}
> +
> +/* 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 = stm32_rtc_readl(rtc, STM32_RTC_TR);
> +	dr = stm32_rtc_readl(rtc, 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;
> +	}
> +
> +	stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
> +	stm32_rtc_writel(rtc, STM32_RTC_DR, 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 = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
> +		/*
> +		 * Date/day don't care 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 care 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 care 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 care 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;
> +
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	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);
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	/* Clear event irqflags, otherwise new events won't be received */
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +	isr &= ~STM32_RTC_ISR_ALRAF;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return 0;
> +}
> +
> +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);
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	/* Disable Alarm */
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAE;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	/* Poll Alarm write flag to be sure that Alarm update is allowed */
> +	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> +						isr,
> +						(isr & STM32_RTC_ISR_ALRAWF),
> +						10, 100);
> +
> +	if (ret) {
> +		dev_err(dev, "Alarm update not allowed\n");
> +		goto end;
> +	}
> +
> +	alrmar = 0;
> +
> +	if (tm->tm_mday < 0 && tm->tm_wday < 0) {
> +		/*
> +		 * Date/day don't care in Alarm comparison so alarm triggers
> +		 * every day
> +		 */
> +		alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
> +	} else {
> +		if (tm->tm_mday > 0) {
> +			/* Date is selected (ignoring wday) */
> +			alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
> +				  STM32_RTC_ALRMXR_DATE;
> +		} else {
> +			/* Day of week is selected */
> +			int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
> +
> +			alrmar |= STM32_RTC_ALRMXR_WDSEL;
> +			alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
> +				  STM32_RTC_ALRMXR_WDAY;
> +		}
> +	}
> +
> +	if (tm->tm_hour < 0) {
> +		/* Hours don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
> +	} else {
> +		/* 24-hour format */
> +		alrmar &= ~STM32_RTC_ALRMXR_PM;
> +		alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
> +			  STM32_RTC_ALRMXR_HOUR;
> +	}
> +
> +	if (tm->tm_min < 0) {
> +		/* Minutes don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
> +	} else {
> +		alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
> +			  STM32_RTC_ALRMXR_MIN;
> +	}
> +
> +	if (tm->tm_sec < 0) {
> +		/* Seconds don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
> +	} else {
> +		alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
> +			  STM32_RTC_ALRMXR_SEC;
> +	}
> +
> +	/* Write to Alarm register */
> +	stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, 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;
> +	stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
> +	stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +
> +	/* Force 24h time format */
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_FMT;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	stm32_rtc_exit_init_mode(rtc);
> +
> +	ret = stm32_rtc_wait_sync(rtc);
> +
> +	if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
> +		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
> +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, "ck_rtc");
> +	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;
> +
> +	if (dbp)
> +		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
> +
> +	ret = stm32_rtc_init(pdev, rtc);
> +	if (ret)
> +		goto err;
> +
> +	rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
> +	if (rtc->irq_alarm <= 0) {
> +		dev_err(&pdev->dev, "no alarm irq\n");
> +		ret = -ENOENT;
> +		goto err;
> +	}
> +
> +	platform_set_drvdata(pdev, rtc);
> +
> +	device_init_wakeup(&pdev->dev, true);
> +
> +	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_irq(&pdev->dev, rtc->irq_alarm,
> +			       stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
> +			       dev_name(&rtc->rtc_dev->dev), rtc);
> +	if (ret) {
> +		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
> +			rtc->irq_alarm);
> +		goto err;
> +	}
> +
> +	return 0;
> +err:
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	if (dbp)
> +		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 = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAIE;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	/* Enable backup domain write protection */
> +	if (dbp)
> +		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-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.9.1
> 

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH 4/6] net: ethernet: ti: cpts: add ptp pps support
From: Grygorii Strashko @ 2016-12-02 17:58 UTC (permalink / raw)
  To: Richard Cochran
  Cc: Murali Karicheri, Wingman Kwok, David S. Miller, netdev,
	Mugunthan V N, Sekhar Nori, linux-kernel, linux-omap, Rob Herring,
	devicetree
In-Reply-To: <20161202095848.GA14586@localhost.localdomain>

Hi Richard,

On 12/02/2016 03:58 AM, Richard Cochran wrote:
> On Wed, Nov 30, 2016 at 11:17:38PM +0100, Richard Cochran wrote:
>> On Wed, Nov 30, 2016 at 02:43:57PM -0600, Grygorii Strashko wrote:
>>> Sry, but this is questionable - code for pps comes from TI internal
>>> branches (SDK releases) where it survived for a pretty long time.
> 
> Actually, there is a way to get an accurate PPS from the am335x.  See
> this recent thread:
> 
>    https://www.mail-archive.com/linuxptp-devel@lists.sourceforge.net/msg01726.html
> 
> That is the way to go, and so, please drop this present patch.
> 

thanks for the links - it sounds very interesting.

As I understood, people trying to enable PPS on am335 device with the
goal to have PPS signal generated on some SoC pin and therefore they use DMtimer.
Also, as i understood, the Timer Load Register (TLDR) is corrected once
a second at each HW_TS_PUSH - as result, if freq was corrected during current sec
there will be some HW_TS_PUSH generation jitter any way.

Above solution is a bit complex for keystone 2 SoCs, as CPTS itself on these SoCs has
output pin (ts_comp) which can be used for PPS signal generation. So, I think,
similar results can be achieved by removing PPS correction code from cpts_ptp_adjfreq()
and updating CPTS_TS_LOAD_VAL once a sec in cpts_overflow_check().

or I missed smth?

-- 
regards,
-grygorii

^ permalink raw reply

* Re: [PATCH 3/8] rtc: add STM32 RTC driver
From: Mathieu Poirier @ 2016-12-02 17:56 UTC (permalink / raw)
  To: Amelie Delaunay
  Cc: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	gabriel.fernandez-qxv4g6HH51o
In-Reply-To: <1480687801-19525-5-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>

On Fri, Dec 02, 2016 at 03:09:56PM +0100, Amelie Delaunay wrote:
> This patch adds support for the STM32 RTC.

Hello Amelie,

> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
> ---
>  drivers/rtc/Kconfig     |  10 +
>  drivers/rtc/Makefile    |   1 +
>  drivers/rtc/rtc-stm32.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++
>  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..dd8b218 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1706,6 +1706,16 @@ 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 On-Chip RTC"
> +	depends on ARCH_STM32
> +	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..9e710ff
> --- /dev/null
> +++ b/drivers/rtc/rtc-stm32.c
> @@ -0,0 +1,777 @@
> +/*
> + * Copyright (C) Amelie Delaunay 2015
> + * Author:  Amelie Delaunay <adelaunay.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_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(11, 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 *pclk;
> +	struct clk *ck_rtc;
> +	unsigned int clksrc;
> +	spinlock_t lock; /* Protects registers accesses */
> +	int irq_alarm;
> +	struct regmap *pwrcr;
> +};
> +
> +static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
> +					   unsigned int offset)
> +{
> +	return readl_relaxed(rtc->base + offset);
> +}
> +
> +static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
> +				    unsigned int offset, unsigned int value)
> +{
> +	writel_relaxed(value, rtc->base + offset);
> +}

I'm not sure wrapping the readl/writel_relaxed function does anything special
other than simply redirecting the reader to another section of the code.

> +
> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
> +{
> +//	if (dbp)
> +//		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);

Did checkpatch let you get away with this?  What did you intend to do here? 

> +
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
> +}
> +
> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
> +{
> +	stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
> +
> +//	if (dbp)
> +//		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +}
> +
> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	if (!(isr & STM32_RTC_ISR_INITF)) {
> +		isr |= STM32_RTC_ISR_INIT;
> +		stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +		return readl_relaxed_poll_timeout_atomic(
> +					rtc->base + STM32_RTC_ISR,
> +					isr, (isr & STM32_RTC_ISR_INITF),
> +					10, 100000);

When using hard coded numerics please add comments that explains the reason
behind the selected values.

> +	}
> +
> +	return 0;
> +}
> +
> +static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_INIT;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +}
> +
> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr;
> +
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_RSF;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	/* Wait the registers to be synchronised */
> +	return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> +						 isr,
> +						 (isr & STM32_RTC_ISR_RSF),
> +						 10, 100000);

Shouldn't the break condition be !((isr & STM32_RTC_ISR_RSF) ?  If not this
probably deserve a better comment.

> +}
> +
> +static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
> +{
> +	struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
> +	unsigned long irqflags, events = 0;
> +	unsigned int isr, cr;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +
> +	if ((isr & STM32_RTC_ISR_ALRAF) &&
> +	    (cr & STM32_RTC_CR_ALRAIE)) {
> +		/* Alarm A flag - Alarm interrupt */
> +		events |= RTC_IRQF | RTC_AF;
> +		isr &= ~STM32_RTC_ISR_ALRAF;
> +	}
> +
> +	/* Clear event irqflags, otherwise new events won't be received */
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	if (events) {
> +		dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
> +
> +		/* Pass event to the kernel */
> +		rtc_update_irq(rtc->rtc_dev, 1, events);
> +		return IRQ_HANDLED;
> +	} else {
> +		return IRQ_NONE;
> +	}
> +}
> +
> +/* 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 = stm32_rtc_readl(rtc, STM32_RTC_TR);
> +	dr = stm32_rtc_readl(rtc, 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;
> +	}
> +
> +	stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
> +	stm32_rtc_writel(rtc, STM32_RTC_DR, 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 = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
> +		/*
> +		 * Date/day don't care 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 care 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 care 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 care 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;
> +
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);

Is the STM32_RTC_CR garanteed to be valid, i.e updated atomically?  If not this
should probably be below the spinlock. 

> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	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);
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	/* Clear event irqflags, otherwise new events won't be received */
> +	isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
> +	isr &= ~STM32_RTC_ISR_ALRAF;
> +	stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
> +
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return 0;
> +}
> +
> +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);
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	/* Disable Alarm */
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAE;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	/* Poll Alarm write flag to be sure that Alarm update is allowed */
> +	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> +						isr,
> +						(isr & STM32_RTC_ISR_ALRAWF),
> +						10, 100);
> +
> +	if (ret) {
> +		dev_err(dev, "Alarm update not allowed\n");
> +		goto end;
> +	}
> +
> +	alrmar = 0;
> +
> +	if (tm->tm_mday < 0 && tm->tm_wday < 0) {
> +		/*
> +		 * Date/day don't care in Alarm comparison so alarm triggers
> +		 * every day
> +		 */
> +		alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
> +	} else {
> +		if (tm->tm_mday > 0) {
> +			/* Date is selected (ignoring wday) */
> +			alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
> +				  STM32_RTC_ALRMXR_DATE;
> +		} else {
> +			/* Day of week is selected */
> +			int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
> +
> +			alrmar |= STM32_RTC_ALRMXR_WDSEL;
> +			alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
> +				  STM32_RTC_ALRMXR_WDAY;
> +		}
> +	}
> +
> +	if (tm->tm_hour < 0) {
> +		/* Hours don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
> +	} else {
> +		/* 24-hour format */
> +		alrmar &= ~STM32_RTC_ALRMXR_PM;
> +		alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
> +			  STM32_RTC_ALRMXR_HOUR;
> +	}
> +
> +	if (tm->tm_min < 0) {
> +		/* Minutes don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
> +	} else {
> +		alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
> +			  STM32_RTC_ALRMXR_MIN;
> +	}
> +
> +	if (tm->tm_sec < 0) {
> +		/* Seconds don't care in Alarm comparison */
> +		alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
> +	} else {
> +		alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
> +			  STM32_RTC_ALRMXR_SEC;
> +	}
> +
> +	/* Write to Alarm register */
> +	stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, 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;
> +	stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
> +	stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
> +
> +	/* Force 24h time format */
> +	cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_FMT;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +
> +	stm32_rtc_exit_init_mode(rtc);
> +
> +	ret = stm32_rtc_wait_sync(rtc);
> +
> +	if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
> +		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
> +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);

The value of 'res' should be checked before using it.

> +	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, "ck_rtc");
> +	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;
> +
> +	if (dbp)
> +		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);

The code above exits if there is a problem with the dbp, there is no point in
checking again.

> +
> +	ret = stm32_rtc_init(pdev, rtc);
> +	if (ret)
> +		goto err;
> +
> +	rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
> +	if (rtc->irq_alarm <= 0) {
> +		dev_err(&pdev->dev, "no alarm irq\n");
> +		ret = -ENOENT;
> +		goto err;
> +	}
> +
> +	platform_set_drvdata(pdev, rtc);
> +
> +	device_init_wakeup(&pdev->dev, true);

What happens if device_init_wakeup() returns an error?

> +
> +	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_irq(&pdev->dev, rtc->irq_alarm,
> +			       stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
> +			       dev_name(&rtc->rtc_dev->dev), rtc);
> +	if (ret) {
> +		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
> +			rtc->irq_alarm);
> +		goto err;
> +	}
> +
> +	return 0;
> +err:
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	if (dbp)
> +		regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);

Same comment as above.

> +
> +	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 = stm32_rtc_readl(rtc, STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAIE;
> +	stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	/* Enable backup domain write protection */
> +	if (dbp)
> +		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-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 1.9.1
> 

-- 
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
--- 
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH] MIPS: NI 169445 board support
From: Nathan Sullivan @ 2016-12-02 17:30 UTC (permalink / raw)
  To: Zubair Lutfullah Kakakhel
  Cc: ralf, mark.rutland, robh+dt, linux-mips, devicetree, linux-kernel
In-Reply-To: <04fd3008-14b1-b5e1-1895-093f0076644d@imgtec.com>

On Fri, Dec 02, 2016 at 04:21:59PM +0000, Zubair Lutfullah Kakakhel wrote:
> Hi,
> 
> On 12/02/2016 03:42 PM, Nathan Sullivan wrote:
> >Support the National Instruments 169445 board.
> 
> Interesting patch.
> 
> But do you happen to have a link to a description of the board?
> I couldn't find anything with a quick search.
> Perhaps the public name is something else?
> 
> Thanks,
> ZubairLK

This patch is for a pre-release board we have not made public yet.  It's a
straightforward MIPS system that will be used for networking, and we'd like to
get Linux support in place ahead of release.

Thanks,
Nathan

^ permalink raw reply

* Re: [PATCH] ARM: omap3: beagleboard-xm: dt: Add ethernet to the device tree
From: Tony Lindgren @ 2016-12-02 16:53 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Benoît Cousson
In-Reply-To: <4245212.aFfvVGINdT@avalon>

* Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161202 05:38]:
> Hi Tony,
> 
> On Thursday 01 Dec 2016 17:18:08 Tony Lindgren wrote:
> > * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161130 09:58]:
> > >  &usbhsehci {
> > >  
> > >  	phys = <0 &hsusb2_phy>;
> > > 
> > > +
> > > +	#address-cells = <1>;
> > > +	#size-cells = <0>;
> > > +
> > > +	usb2@2 {
> > 
> > I think this should be usb1@2 instead of usb2@2? That's because it's
> > at /sys/bus/usb/devices/1-2 and not at /sys/bus/usb/devices/2-2?
> > 
> > Or what's the naming standard here?
> 
> Good question. As far as I know, the node name is irrelevant, only the reg 
> value is important. Maybe we should call it hub@2 ?

Yeah hub sounds good to me, Rob?

Sohow does the kernel know which instance it is if there
are multiple devices? For example, below is a patch for
igepv5 (not yet using "hub" naming), note how it has things
at 3-2 and 3-2.3. So if it also had something at 1-2 and
1-2.1, how would we name them?

Regards,

Tony

8< ------------------------

>From tony Mon Sep 17 00:00:00 2001
From: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
Date: Thu, 1 Dec 2016 17:04:50 -0800
Subject: [PATCH] ARM: dts: omap5-igep0050: Allow bootloader to configure
 USB Ethernet MAC

This is slightly different wiring compared to omap5-uevm or pandaboard:

/sys/bus/usb/devices/3-2	hub
/sys/bus/usb/devices/3-2.3	7500

Signed-off-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/boot/dts/omap5-igep0050.dts | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/omap5-igep0050.dts b/arch/arm/boot/dts/omap5-igep0050.dts
--- a/arch/arm/boot/dts/omap5-igep0050.dts
+++ b/arch/arm/boot/dts/omap5-igep0050.dts
@@ -19,6 +19,10 @@
 		reg = <0x0 0x80000000 0 0x7f000000>;	/* 2032 MB */
 	};
 
+	aliases {
+		ethernet = &ethernet;
+	};
+
 	gpio_keys {
 		compatible = "gpio-keys";
 		pinctrl-0 = <&power_button_pin>;
@@ -116,3 +120,20 @@
 		OMAP5_IOPAD(0x1ca, PIN_OUTPUT | MUX_MODE6)	/* perslimbus2_clock.gpio5_145 */
 	>;
 };
+
+&usbhsehci {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	usb3@2 {
+		compatible = "usb424,3503";
+		reg = <2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethernet: usbether@3 {
+			compatible = "usb424,7500";
+			reg = <3>;
+		};
+	};
+};
-- 
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/5] pinctrl: core: Use delayed work for hogs
From: Tony Lindgren @ 2016-12-02 16:44 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
	Nishanth Menon, linux-gpio@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Linux-OMAP
In-Reply-To: <CACRpkdZUtqEUQbz7YqtLnYWdOmW4g4q4ikRuqfCwzf5kMR5JDg@mail.gmail.com>

* Linus Walleij <linus.walleij@linaro.org> [161202 05:08]:
> On Tue, Nov 15, 2016 at 6:08 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Tony Lindgren <tony@atomide.com> [161115 07:42]:
> >> * Linus Walleij <linus.walleij@linaro.org> [161114 22:53]:
> >> > On Tue, Nov 15, 2016 at 1:47 AM, Tony Lindgren <tony@atomide.com> wrote:
> >> >
> >> > > 8< --------------------------------
> >> > > From tony Mon Sep 17 00:00:00 2001
> >> > > From: Tony Lindgren <tony@atomide.com>
> >> > > Date: Tue, 25 Oct 2016 08:33:35 -0700
> >> > > Subject: [PATCH] pinctrl: core: Use delayed work for hogs
> >> > >
> >> > > Having the pin control framework call pin controller functions
> >> > > before it's probe has finished is not nice as the pin controller
> >> > > device driver does not yet have struct pinctrl_dev handle.
> >> > >
> >> > > Let's fix this issue by adding deferred work for late init. This is
> >> > > needed to be able to add pinctrl generic helper functions that expect
> >> > > to know struct pinctrl_dev handle. Note that we now need to call
> >> > > create_pinctrl() directly as we don't want to add the pin controller
> >> > > to the list of controllers until the hogs are claimed. We also need
> >> > > to pass the pinctrl_dev to the device tree parser functions as they
> >> > > otherwise won't find the right controller at this point.
> >> > >
> >> > > Signed-off-by: Tony Lindgren <tony@atomide.com>
> >> >
> >> > This looks a lot better!
> >> >
> >> > So if I understand correctly, we can guarantee that the delayed
> >> > work will not execute until the device driver probe() has finished,
> >> > and it *will* execute immediately after that?
> >> >
> >> > So:
> >> > - Device driver probes
> >> > - Delayed work is called
> >> > - Next initcall
> >> >
> >> > I'm not 100% familiar with how delayed work works... :/
> >>
> >> Yeah well the delayed work gets scheduled for next jiffy but may
> >> be pre-empted as it runs in process context.
> >>
> >> So in the worst case it could that we still may need to fix few
> >> drivers to support -EPROBE_DEFER. I wonder if we should check for
> >> hogs in probe already and only defer if hogs are defined?
> >
> > Below is a version using delayed_work only if pinctrl_dt_has_hogs().
> >
> > Not sure if testing only for pinctrl-0 is enough there though?
> 
> Sorry for the lack of attention to this patch set on my part. :(
> 
> Do you think you could resend these last 5 patches after the
> release of v4.10-rc1 so we merge it early for the next cycle
> and people get a chance to test and see if it works well for
> everyone?

Yeah no problem, too late to do anything with them right now :)

> I'm worried about adding it to the tree this late in the kernel
> cycle...

Yup me too.

> However I like the look of the series overall a lot.

OK good to hear.

Tony

^ 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