linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/1] Motorola CPCAP PMIC RTC
@ 2017-02-20  7:35 Sebastian Reichel
  2017-02-20  7:35 ` [PATCH 1/1] rtc: cpcap: new rtc driver Sebastian Reichel
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-20  7:35 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: rtc-linux, linux-kernel

Hi,

Here is a driver for the RTC found inside of the
Motorola Droid 4 based on linux-next 2017021.
I tried to set & get the time using hwclock and
used ./tools/testing/selftests/timers/rtctest.c:

$ ./rtctest 

			RTC Driver Test Example.

Counting 5 update (1/sec) interrupts from reading /dev/rtc0: 1 2 3 4 5
Again, from using select(2) on /dev/rtc: 1 2 3 4 5

Current RTC date/time is 20-2-2017, 07:11:22.
Alarm time now set to 07:11:27.
Waiting 5 seconds for alarm... okay. Alarm rang.

Periodic IRQ rate is 1Hz.
Counting 20 interrupts at:
2Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
4Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
8Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
16Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
32Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
64Hz:	 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

			 *** Test complete ***

I did not include a patch for omap4-droid4-xt894.dts,
since the CPCAP DT entry has not yet been added. The
following DT snippet can be used for testing on droid4:

&cpcap {
	cpcap_rtc: rtc {
		compatible = "motorola,cpcap-rtc";

		interrupt-parent = <&cpcap>;
		interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
	};
};

-- Sebastian

Sebastian Reichel (1):
  rtc: cpcap: new rtc driver

 .../devicetree/bindings/rtc/cpcap-rtc.txt          |  13 +
 drivers/rtc/Kconfig                                |   7 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-cpcap.c                            | 318 +++++++++++++++++++++
 4 files changed, 339 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
 create mode 100644 drivers/rtc/rtc-cpcap.c

-- 
2.11.0

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

* [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20  7:35 [PATCH 0/1] Motorola CPCAP PMIC RTC Sebastian Reichel
@ 2017-02-20  7:35 ` Sebastian Reichel
  2017-02-20 16:31   ` Tony Lindgren
  2017-02-21  6:16 ` [PATCHv2] " Sebastian Reichel
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-20  7:35 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: rtc-linux, linux-kernel

This driver supports the Motorola CPCAP PMIC found on
some of Motorola's mobile phones, such as the Droid 4.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 .../devicetree/bindings/rtc/cpcap-rtc.txt          |  13 +
 drivers/rtc/Kconfig                                |   7 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-cpcap.c                            | 318 +++++++++++++++++++++
 4 files changed, 339 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
 create mode 100644 drivers/rtc/rtc-cpcap.c

diff --git a/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
new file mode 100644
index 000000000000..2709c32baf2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
@@ -0,0 +1,13 @@
+Motorola CPCAP PMIC RTC
+------------------------------------
+
+Requires node properties:
+- compatible: should contain "motorola,cpcap-rtc"
+- interrupts: An interrupt specifier for alarm and 1 Hz irq
+
+Example:
+
+cpcap_rtc: rtc {
+	compatible = "motorola,cpcap-rtc";
+	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ee1b0e9dde79..050bec749fae 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32
 	   This driver can also be built as a module, if so, the module
 	   will be called "rtc-stm32".
 
+config RTC_DRV_CPCAP
+	depends on MFD_CPCAP
+	tristate "Motorola CPCAP RTC"
+	help
+	   Say y here for CPCAP rtc found on some Motorola phones
+	   and tablets such as Droid 4.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f07297b1460a..13857d2fce09 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K)	+= rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_CPCAP)	+= rtc-cpcap.o
 obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o
 obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
new file mode 100644
index 000000000000..815beca843ce
--- /dev/null
+++ b/drivers/rtc/rtc-cpcap.c
@@ -0,0 +1,318 @@
+/*
+ * Motorola CPCAP PMIC RTC driver
+ *
+ * Based on cpcap-regulator.c from Motorola Linux kernel tree
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * Rewritten for mainline kernel
+ *  - use DT
+ *  - use regmap
+ *  - use standard interrupt framework
+ *  - use managed device resources
+ *  - remove custom "secure clock daemon" helpers
+ *
+ * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#define SECS_PER_DAY 86400
+#define DAY_MASK  0x7FFF
+#define TOD1_MASK 0x00FF
+#define TOD2_MASK 0x01FF
+
+struct cpcap_time {
+	int day;
+	int tod1;
+	int tod2;
+};
+
+struct cpcap_rtc {
+	struct regmap *regmap;
+	struct rtc_device *rtc_dev;
+	u16 vendor;
+	int alarm_irq;
+	bool alarm_enabled;
+	int update_irq;
+	bool update_enabled;
+};
+
+static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
+{
+	unsigned long int tod;
+	unsigned long int time;
+
+	tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
+	time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
+
+	rtc_time_to_tm(time, rtc);
+}
+
+static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
+{
+	unsigned long time;
+
+	rtc_tm_to_time(rtc, &time);
+
+	cpcap->day = time / SECS_PER_DAY;
+	time %= SECS_PER_DAY;
+	cpcap->tod2 = (time >> 8) & TOD2_MASK;
+	cpcap->tod1 = time & TOD1_MASK;
+}
+
+static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct cpcap_rtc *rtc = dev_get_drvdata(dev);
+
+	if (rtc->alarm_enabled == enabled)
+		return 0;
+
+	if (enabled)
+		enable_irq(rtc->alarm_irq);
+	else
+		disable_irq(rtc->alarm_irq);
+
+	rtc->alarm_enabled = !!enabled;
+
+	return 0;
+}
+
+static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int temp_tod2;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
+
+	if (temp_tod2 > cpcap_tm.tod2)
+		ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(tm, &cpcap_tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret = 0;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, tm);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+	if (rtc->update_enabled)
+		disable_irq(rtc->update_irq);
+
+	if (rtc->vendor == CPCAP_VENDOR_ST) {
+		/* The TOD1 and TOD2 registers MUST be written in this order
+		 * for the change to properly set. */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+	} else {
+		/* Clearing the upper lower 8 bits of the TOD guarantees that
+		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
+		 * ticks (255 seconds).  During this time we can safely write
+		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
+		 * synchronized to the exact time requested upon the final write
+		 * to TOD1. */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, 0);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+	}
+
+	if (rtc->update_enabled)
+		enable_irq(rtc->update_irq);
+	if (rtc->alarm_enabled)
+		enable_irq(rtc->alarm_irq);
+
+	return ret;
+}
+
+static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	alrm->enabled = rtc->alarm_enabled;
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(&alrm->time, &cpcap_tm);
+	return rtc_valid_tm(&alrm->time);
+}
+
+static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, &alrm->time);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+
+	ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
+				 cpcap_tm.day);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
+				  cpcap_tm.tod2);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
+				  cpcap_tm.tod1);
+
+	if (!ret) {
+		enable_irq(rtc->alarm_irq);
+		rtc->alarm_enabled = true;
+	}
+
+	return ret;
+}
+
+static struct rtc_class_ops cpcap_rtc_ops = {
+	.read_time		= cpcap_rtc_read_time,
+	.set_time		= cpcap_rtc_set_time,
+	.read_alarm		= cpcap_rtc_read_alarm,
+	.set_alarm		= cpcap_rtc_set_alarm,
+	.alarm_irq_enable 	= cpcap_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static int cpcap_rtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cpcap_rtc *rtc;
+	int err;
+
+	rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!rtc->regmap)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, rtc);
+	rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
+						&cpcap_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc->rtc_dev)) {
+		kfree(rtc);
+		return PTR_ERR(rtc->rtc_dev);
+	}
+
+	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
+	if (err)
+		return err;
+
+	rtc->alarm_irq= platform_get_irq(pdev, 0);
+	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
+					cpcap_rtc_alarm_irq, IRQ_NONE,
+					"rtc_alarm", rtc);
+	if (err) {
+		dev_err(dev, "Could not request alarm irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->alarm_irq);
+
+	rtc->update_irq= platform_get_irq(pdev, 1);
+	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
+					cpcap_rtc_update_irq, IRQ_NONE,
+					"rtc_1hz", rtc);
+	if (err) {
+		dev_err(dev, "Could not request update irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->update_irq);
+
+	return 0;
+}
+
+static const struct of_device_id cpcap_rtc_of_match[] = {
+	{ .compatible = "motorola,cpcap-rtc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
+
+static struct platform_driver cpcap_rtc_driver = {
+	.probe		= cpcap_rtc_probe,
+	.driver		= {
+		.name	= "cpcap-rtc",
+		.of_match_table = cpcap_rtc_of_match,
+	},
+};
+
+module_platform_driver(cpcap_rtc_driver);
+
+MODULE_ALIAS("platform:cpcap-rtc");
+MODULE_DESCRIPTION("CPCAP RTC driver");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_LICENSE("GPL");
-- 
2.11.0

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

* Re: [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20  7:35 ` [PATCH 1/1] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-02-20 16:31   ` Tony Lindgren
  2017-02-20 16:38     ` Alexandre Belloni
  0 siblings, 1 reply; 20+ messages in thread
From: Tony Lindgren @ 2017-02-20 16:31 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Alessandro Zummo, Alexandre Belloni, rtc-linux, linux-kernel

* Sebastian Reichel <sre@kernel.org> [170219 23:37]:
> This driver supports the Motorola CPCAP PMIC found on
> some of Motorola's mobile phones, such as the Droid 4.

Hey that's cool, works for me for reading and setting date :)
Just noticed one thing, see below.

> +Requires node properties:
> +- compatible: should contain "motorola,cpcap-rtc"
> +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> +
> +Example:
> +
> +cpcap_rtc: rtc {
> +	compatible = "motorola,cpcap-rtc";
> +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> +};

I tried rtcwake -s 3, but got the following:

rtcwake: cannot open /sys/class/rtc/rtc0/device/power/wakeup:
No such file or directory
rtcwake: /dev/rtc0 not enabled for wakeup events

Then tried adding "wakeup-source" to above but I think the driver
needs something, maybe probably just PM ops?

Regards,

Tony

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

* Re: [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20 16:31   ` Tony Lindgren
@ 2017-02-20 16:38     ` Alexandre Belloni
  2017-02-20 17:21       ` Tony Lindgren
  0 siblings, 1 reply; 20+ messages in thread
From: Alexandre Belloni @ 2017-02-20 16:38 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Sebastian Reichel, Alessandro Zummo, rtc-linux, linux-kernel

On 20/02/2017 at 08:31:56 -0800, Tony Lindgren wrote:
> * Sebastian Reichel <sre@kernel.org> [170219 23:37]:
> > This driver supports the Motorola CPCAP PMIC found on
> > some of Motorola's mobile phones, such as the Droid 4.
> 
> Hey that's cool, works for me for reading and setting date :)
> Just noticed one thing, see below.
> 
> > +Requires node properties:
> > +- compatible: should contain "motorola,cpcap-rtc"
> > +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> > +
> > +Example:
> > +
> > +cpcap_rtc: rtc {
> > +	compatible = "motorola,cpcap-rtc";
> > +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> > +};
> 
> I tried rtcwake -s 3, but got the following:
> 
> rtcwake: cannot open /sys/class/rtc/rtc0/device/power/wakeup:
> No such file or directory
> rtcwake: /dev/rtc0 not enabled for wakeup events
> 
> Then tried adding "wakeup-source" to above but I think the driver
> needs something, maybe probably just PM ops?
> 

Probably device_init_wakeup(dev, 1) ?


-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

* Re: [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20 16:38     ` Alexandre Belloni
@ 2017-02-20 17:21       ` Tony Lindgren
  2017-02-20 17:27         ` Tony Lindgren
  0 siblings, 1 reply; 20+ messages in thread
From: Tony Lindgren @ 2017-02-20 17:21 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Sebastian Reichel, Alessandro Zummo, rtc-linux, linux-kernel

* Alexandre Belloni <alexandre.belloni@free-electrons.com> [170220 08:40]:
> On 20/02/2017 at 08:31:56 -0800, Tony Lindgren wrote:
> > * Sebastian Reichel <sre@kernel.org> [170219 23:37]:
> > > This driver supports the Motorola CPCAP PMIC found on
> > > some of Motorola's mobile phones, such as the Droid 4.
> > 
> > Hey that's cool, works for me for reading and setting date :)
> > Just noticed one thing, see below.
> > 
> > > +Requires node properties:
> > > +- compatible: should contain "motorola,cpcap-rtc"
> > > +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> > > +
> > > +Example:
> > > +
> > > +cpcap_rtc: rtc {
> > > +	compatible = "motorola,cpcap-rtc";
> > > +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> > > +};
> > 
> > I tried rtcwake -s 3, but got the following:
> > 
> > rtcwake: cannot open /sys/class/rtc/rtc0/device/power/wakeup:
> > No such file or directory
> > rtcwake: /dev/rtc0 not enabled for wakeup events
> > 
> > Then tried adding "wakeup-source" to above but I think the driver
> > needs something, maybe probably just PM ops?
> > 
> 
> Probably device_init_wakeup(dev, 1) ?

That gets us a bit closer but now produces:

rtcwake: write error

Regards,

Tony

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

* Re: [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20 17:21       ` Tony Lindgren
@ 2017-02-20 17:27         ` Tony Lindgren
  2017-02-20 19:35           ` Sebastian Reichel
  0 siblings, 1 reply; 20+ messages in thread
From: Tony Lindgren @ 2017-02-20 17:27 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Sebastian Reichel, Alessandro Zummo, rtc-linux, linux-kernel

* Tony Lindgren <tony@atomide.com> [170220 09:21]:
> * Alexandre Belloni <alexandre.belloni@free-electrons.com> [170220 08:40]:
> > On 20/02/2017 at 08:31:56 -0800, Tony Lindgren wrote:
> > > * Sebastian Reichel <sre@kernel.org> [170219 23:37]:
> > > > This driver supports the Motorola CPCAP PMIC found on
> > > > some of Motorola's mobile phones, such as the Droid 4.
> > > 
> > > Hey that's cool, works for me for reading and setting date :)
> > > Just noticed one thing, see below.
> > > 
> > > > +Requires node properties:
> > > > +- compatible: should contain "motorola,cpcap-rtc"
> > > > +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> > > > +
> > > > +Example:
> > > > +
> > > > +cpcap_rtc: rtc {
> > > > +	compatible = "motorola,cpcap-rtc";
> > > > +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> > > > +};
> > > 
> > > I tried rtcwake -s 3, but got the following:
> > > 
> > > rtcwake: cannot open /sys/class/rtc/rtc0/device/power/wakeup:
> > > No such file or directory
> > > rtcwake: /dev/rtc0 not enabled for wakeup events
> > > 
> > > Then tried adding "wakeup-source" to above but I think the driver
> > > needs something, maybe probably just PM ops?
> > > 
> > 
> > Probably device_init_wakeup(dev, 1) ?
> 
> That gets us a bit closer but now produces:
> 
> rtcwake: write error

Oh user error.. It needs to be done with:

# rtcwake -s 3 -m mem

And with the addition of device_init_wakeup(dev, 1) to the probe
it works for me. So Sebastian, with that change, please feel free
to add:

Tested-by: Tony Lindgren <tony@atomide.com>

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

* Re: [PATCH 1/1] rtc: cpcap: new rtc driver
  2017-02-20 17:27         ` Tony Lindgren
@ 2017-02-20 19:35           ` Sebastian Reichel
  0 siblings, 0 replies; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-20 19:35 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Alexandre Belloni, Alessandro Zummo, rtc-linux, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1924 bytes --]

Hi,

On Mon, Feb 20, 2017 at 09:27:37AM -0800, Tony Lindgren wrote:
> * Tony Lindgren <tony@atomide.com> [170220 09:21]:
> > * Alexandre Belloni <alexandre.belloni@free-electrons.com> [170220 08:40]:
> > > On 20/02/2017 at 08:31:56 -0800, Tony Lindgren wrote:
> > > > * Sebastian Reichel <sre@kernel.org> [170219 23:37]:
> > > > > This driver supports the Motorola CPCAP PMIC found on
> > > > > some of Motorola's mobile phones, such as the Droid 4.
> > > > 
> > > > Hey that's cool, works for me for reading and setting date :)
> > > > Just noticed one thing, see below.
> > > > 
> > > > > +Requires node properties:
> > > > > +- compatible: should contain "motorola,cpcap-rtc"
> > > > > +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> > > > > +
> > > > > +Example:
> > > > > +
> > > > > +cpcap_rtc: rtc {
> > > > > +	compatible = "motorola,cpcap-rtc";
> > > > > +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> > > > > +};
> > > > 
> > > > I tried rtcwake -s 3, but got the following:
> > > > 
> > > > rtcwake: cannot open /sys/class/rtc/rtc0/device/power/wakeup:
> > > > No such file or directory
> > > > rtcwake: /dev/rtc0 not enabled for wakeup events
> > > > 
> > > > Then tried adding "wakeup-source" to above but I think the driver
> > > > needs something, maybe probably just PM ops?
> > > > 
> > > 
> > > Probably device_init_wakeup(dev, 1) ?
> > 
> > That gets us a bit closer but now produces:
> > 
> > rtcwake: write error
> 
> Oh user error.. It needs to be done with:
> 
> # rtcwake -s 3 -m mem
> 
> And with the addition of device_init_wakeup(dev, 1) to the probe
> it works for me. So Sebastian, with that change, please feel free
> to add:
> 
> Tested-by: Tony Lindgren <tony@atomide.com>

Nice. I actually forgot to mention, that its missing wakeup support
for now and now its already done :) I will resend later.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCHv2] rtc: cpcap: new rtc driver
  2017-02-20  7:35 [PATCH 0/1] Motorola CPCAP PMIC RTC Sebastian Reichel
  2017-02-20  7:35 ` [PATCH 1/1] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-02-21  6:16 ` Sebastian Reichel
  2017-02-21 23:52   ` Alexandre Belloni
  2017-02-23  1:03 ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Sebastian Reichel
  2017-03-02  0:27 ` [PATCHv4 " Sebastian Reichel
  3 siblings, 1 reply; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-21  6:16 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: rtc-linux, linux-kernel

This driver supports the Motorola CPCAP PMIC found on
some of Motorola's mobile phones, such as the Droid 4.

Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes to PATCHv1:
 - added device_init_wakeup() at the end of probe
 - added Tested-by from Tony
---
 .../devicetree/bindings/rtc/cpcap-rtc.txt          |  13 +
 drivers/rtc/Kconfig                                |   7 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-cpcap.c                            | 324 +++++++++++++++++++++
 4 files changed, 345 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
 create mode 100644 drivers/rtc/rtc-cpcap.c

diff --git a/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
new file mode 100644
index 000000000000..2709c32baf2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
@@ -0,0 +1,13 @@
+Motorola CPCAP PMIC RTC
+------------------------------------
+
+Requires node properties:
+- compatible: should contain "motorola,cpcap-rtc"
+- interrupts: An interrupt specifier for alarm and 1 Hz irq
+
+Example:
+
+cpcap_rtc: rtc {
+	compatible = "motorola,cpcap-rtc";
+	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ee1b0e9dde79..050bec749fae 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32
 	   This driver can also be built as a module, if so, the module
 	   will be called "rtc-stm32".
 
+config RTC_DRV_CPCAP
+	depends on MFD_CPCAP
+	tristate "Motorola CPCAP RTC"
+	help
+	   Say y here for CPCAP rtc found on some Motorola phones
+	   and tablets such as Droid 4.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f07297b1460a..13857d2fce09 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K)	+= rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_CPCAP)	+= rtc-cpcap.o
 obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o
 obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
new file mode 100644
index 000000000000..d24c205b70e8
--- /dev/null
+++ b/drivers/rtc/rtc-cpcap.c
@@ -0,0 +1,324 @@
+/*
+ * Motorola CPCAP PMIC RTC driver
+ *
+ * Based on cpcap-regulator.c from Motorola Linux kernel tree
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * Rewritten for mainline kernel
+ *  - use DT
+ *  - use regmap
+ *  - use standard interrupt framework
+ *  - use managed device resources
+ *  - remove custom "secure clock daemon" helpers
+ *
+ * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#define SECS_PER_DAY 86400
+#define DAY_MASK  0x7FFF
+#define TOD1_MASK 0x00FF
+#define TOD2_MASK 0x01FF
+
+struct cpcap_time {
+	int day;
+	int tod1;
+	int tod2;
+};
+
+struct cpcap_rtc {
+	struct regmap *regmap;
+	struct rtc_device *rtc_dev;
+	u16 vendor;
+	int alarm_irq;
+	bool alarm_enabled;
+	int update_irq;
+	bool update_enabled;
+};
+
+static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
+{
+	unsigned long int tod;
+	unsigned long int time;
+
+	tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
+	time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
+
+	rtc_time_to_tm(time, rtc);
+}
+
+static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
+{
+	unsigned long time;
+
+	rtc_tm_to_time(rtc, &time);
+
+	cpcap->day = time / SECS_PER_DAY;
+	time %= SECS_PER_DAY;
+	cpcap->tod2 = (time >> 8) & TOD2_MASK;
+	cpcap->tod1 = time & TOD1_MASK;
+}
+
+static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct cpcap_rtc *rtc = dev_get_drvdata(dev);
+
+	if (rtc->alarm_enabled == enabled)
+		return 0;
+
+	if (enabled)
+		enable_irq(rtc->alarm_irq);
+	else
+		disable_irq(rtc->alarm_irq);
+
+	rtc->alarm_enabled = !!enabled;
+
+	return 0;
+}
+
+static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int temp_tod2;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
+
+	if (temp_tod2 > cpcap_tm.tod2)
+		ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(tm, &cpcap_tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret = 0;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, tm);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+	if (rtc->update_enabled)
+		disable_irq(rtc->update_irq);
+
+	if (rtc->vendor == CPCAP_VENDOR_ST) {
+		/* The TOD1 and TOD2 registers MUST be written in this order
+		 * for the change to properly set. */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+	} else {
+		/* Clearing the upper lower 8 bits of the TOD guarantees that
+		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
+		 * ticks (255 seconds).  During this time we can safely write
+		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
+		 * synchronized to the exact time requested upon the final write
+		 * to TOD1. */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, 0);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+	}
+
+	if (rtc->update_enabled)
+		enable_irq(rtc->update_irq);
+	if (rtc->alarm_enabled)
+		enable_irq(rtc->alarm_irq);
+
+	return ret;
+}
+
+static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	alrm->enabled = rtc->alarm_enabled;
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(&alrm->time, &cpcap_tm);
+	return rtc_valid_tm(&alrm->time);
+}
+
+static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, &alrm->time);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+
+	ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
+				 cpcap_tm.day);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
+				  cpcap_tm.tod2);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
+				  cpcap_tm.tod1);
+
+	if (!ret) {
+		enable_irq(rtc->alarm_irq);
+		rtc->alarm_enabled = true;
+	}
+
+	return ret;
+}
+
+static struct rtc_class_ops cpcap_rtc_ops = {
+	.read_time		= cpcap_rtc_read_time,
+	.set_time		= cpcap_rtc_set_time,
+	.read_alarm		= cpcap_rtc_read_alarm,
+	.set_alarm		= cpcap_rtc_set_alarm,
+	.alarm_irq_enable 	= cpcap_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static int cpcap_rtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cpcap_rtc *rtc;
+	int err;
+
+	rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!rtc->regmap)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, rtc);
+	rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
+						&cpcap_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc->rtc_dev)) {
+		kfree(rtc);
+		return PTR_ERR(rtc->rtc_dev);
+	}
+
+	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
+	if (err)
+		return err;
+
+	rtc->alarm_irq= platform_get_irq(pdev, 0);
+	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
+					cpcap_rtc_alarm_irq, IRQ_NONE,
+					"rtc_alarm", rtc);
+	if (err) {
+		dev_err(dev, "Could not request alarm irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->alarm_irq);
+
+	rtc->update_irq= platform_get_irq(pdev, 1);
+	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
+					cpcap_rtc_update_irq, IRQ_NONE,
+					"rtc_1hz", rtc);
+	if (err) {
+		dev_err(dev, "Could not request update irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->update_irq);
+
+	err = device_init_wakeup(dev, 1);
+	if (err) {
+		dev_err(dev, "wakeup initialization failed (%d)\n", err);
+		/* ignore error and continue without wakeup support */
+	}
+
+	return 0;
+}
+
+static const struct of_device_id cpcap_rtc_of_match[] = {
+	{ .compatible = "motorola,cpcap-rtc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
+
+static struct platform_driver cpcap_rtc_driver = {
+	.probe		= cpcap_rtc_probe,
+	.driver		= {
+		.name	= "cpcap-rtc",
+		.of_match_table = cpcap_rtc_of_match,
+	},
+};
+
+module_platform_driver(cpcap_rtc_driver);
+
+MODULE_ALIAS("platform:cpcap-rtc");
+MODULE_DESCRIPTION("CPCAP RTC driver");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_LICENSE("GPL");
-- 
2.11.0

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

* Re: [PATCHv2] rtc: cpcap: new rtc driver
  2017-02-21  6:16 ` [PATCHv2] " Sebastian Reichel
@ 2017-02-21 23:52   ` Alexandre Belloni
  2017-02-22  1:56     ` Sebastian Reichel
  0 siblings, 1 reply; 20+ messages in thread
From: Alexandre Belloni @ 2017-02-21 23:52 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, rtc-linux, linux-kernel

Hi,

The patch has a few checkpatch issues. Some of those should really be
fixed. Can you do that?

Else, it is mostly fine, a few comments below.

On 21/02/2017 at 07:16:50 +0100, Sebastian Reichel wrote:
> +static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct cpcap_rtc *rtc;
> +	struct cpcap_time cpcap_tm;
> +	int ret = 0;
> +
> +	rtc = dev_get_drvdata(dev);
> +
> +	rtc2cpcap_time(&cpcap_tm, tm);
> +
> +	if (rtc->alarm_enabled)
> +		disable_irq(rtc->alarm_irq);
> +	if (rtc->update_enabled)
> +		disable_irq(rtc->update_irq);
> +
> +	if (rtc->vendor == CPCAP_VENDOR_ST) {
> +		/* The TOD1 and TOD2 registers MUST be written in this order
> +		 * for the change to properly set. */

Does this mean there is a race condition?

> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> +					  TOD1_MASK, cpcap_tm.tod1);
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
> +					  TOD2_MASK, cpcap_tm.tod2);
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
> +					  DAY_MASK, cpcap_tm.day);
> +	} else {
> +		/* Clearing the upper lower 8 bits of the TOD guarantees that
> +		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
> +		 * ticks (255 seconds).  During this time we can safely write
> +		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
> +		 * synchronized to the exact time requested upon the final write
> +		 * to TOD1. */
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> +					  TOD1_MASK, 0);
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
> +					  DAY_MASK, cpcap_tm.day);
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
> +					  TOD2_MASK, cpcap_tm.tod2);
> +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> +					  TOD1_MASK, cpcap_tm.tod1);
> +	}
> +

> +	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
I think this means it depends on the mfd tree.

> +	if (err)
> +		return err;
> +
> +	rtc->alarm_irq= platform_get_irq(pdev, 0);
> +	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
> +					cpcap_rtc_alarm_irq, IRQ_NONE,
> +					"rtc_alarm", rtc);
> +	if (err) {
> +		dev_err(dev, "Could not request alarm irq: %d\n", err);
> +		return err;
> +	}
> +	disable_irq(rtc->alarm_irq);
> +
> +	rtc->update_irq= platform_get_irq(pdev, 1);
> +	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
> +					cpcap_rtc_update_irq, IRQ_NONE,
> +					"rtc_1hz", rtc);
I don't think this IRQ is actually useful. It doesn't really harm but
the tests should pass without it.

> +	if (err) {
> +		dev_err(dev, "Could not request update irq: %d\n", err);
> +		return err;
> +	}
> +	disable_irq(rtc->update_irq);
> +
> +	err = device_init_wakeup(dev, 1);

If you use device_init_wakeup, I think it needs to be called before
devm_rtc_device_register() to properly work.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

* Re: [PATCHv2] rtc: cpcap: new rtc driver
  2017-02-21 23:52   ` Alexandre Belloni
@ 2017-02-22  1:56     ` Sebastian Reichel
  2017-02-22  8:18       ` Alexandre Belloni
  0 siblings, 1 reply; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-22  1:56 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Tony Lindgren, Alessandro Zummo, rtc-linux, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4169 bytes --]

Hi Alexandre,

On Wed, Feb 22, 2017 at 12:52:12AM +0100, Alexandre Belloni wrote:
> The patch has a few checkpatch issues. Some of those should really be
> fixed. Can you do that?

of course.

> Else, it is mostly fine, a few comments below.
> 
> On 21/02/2017 at 07:16:50 +0100, Sebastian Reichel wrote:
> > +static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
> > +{
> > +	struct cpcap_rtc *rtc;
> > +	struct cpcap_time cpcap_tm;
> > +	int ret = 0;
> > +
> > +	rtc = dev_get_drvdata(dev);
> > +
> > +	rtc2cpcap_time(&cpcap_tm, tm);
> > +
> > +	if (rtc->alarm_enabled)
> > +		disable_irq(rtc->alarm_irq);
> > +	if (rtc->update_enabled)
> > +		disable_irq(rtc->update_irq);
> > +
> > +	if (rtc->vendor == CPCAP_VENDOR_ST) {
> > +		/* The TOD1 and TOD2 registers MUST be written in this order
> > +		 * for the change to properly set. */
> 
> Does this mean there is a race condition?

The logic (incl. comments) in this section are from the vendor
kernel driver and there is no documentation for CPCAP as far as
I know. I don't know if the hardware has logic to prevent a race
condition for the cpcap_tm.tod1 == 255 case.

> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> > +					  TOD1_MASK, cpcap_tm.tod1);
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
> > +					  TOD2_MASK, cpcap_tm.tod2);
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
> > +					  DAY_MASK, cpcap_tm.day);
> > +	} else {
> > +		/* Clearing the upper lower 8 bits of the TOD guarantees that
> > +		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
> > +		 * ticks (255 seconds).  During this time we can safely write
> > +		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
> > +		 * synchronized to the exact time requested upon the final write
> > +		 * to TOD1. */
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> > +					  TOD1_MASK, 0);
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
> > +					  DAY_MASK, cpcap_tm.day);
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
> > +					  TOD2_MASK, cpcap_tm.tod2);
> > +		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
> > +					  TOD1_MASK, cpcap_tm.tod1);
> > +	}
> > +
> 
> > +	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
> I think this means it depends on the mfd tree.

Yes, but cpcap_get_vendor should get into mainline with the
4.11 mfd pull request. So if you base your 4.12 for-next tree
on 4.11-rc1 everything should be fine.

> > +	if (err)
> > +		return err;
> > +
> > +	rtc->alarm_irq= platform_get_irq(pdev, 0);
> > +	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
> > +					cpcap_rtc_alarm_irq, IRQ_NONE,
> > +					"rtc_alarm", rtc);
> > +	if (err) {
> > +		dev_err(dev, "Could not request alarm irq: %d\n", err);
> > +		return err;
> > +	}
> > +	disable_irq(rtc->alarm_irq);
> > +
> > +	rtc->update_irq= platform_get_irq(pdev, 1);
> > +	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
> > +					cpcap_rtc_update_irq, IRQ_NONE,
> > +					"rtc_1hz", rtc);

> I don't think this IRQ is actually useful. It doesn't really harm but
> the tests should pass without it.

Yes. RTC works perfectly fine with just the alarm irq. It also
works perfectly fine with just the 1 Hz irq (except for wakeup).

I would like to keep the irq in the driver, so that it's explicitly
disabled. On Droid 4 mainline kernel is booted via kexec from
Android (AKA bootloader) and Motorola's Android kernel uses the
1 Hz IRQ for some proprietary "secure clock daemon".

I will add a comment.

> > +	if (err) {
> > +		dev_err(dev, "Could not request update irq: %d\n", err);
> > +		return err;
> > +	}
> > +	disable_irq(rtc->update_irq);
> > +
> > +	err = device_init_wakeup(dev, 1);
> 
> If you use device_init_wakeup, I think it needs to be called before
> devm_rtc_device_register() to properly work.

I successfully tested wakeup before sending this. But in case your 
prefer it to be called before registering the RTC I can move the
call accordingly.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCHv2] rtc: cpcap: new rtc driver
  2017-02-22  1:56     ` Sebastian Reichel
@ 2017-02-22  8:18       ` Alexandre Belloni
  0 siblings, 0 replies; 20+ messages in thread
From: Alexandre Belloni @ 2017-02-22  8:18 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, rtc-linux, linux-kernel

On 22/02/2017 at 02:56:34 +0100, Sebastian Reichel wrote:
> > Does this mean there is a race condition?
> 
> The logic (incl. comments) in this section are from the vendor
> kernel driver and there is no documentation for CPCAP as far as
> I know. I don't know if the hardware has logic to prevent a race
> condition for the cpcap_tm.tod1 == 255 case.
> 

That's fine, I was just curious :)

> > > +	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
> > I think this means it depends on the mfd tree.
> 
> Yes, but cpcap_get_vendor should get into mainline with the
> 4.11 mfd pull request. So if you base your 4.12 for-next tree
> on 4.11-rc1 everything should be fine.
> 

OK, I'll take it for 4.12 then

> > > +	if (err)
> > > +		return err;
> > > +
> > > +	rtc->alarm_irq= platform_get_irq(pdev, 0);
> > > +	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
> > > +					cpcap_rtc_alarm_irq, IRQ_NONE,
> > > +					"rtc_alarm", rtc);
> > > +	if (err) {
> > > +		dev_err(dev, "Could not request alarm irq: %d\n", err);
> > > +		return err;
> > > +	}
> > > +	disable_irq(rtc->alarm_irq);
> > > +
> > > +	rtc->update_irq= platform_get_irq(pdev, 1);
> > > +	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
> > > +					cpcap_rtc_update_irq, IRQ_NONE,
> > > +					"rtc_1hz", rtc);
> 
> > I don't think this IRQ is actually useful. It doesn't really harm but
> > the tests should pass without it.
> 
> Yes. RTC works perfectly fine with just the alarm irq. It also
> works perfectly fine with just the 1 Hz irq (except for wakeup).
> 
> I would like to keep the irq in the driver, so that it's explicitly
> disabled. On Droid 4 mainline kernel is booted via kexec from
> Android (AKA bootloader) and Motorola's Android kernel uses the
> 1 Hz IRQ for some proprietary "secure clock daemon".
> 
> I will add a comment.
> 

OK, my plan was to remove all the RTC_UF users. I'll give it more
thoughts.

> > > +	if (err) {
> > > +		dev_err(dev, "Could not request update irq: %d\n", err);
> > > +		return err;
> > > +	}
> > > +	disable_irq(rtc->update_irq);
> > > +
> > > +	err = device_init_wakeup(dev, 1);
> > 
> > If you use device_init_wakeup, I think it needs to be called before
> > devm_rtc_device_register() to properly work.
> 
> I successfully tested wakeup before sending this. But in case your 
> prefer it to be called before registering the RTC I can move the
> call accordingly.
> 

Then it is fine where it is.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

* [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola
  2017-02-20  7:35 [PATCH 0/1] Motorola CPCAP PMIC RTC Sebastian Reichel
  2017-02-20  7:35 ` [PATCH 1/1] rtc: cpcap: new rtc driver Sebastian Reichel
  2017-02-21  6:16 ` [PATCHv2] " Sebastian Reichel
@ 2017-02-23  1:03 ` Sebastian Reichel
  2017-02-23  1:03   ` [PATCHv3 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
  2017-02-27 23:48   ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Rob Herring
  2017-03-02  0:27 ` [PATCHv4 " Sebastian Reichel
  3 siblings, 2 replies; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-23  1:03 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: Rob Herring, Mark Rutland, rtc-linux, devicetree, linux-kernel

Motorola was involved in semiconductor and mobile phone business.
The "motrola," prefix is already used by a couple of bindings:

* rtc/rtc-cmos.txt
* mfd/motorola-cpcap.txt
* regulator/cpcap-regulator.txt

Apart from that it is used in the DT file for the Droid 4 mobile
phone.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 1e4e84ee6a3d..1a21b378fa91 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -189,6 +189,7 @@ minix	MINIX Technology Ltd.
 miramems	MiraMEMS Sensing Technology Co., Ltd.
 mitsubishi	Mitsubishi Electric Corporation
 mosaixtech	Mosaix Technologies, Inc.
+motorola	Motorola, Inc.
 moxa	Moxa
 mpl	MPL AG
 mqmaker	mqmaker Inc.
-- 
2.11.0

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

* [PATCHv3 2/2] rtc: cpcap: new rtc driver
  2017-02-23  1:03 ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Sebastian Reichel
@ 2017-02-23  1:03   ` Sebastian Reichel
  2017-02-27 23:49     ` Rob Herring
  2017-02-27 23:48   ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Rob Herring
  1 sibling, 1 reply; 20+ messages in thread
From: Sebastian Reichel @ 2017-02-23  1:03 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: Rob Herring, Mark Rutland, rtc-linux, devicetree, linux-kernel

This driver supports the Motorola CPCAP PMIC found on
some of Motorola's mobile phones, such as the Droid 4.

Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---

Changes since PATCHv2:
 - checkpatch fixes
 - add comment for update irq
 - introduced vendor prefix patch
Changes since PATCHv1:
 - added device_init_wakeup() at the end of probe
 - added Tested-by from Tony

---
 .../devicetree/bindings/rtc/cpcap-rtc.txt          |  13 +
 drivers/rtc/Kconfig                                |   7 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-cpcap.c                            | 332 +++++++++++++++++++++
 4 files changed, 353 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
 create mode 100644 drivers/rtc/rtc-cpcap.c

diff --git a/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
new file mode 100644
index 000000000000..2709c32baf2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
@@ -0,0 +1,13 @@
+Motorola CPCAP PMIC RTC
+------------------------------------
+
+Requires node properties:
+- compatible: should contain "motorola,cpcap-rtc"
+- interrupts: An interrupt specifier for alarm and 1 Hz irq
+
+Example:
+
+cpcap_rtc: rtc {
+	compatible = "motorola,cpcap-rtc";
+	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ee1b0e9dde79..050bec749fae 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32
 	   This driver can also be built as a module, if so, the module
 	   will be called "rtc-stm32".
 
+config RTC_DRV_CPCAP
+	depends on MFD_CPCAP
+	tristate "Motorola CPCAP RTC"
+	help
+	   Say y here for CPCAP rtc found on some Motorola phones
+	   and tablets such as Droid 4.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f07297b1460a..13857d2fce09 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K)	+= rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_CPCAP)	+= rtc-cpcap.o
 obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o
 obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
new file mode 100644
index 000000000000..7c6a3c3167bd
--- /dev/null
+++ b/drivers/rtc/rtc-cpcap.c
@@ -0,0 +1,332 @@
+/*
+ * Motorola CPCAP PMIC RTC driver
+ *
+ * Based on cpcap-regulator.c from Motorola Linux kernel tree
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * Rewritten for mainline kernel
+ *  - use DT
+ *  - use regmap
+ *  - use standard interrupt framework
+ *  - use managed device resources
+ *  - remove custom "secure clock daemon" helpers
+ *
+ * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#define SECS_PER_DAY 86400
+#define DAY_MASK  0x7FFF
+#define TOD1_MASK 0x00FF
+#define TOD2_MASK 0x01FF
+
+struct cpcap_time {
+	int day;
+	int tod1;
+	int tod2;
+};
+
+struct cpcap_rtc {
+	struct regmap *regmap;
+	struct rtc_device *rtc_dev;
+	u16 vendor;
+	int alarm_irq;
+	bool alarm_enabled;
+	int update_irq;
+	bool update_enabled;
+};
+
+static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
+{
+	unsigned long int tod;
+	unsigned long int time;
+
+	tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
+	time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
+
+	rtc_time_to_tm(time, rtc);
+}
+
+static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
+{
+	unsigned long time;
+
+	rtc_tm_to_time(rtc, &time);
+
+	cpcap->day = time / SECS_PER_DAY;
+	time %= SECS_PER_DAY;
+	cpcap->tod2 = (time >> 8) & TOD2_MASK;
+	cpcap->tod1 = time & TOD1_MASK;
+}
+
+static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct cpcap_rtc *rtc = dev_get_drvdata(dev);
+
+	if (rtc->alarm_enabled == enabled)
+		return 0;
+
+	if (enabled)
+		enable_irq(rtc->alarm_irq);
+	else
+		disable_irq(rtc->alarm_irq);
+
+	rtc->alarm_enabled = !!enabled;
+
+	return 0;
+}
+
+static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int temp_tod2;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
+
+	if (temp_tod2 > cpcap_tm.tod2)
+		ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(tm, &cpcap_tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret = 0;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, tm);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+	if (rtc->update_enabled)
+		disable_irq(rtc->update_irq);
+
+	if (rtc->vendor == CPCAP_VENDOR_ST) {
+		/* The TOD1 and TOD2 registers MUST be written in this order
+		 * for the change to properly set.
+		 */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+	} else {
+		/* Clearing the upper lower 8 bits of the TOD guarantees that
+		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
+		 * ticks (255 seconds).  During this time we can safely write
+		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
+		 * synchronized to the exact time requested upon the final write
+		 * to TOD1.
+		 */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, 0);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+	}
+
+	if (rtc->update_enabled)
+		enable_irq(rtc->update_irq);
+	if (rtc->alarm_enabled)
+		enable_irq(rtc->alarm_irq);
+
+	return ret;
+}
+
+static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	alrm->enabled = rtc->alarm_enabled;
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(&alrm->time, &cpcap_tm);
+	return rtc_valid_tm(&alrm->time);
+}
+
+static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, &alrm->time);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+
+	ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
+				 cpcap_tm.day);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
+				  cpcap_tm.tod2);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
+				  cpcap_tm.tod1);
+
+	if (!ret) {
+		enable_irq(rtc->alarm_irq);
+		rtc->alarm_enabled = true;
+	}
+
+	return ret;
+}
+
+static const struct rtc_class_ops cpcap_rtc_ops = {
+	.read_time		= cpcap_rtc_read_time,
+	.set_time		= cpcap_rtc_set_time,
+	.read_alarm		= cpcap_rtc_read_alarm,
+	.set_alarm		= cpcap_rtc_set_alarm,
+	.alarm_irq_enable	= cpcap_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static int cpcap_rtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cpcap_rtc *rtc;
+	int err;
+
+	rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!rtc->regmap)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, rtc);
+	rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
+						&cpcap_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc->rtc_dev)) {
+		kfree(rtc);
+		return PTR_ERR(rtc->rtc_dev);
+	}
+
+	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
+	if (err)
+		return err;
+
+	rtc->alarm_irq = platform_get_irq(pdev, 0);
+	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
+					cpcap_rtc_alarm_irq, IRQ_NONE,
+					"rtc_alarm", rtc);
+	if (err) {
+		dev_err(dev, "Could not request alarm irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->alarm_irq);
+
+	/* Stock Android uses the 1 Hz interrupt for "secure clock daemon",
+	 * which is not supported by the mainline kernel. The mainline kernel
+	 * does not use the irq at the moment, but we explicitly request and
+	 * disable it, so that its masked and does not wake up the processor
+	 * every second.
+	 */
+	rtc->update_irq = platform_get_irq(pdev, 1);
+	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
+					cpcap_rtc_update_irq, IRQ_NONE,
+					"rtc_1hz", rtc);
+	if (err) {
+		dev_err(dev, "Could not request update irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->update_irq);
+
+	err = device_init_wakeup(dev, 1);
+	if (err) {
+		dev_err(dev, "wakeup initialization failed (%d)\n", err);
+		/* ignore error and continue without wakeup support */
+	}
+
+	return 0;
+}
+
+static const struct of_device_id cpcap_rtc_of_match[] = {
+	{ .compatible = "motorola,cpcap-rtc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
+
+static struct platform_driver cpcap_rtc_driver = {
+	.probe		= cpcap_rtc_probe,
+	.driver		= {
+		.name	= "cpcap-rtc",
+		.of_match_table = cpcap_rtc_of_match,
+	},
+};
+
+module_platform_driver(cpcap_rtc_driver);
+
+MODULE_ALIAS("platform:cpcap-rtc");
+MODULE_DESCRIPTION("CPCAP RTC driver");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_LICENSE("GPL");
-- 
2.11.0

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

* Re: [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola
  2017-02-23  1:03 ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Sebastian Reichel
  2017-02-23  1:03   ` [PATCHv3 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-02-27 23:48   ` Rob Herring
  1 sibling, 0 replies; 20+ messages in thread
From: Rob Herring @ 2017-02-27 23:48 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	rtc-linux, devicetree, linux-kernel

On Thu, Feb 23, 2017 at 02:03:52AM +0100, Sebastian Reichel wrote:
> Motorola was involved in semiconductor and mobile phone business.
> The "motrola," prefix is already used by a couple of bindings:

typo.

> 
> * rtc/rtc-cmos.txt
> * mfd/motorola-cpcap.txt
> * regulator/cpcap-regulator.txt
> 
> Apart from that it is used in the DT file for the Droid 4 mobile
> phone.
> 
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)

Otherwise,

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCHv3 2/2] rtc: cpcap: new rtc driver
  2017-02-23  1:03   ` [PATCHv3 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-02-27 23:49     ` Rob Herring
  0 siblings, 0 replies; 20+ messages in thread
From: Rob Herring @ 2017-02-27 23:49 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	rtc-linux, devicetree, linux-kernel

On Thu, Feb 23, 2017 at 02:03:53AM +0100, Sebastian Reichel wrote:
> This driver supports the Motorola CPCAP PMIC found on
> some of Motorola's mobile phones, such as the Droid 4.
> 
> Tested-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
> 
> Changes since PATCHv2:
>  - checkpatch fixes
>  - add comment for update irq
>  - introduced vendor prefix patch
> Changes since PATCHv1:
>  - added device_init_wakeup() at the end of probe
>  - added Tested-by from Tony
> 
> ---
>  .../devicetree/bindings/rtc/cpcap-rtc.txt          |  13 +
>  drivers/rtc/Kconfig                                |   7 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-cpcap.c                            | 332 +++++++++++++++++++++
>  4 files changed, 353 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
>  create mode 100644 drivers/rtc/rtc-cpcap.c
> 
> diff --git a/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
> new file mode 100644
> index 000000000000..2709c32baf2c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
> @@ -0,0 +1,13 @@
> +Motorola CPCAP PMIC RTC
> +------------------------------------

Need to state what this is a child of.

> +
> +Requires node properties:
> +- compatible: should contain "motorola,cpcap-rtc"
> +- interrupts: An interrupt specifier for alarm and 1 Hz irq
> +
> +Example:
> +
> +cpcap_rtc: rtc {
> +	compatible = "motorola,cpcap-rtc";
> +	interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
> +};

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

* [PATCHv4 1/2] dt-bindings: Add vendor prefix for Motorola
  2017-02-20  7:35 [PATCH 0/1] Motorola CPCAP PMIC RTC Sebastian Reichel
                   ` (2 preceding siblings ...)
  2017-02-23  1:03 ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Sebastian Reichel
@ 2017-03-02  0:27 ` Sebastian Reichel
  2017-03-02  0:27   ` [PATCHv4 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
  2017-03-09  0:33   ` [PATCHv4 1/2] dt-bindings: Add vendor prefix for Motorola Alexandre Belloni
  3 siblings, 2 replies; 20+ messages in thread
From: Sebastian Reichel @ 2017-03-02  0:27 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: Rob Herring, Mark Rutland, rtc-linux, devicetree, linux-kernel

Motorola was involved in semiconductor and mobile phone business.
The "motorola," prefix is already used by a couple of bindings:

* rtc/rtc-cmos.txt
* mfd/motorola-cpcap.txt
* regulator/cpcap-regulator.txt

Apart from that it is used in the DT file for the Droid 4 mobile
phone.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv3:
 - Fix typo
 - Add Acked-By from Rob Herring
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index bd0ed3cb4994..81b538fbad22 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -190,6 +190,7 @@ minix	MINIX Technology Ltd.
 miramems	MiraMEMS Sensing Technology Co., Ltd.
 mitsubishi	Mitsubishi Electric Corporation
 mosaixtech	Mosaix Technologies, Inc.
+motorola	Motorola, Inc.
 moxa	Moxa
 mpl	MPL AG
 mqmaker	mqmaker Inc.
-- 
2.11.0

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

* [PATCHv4 2/2] rtc: cpcap: new rtc driver
  2017-03-02  0:27 ` [PATCHv4 " Sebastian Reichel
@ 2017-03-02  0:27   ` Sebastian Reichel
  2017-03-02 14:11     ` Rob Herring
  2017-03-09  0:34     ` Alexandre Belloni
  2017-03-09  0:33   ` [PATCHv4 1/2] dt-bindings: Add vendor prefix for Motorola Alexandre Belloni
  1 sibling, 2 replies; 20+ messages in thread
From: Sebastian Reichel @ 2017-03-02  0:27 UTC (permalink / raw)
  To: Sebastian Reichel, Tony Lindgren, Alessandro Zummo, Alexandre Belloni
  Cc: Rob Herring, Mark Rutland, rtc-linux, devicetree, linux-kernel

This driver supports the Motorola CPCAP PMIC found on
some of Motorola's mobile phones, such as the Droid 4.

Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv3:
 - Modified DT binding document to mention parent device
---
 .../devicetree/bindings/rtc/cpcap-rtc.txt          |  18 ++
 drivers/rtc/Kconfig                                |   7 +
 drivers/rtc/Makefile                               |   1 +
 drivers/rtc/rtc-cpcap.c                            | 332 +++++++++++++++++++++
 4 files changed, 358 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
 create mode 100644 drivers/rtc/rtc-cpcap.c

diff --git a/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
new file mode 100644
index 000000000000..45750ff3112d
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
@@ -0,0 +1,18 @@
+Motorola CPCAP PMIC RTC
+-----------------------
+
+This module is part of the CPCAP. For more details about the whole
+chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
+
+Requires node properties:
+- compatible: should contain "motorola,cpcap-rtc"
+- interrupts: An interrupt specifier for alarm and 1 Hz irq
+
+Example:
+
+&cpcap {
+	cpcap_rtc: rtc {
+		compatible = "motorola,cpcap-rtc";
+		interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
+	};
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ee1b0e9dde79..050bec749fae 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32
 	   This driver can also be built as a module, if so, the module
 	   will be called "rtc-stm32".
 
+config RTC_DRV_CPCAP
+	depends on MFD_CPCAP
+	tristate "Motorola CPCAP RTC"
+	help
+	   Say y here for CPCAP rtc found on some Motorola phones
+	   and tablets such as Droid 4.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f07297b1460a..13857d2fce09 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K)	+= rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_CPCAP)	+= rtc-cpcap.o
 obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o
 obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
new file mode 100644
index 000000000000..7c6a3c3167bd
--- /dev/null
+++ b/drivers/rtc/rtc-cpcap.c
@@ -0,0 +1,332 @@
+/*
+ * Motorola CPCAP PMIC RTC driver
+ *
+ * Based on cpcap-regulator.c from Motorola Linux kernel tree
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * Rewritten for mainline kernel
+ *  - use DT
+ *  - use regmap
+ *  - use standard interrupt framework
+ *  - use managed device resources
+ *  - remove custom "secure clock daemon" helpers
+ *
+ * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/motorola-cpcap.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#define SECS_PER_DAY 86400
+#define DAY_MASK  0x7FFF
+#define TOD1_MASK 0x00FF
+#define TOD2_MASK 0x01FF
+
+struct cpcap_time {
+	int day;
+	int tod1;
+	int tod2;
+};
+
+struct cpcap_rtc {
+	struct regmap *regmap;
+	struct rtc_device *rtc_dev;
+	u16 vendor;
+	int alarm_irq;
+	bool alarm_enabled;
+	int update_irq;
+	bool update_enabled;
+};
+
+static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
+{
+	unsigned long int tod;
+	unsigned long int time;
+
+	tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
+	time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
+
+	rtc_time_to_tm(time, rtc);
+}
+
+static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
+{
+	unsigned long time;
+
+	rtc_tm_to_time(rtc, &time);
+
+	cpcap->day = time / SECS_PER_DAY;
+	time %= SECS_PER_DAY;
+	cpcap->tod2 = (time >> 8) & TOD2_MASK;
+	cpcap->tod1 = time & TOD1_MASK;
+}
+
+static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct cpcap_rtc *rtc = dev_get_drvdata(dev);
+
+	if (rtc->alarm_enabled == enabled)
+		return 0;
+
+	if (enabled)
+		enable_irq(rtc->alarm_irq);
+	else
+		disable_irq(rtc->alarm_irq);
+
+	rtc->alarm_enabled = !!enabled;
+
+	return 0;
+}
+
+static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int temp_tod2;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
+
+	if (temp_tod2 > cpcap_tm.tod2)
+		ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(tm, &cpcap_tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret = 0;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, tm);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+	if (rtc->update_enabled)
+		disable_irq(rtc->update_irq);
+
+	if (rtc->vendor == CPCAP_VENDOR_ST) {
+		/* The TOD1 and TOD2 registers MUST be written in this order
+		 * for the change to properly set.
+		 */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+	} else {
+		/* Clearing the upper lower 8 bits of the TOD guarantees that
+		 * the upper half of TOD (TOD2) will not increment for 0xFF RTC
+		 * ticks (255 seconds).  During this time we can safely write
+		 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
+		 * synchronized to the exact time requested upon the final write
+		 * to TOD1.
+		 */
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, 0);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
+					  DAY_MASK, cpcap_tm.day);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
+					  TOD2_MASK, cpcap_tm.tod2);
+		ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
+					  TOD1_MASK, cpcap_tm.tod1);
+	}
+
+	if (rtc->update_enabled)
+		enable_irq(rtc->update_irq);
+	if (rtc->alarm_enabled)
+		enable_irq(rtc->alarm_irq);
+
+	return ret;
+}
+
+static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	alrm->enabled = rtc->alarm_enabled;
+
+	ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
+	ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
+
+	if (ret) {
+		dev_err(dev, "Failed to read time\n");
+		return -EIO;
+	}
+
+	cpcap2rtc_time(&alrm->time, &cpcap_tm);
+	return rtc_valid_tm(&alrm->time);
+}
+
+static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cpcap_rtc *rtc;
+	struct cpcap_time cpcap_tm;
+	int ret;
+
+	rtc = dev_get_drvdata(dev);
+
+	rtc2cpcap_time(&cpcap_tm, &alrm->time);
+
+	if (rtc->alarm_enabled)
+		disable_irq(rtc->alarm_irq);
+
+	ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
+				 cpcap_tm.day);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
+				  cpcap_tm.tod2);
+	ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
+				  cpcap_tm.tod1);
+
+	if (!ret) {
+		enable_irq(rtc->alarm_irq);
+		rtc->alarm_enabled = true;
+	}
+
+	return ret;
+}
+
+static const struct rtc_class_ops cpcap_rtc_ops = {
+	.read_time		= cpcap_rtc_read_time,
+	.set_time		= cpcap_rtc_set_time,
+	.read_alarm		= cpcap_rtc_read_alarm,
+	.set_alarm		= cpcap_rtc_set_alarm,
+	.alarm_irq_enable	= cpcap_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
+{
+	struct cpcap_rtc *rtc = data;
+
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+	return IRQ_HANDLED;
+}
+
+static int cpcap_rtc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cpcap_rtc *rtc;
+	int err;
+
+	rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!rtc->regmap)
+		return -ENODEV;
+
+	platform_set_drvdata(pdev, rtc);
+	rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
+						&cpcap_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc->rtc_dev)) {
+		kfree(rtc);
+		return PTR_ERR(rtc->rtc_dev);
+	}
+
+	err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
+	if (err)
+		return err;
+
+	rtc->alarm_irq = platform_get_irq(pdev, 0);
+	err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
+					cpcap_rtc_alarm_irq, IRQ_NONE,
+					"rtc_alarm", rtc);
+	if (err) {
+		dev_err(dev, "Could not request alarm irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->alarm_irq);
+
+	/* Stock Android uses the 1 Hz interrupt for "secure clock daemon",
+	 * which is not supported by the mainline kernel. The mainline kernel
+	 * does not use the irq at the moment, but we explicitly request and
+	 * disable it, so that its masked and does not wake up the processor
+	 * every second.
+	 */
+	rtc->update_irq = platform_get_irq(pdev, 1);
+	err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
+					cpcap_rtc_update_irq, IRQ_NONE,
+					"rtc_1hz", rtc);
+	if (err) {
+		dev_err(dev, "Could not request update irq: %d\n", err);
+		return err;
+	}
+	disable_irq(rtc->update_irq);
+
+	err = device_init_wakeup(dev, 1);
+	if (err) {
+		dev_err(dev, "wakeup initialization failed (%d)\n", err);
+		/* ignore error and continue without wakeup support */
+	}
+
+	return 0;
+}
+
+static const struct of_device_id cpcap_rtc_of_match[] = {
+	{ .compatible = "motorola,cpcap-rtc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
+
+static struct platform_driver cpcap_rtc_driver = {
+	.probe		= cpcap_rtc_probe,
+	.driver		= {
+		.name	= "cpcap-rtc",
+		.of_match_table = cpcap_rtc_of_match,
+	},
+};
+
+module_platform_driver(cpcap_rtc_driver);
+
+MODULE_ALIAS("platform:cpcap-rtc");
+MODULE_DESCRIPTION("CPCAP RTC driver");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
+MODULE_LICENSE("GPL");
-- 
2.11.0

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

* Re: [PATCHv4 2/2] rtc: cpcap: new rtc driver
  2017-03-02  0:27   ` [PATCHv4 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-03-02 14:11     ` Rob Herring
  2017-03-09  0:34     ` Alexandre Belloni
  1 sibling, 0 replies; 20+ messages in thread
From: Rob Herring @ 2017-03-02 14:11 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, devicetree,
	linux-kernel

On Wed, Mar 1, 2017 at 6:27 PM, Sebastian Reichel <sre@kernel.org> wrote:
> This driver supports the Motorola CPCAP PMIC found on
> some of Motorola's mobile phones, such as the Droid 4.
>
> Tested-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
> Changes since PATCHv3:
>  - Modified DT binding document to mention parent device
> ---
>  .../devicetree/bindings/rtc/cpcap-rtc.txt          |  18 ++

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/rtc/Kconfig                                |   7 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-cpcap.c                            | 332 +++++++++++++++++++++
>  4 files changed, 358 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
>  create mode 100644 drivers/rtc/rtc-cpcap.c

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

* Re: [PATCHv4 1/2] dt-bindings: Add vendor prefix for Motorola
  2017-03-02  0:27 ` [PATCHv4 " Sebastian Reichel
  2017-03-02  0:27   ` [PATCHv4 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
@ 2017-03-09  0:33   ` Alexandre Belloni
  1 sibling, 0 replies; 20+ messages in thread
From: Alexandre Belloni @ 2017-03-09  0:33 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, Rob Herring, Mark Rutland,
	rtc-linux, devicetree, linux-kernel

On 02/03/2017 at 01:27:08 +0100, Sebastian Reichel wrote:
> Motorola was involved in semiconductor and mobile phone business.
> The "motorola," prefix is already used by a couple of bindings:
> 
> * rtc/rtc-cmos.txt
> * mfd/motorola-cpcap.txt
> * regulator/cpcap-regulator.txt
> 
> Apart from that it is used in the DT file for the Droid 4 mobile
> phone.
> 
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
> Changes since PATCHv3:
>  - Fix typo
>  - Add Acked-By from Rob Herring
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)
> 
Applied, thanks.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

* Re: [PATCHv4 2/2] rtc: cpcap: new rtc driver
  2017-03-02  0:27   ` [PATCHv4 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
  2017-03-02 14:11     ` Rob Herring
@ 2017-03-09  0:34     ` Alexandre Belloni
  1 sibling, 0 replies; 20+ messages in thread
From: Alexandre Belloni @ 2017-03-09  0:34 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Tony Lindgren, Alessandro Zummo, Rob Herring, Mark Rutland,
	rtc-linux, devicetree, linux-kernel

On 02/03/2017 at 01:27:09 +0100, Sebastian Reichel wrote:
> This driver supports the Motorola CPCAP PMIC found on
> some of Motorola's mobile phones, such as the Droid 4.
> 
> Tested-by: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> ---
> Changes since PATCHv3:
>  - Modified DT binding document to mention parent device
> ---
>  .../devicetree/bindings/rtc/cpcap-rtc.txt          |  18 ++
>  drivers/rtc/Kconfig                                |   7 +
>  drivers/rtc/Makefile                               |   1 +
>  drivers/rtc/rtc-cpcap.c                            | 332 +++++++++++++++++++++
>  4 files changed, 358 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/rtc/cpcap-rtc.txt
>  create mode 100644 drivers/rtc/rtc-cpcap.c
> 
Applied, thanks.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

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

end of thread, other threads:[~2017-03-09  0:42 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-20  7:35 [PATCH 0/1] Motorola CPCAP PMIC RTC Sebastian Reichel
2017-02-20  7:35 ` [PATCH 1/1] rtc: cpcap: new rtc driver Sebastian Reichel
2017-02-20 16:31   ` Tony Lindgren
2017-02-20 16:38     ` Alexandre Belloni
2017-02-20 17:21       ` Tony Lindgren
2017-02-20 17:27         ` Tony Lindgren
2017-02-20 19:35           ` Sebastian Reichel
2017-02-21  6:16 ` [PATCHv2] " Sebastian Reichel
2017-02-21 23:52   ` Alexandre Belloni
2017-02-22  1:56     ` Sebastian Reichel
2017-02-22  8:18       ` Alexandre Belloni
2017-02-23  1:03 ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Sebastian Reichel
2017-02-23  1:03   ` [PATCHv3 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
2017-02-27 23:49     ` Rob Herring
2017-02-27 23:48   ` [PATCHv3 1/2] dt-bindings: Add vendor prefix for Motorola Rob Herring
2017-03-02  0:27 ` [PATCHv4 " Sebastian Reichel
2017-03-02  0:27   ` [PATCHv4 2/2] rtc: cpcap: new rtc driver Sebastian Reichel
2017-03-02 14:11     ` Rob Herring
2017-03-09  0:34     ` Alexandre Belloni
2017-03-09  0:33   ` [PATCHv4 1/2] dt-bindings: Add vendor prefix for Motorola Alexandre Belloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).