Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1262377 > unrolled thread

[PATCH 0/9] rtc-2123: access the clock offset feature

Started byJoshua Clayton <stillcompiling@gmail.com>
First post2015-11-04 16:40 +0100
Last post2015-11-04 16:40 +0100
Articles 5 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/9] rtc-2123: access the clock offset feature Joshua Clayton <stillcompiling@gmail.com> - 2015-11-04 16:40 +0100
    [PATCH 2/9] rtc-pcf2123: clean up reads from the chip Joshua Clayton <stillcompiling@gmail.com> - 2015-11-04 16:40 +0100
    [PATCH 5/9] rtc-pcf2123: put the chip reset into a function Joshua Clayton <stillcompiling@gmail.com> - 2015-11-04 16:40 +0100
    [PATCH 7/9] rtc-pcf2123: allow sysfs to accept hexidecimal Joshua Clayton <stillcompiling@gmail.com> - 2015-11-04 16:40 +0100
    [PATCH 9/9] rtc-pcf2123: adjust the clock rate via sysfs Joshua Clayton <stillcompiling@gmail.com> - 2015-11-04 16:40 +0100

#1262377 — [PATCH 0/9] rtc-2123: access the clock offset feature

FromJoshua Clayton <stillcompiling@gmail.com>
Date2015-11-04 16:40 +0100
Subject[PATCH 0/9] rtc-2123: access the clock offset feature
Message-ID<qr8kh-2go-9@gated-at.bofh.it>
Greetings,
This series was prompted by a need to adjust the clock rate of the rtc
The existing code performs a soft reset during probe, which wipes out
several registers including the offset register, which performs adjustments
to the clock rate.

The first several patches are cleanup, with patch 5 and 6 avoiding the reset,
and patch 9 adding a nice sysfs interface to the clock offset.

I know that this is not the only rtc to provide a programmable clock offset
I wonder if this interface would make a good addition to the rtc api?

The rtc chips I have seen list their clock adjustments in parts per million.
I went with parts per billion, since the ppm listed was listed with a
fractional component.

Joshua Clayton (9):
  rtc-pcf2123: Document all registers and useful bits
  rtc-pcf2123: clean up reads from the chip
  rtc-pcf2123: clean up writes to the rtc chip
  rtc-pcf2123: replace magic numbers with defines
  rtc-pcf2123: put the chip reset into a function
  rtc-pcf2123: avoid resetting the clock if possible
  rtc-pcf2123: allow sysfs to accept hexidecimal
  rtc-pcf2123: use sysfs groups
  rtc-pcf2123: adjust the clock rate via sysfs

 drivers/rtc/rtc-pcf2123.c | 391 ++++++++++++++++++++++++++++++----------------
 1 file changed, 257 insertions(+), 134 deletions(-)

-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1262378 — [PATCH 2/9] rtc-pcf2123: clean up reads from the chip

FromJoshua Clayton <stillcompiling@gmail.com>
Date2015-11-04 16:40 +0100
Subject[PATCH 2/9] rtc-pcf2123: clean up reads from the chip
Message-ID<qr8kj-2go-57@gated-at.bofh.it>
In reply to#1262377
put read operations into a function.
This makes the starting register more prominent and hides the delay.

Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
 drivers/rtc/rtc-pcf2123.c | 39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 7756210..648cb74 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -104,12 +104,26 @@ static inline void pcf2123_delay_trec(void)
 	ndelay(30);
 }
 
+static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	int ret;
+
+	if (reg > PCF2123_REG_MAX)
+		return -EFAULT;
+
+	reg |= PCF2123_READ;
+	ret = spi_write_then_read(spi, &reg, 1, rxbuf, size);
+	pcf2123_delay_trec();
+
+	return ret;
+}
+
 static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
 			    char *buffer)
 {
-	struct spi_device *spi = to_spi_device(dev);
 	struct pcf2123_sysfs_reg *r;
-	u8 txbuf[1], rxbuf[1];
+	u8 rxbuf[1];
 	unsigned long reg;
 	int ret;
 
@@ -119,11 +133,10 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
 	if (ret)
 		return ret;
 
-	txbuf[0] = PCF2123_READ | reg;
-	ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+	ret = pcf2123_read(dev, reg, rxbuf, 1);
 	if (ret < 0)
 		return -EIO;
-	pcf2123_delay_trec();
+
 	return sprintf(buffer, "0x%x\n", rxbuf[0]);
 }
 
@@ -158,16 +171,12 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
 
 static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-	struct spi_device *spi = to_spi_device(dev);
-	u8 txbuf[1], rxbuf[7];
+	u8 rxbuf[7];
 	int ret;
 
-	txbuf[0] = PCF2123_READ | PCF2123_REG_SC;
-	ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
-			rxbuf, sizeof(rxbuf));
+	ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
 	if (ret < 0)
 		return ret;
-	pcf2123_delay_trec();
 
 	tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F);
 	tm->tm_min = bcd2bin(rxbuf[1] & 0x7F);
@@ -279,16 +288,12 @@ static int pcf2123_probe(struct spi_device *spi)
 	pcf2123_delay_trec();
 
 	/* See if the counter was actually stopped */
-	txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1;
-	dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n",
-			txbuf[0]);
-	ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8),
-					rxbuf, 2 * sizeof(u8));
+	dev_dbg(&spi->dev, "checking for presence of RTC\n");
+	ret = pcf2123_read(&spi->dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
 	dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n",
 			rxbuf[0], rxbuf[1]);
 	if (ret < 0)
 		goto kfree_exit;
-	pcf2123_delay_trec();
 
 	if (!(rxbuf[0] & 0x20)) {
 		dev_err(&spi->dev, "chip not found\n");
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1262380 — [PATCH 5/9] rtc-pcf2123: put the chip reset into a function

FromJoshua Clayton <stillcompiling@gmail.com>
Date2015-11-04 16:40 +0100
Subject[PATCH 5/9] rtc-pcf2123: put the chip reset into a function
Message-ID<qr8kj-2go-65@gated-at.bofh.it>
In reply to#1262377
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
 drivers/rtc/rtc-pcf2123.c | 64 ++++++++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 28 deletions(-)

diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 257ce7d..d3c1447 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -260,6 +260,40 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	return 0;
 }
 
+static int pcf2123_reset(struct device *dev)
+{
+	int ret;
+	u8  rxbuf[2];
+
+	ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
+	if (ret < 0)
+		return ret;
+
+	/* Stop the counter */
+	dev_dbg(dev, "stopping RTC\n");
+	ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
+	if (ret < 0)
+		return ret;
+
+	/* See if the counter was actually stopped */
+	dev_dbg(dev, "checking for presence of RTC\n");
+	ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
+			rxbuf[0], rxbuf[1]);
+	if (!(rxbuf[0] & CTRL1_STOP))
+		return -ENODEV;
+
+	/* Start the counter */
+	ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static const struct rtc_class_ops pcf2123_rtc_ops = {
 	.read_time	= pcf2123_rtc_read_time,
 	.set_time	= pcf2123_rtc_set_time,
@@ -269,7 +303,6 @@ static int pcf2123_probe(struct spi_device *spi)
 {
 	struct rtc_device *rtc;
 	struct pcf2123_plat_data *pdata;
-	u8  rxbuf[2];
 	int ret, i;
 
 	pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
@@ -278,29 +311,9 @@ static int pcf2123_probe(struct spi_device *spi)
 		return -ENOMEM;
 	spi->dev.platform_data = pdata;
 
-	/* Send a software reset command */
-	dev_dbg(&spi->dev, "resetting RTC\n");
-	ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
-	if (ret < 0)
-		goto kfree_exit;
-
-	/* Stop the counter */
-	dev_dbg(&spi->dev, "stopping RTC\n");
-	ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_STOP);
-	if (ret < 0)
-		goto kfree_exit;
-
-	/* See if the counter was actually stopped */
-	dev_dbg(&spi->dev, "checking for presence of RTC\n");
-	ret = pcf2123_read(&spi->dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
-	dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n",
-			rxbuf[0], rxbuf[1]);
-	if (ret < 0)
-		goto kfree_exit;
-
-	if (!(rxbuf[0] & CTRL1_STOP)) {
+	ret = pcf2123_reset(&spi->dev);
+	if (ret < 0) {
 		dev_err(&spi->dev, "chip not found\n");
-		ret = -ENODEV;
 		goto kfree_exit;
 	}
 
@@ -308,11 +321,6 @@ static int pcf2123_probe(struct spi_device *spi)
 	dev_info(&spi->dev, "spiclk %u KHz.\n",
 			(spi->max_speed_hz + 500) / 1000);
 
-	/* Start the counter */
-	ret = pcf2123_write_reg(&spi->dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
-	if (ret < 0)
-		goto kfree_exit;
-
 	/* Finalize the initialization */
 	rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
 			&pcf2123_rtc_ops, THIS_MODULE);
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1262381 — [PATCH 7/9] rtc-pcf2123: allow sysfs to accept hexidecimal

FromJoshua Clayton <stillcompiling@gmail.com>
Date2015-11-04 16:40 +0100
Subject[PATCH 7/9] rtc-pcf2123: allow sysfs to accept hexidecimal
Message-ID<qr8kk-2go-67@gated-at.bofh.it>
In reply to#1262377
pcf2123 registers store their values in bcd.
sysfs sensibly displays them in hexidecimal.
Up to now, the sysfs store functions only accept base 10, which
makes no sense.

Add support for hexidecimal without removing base10 support.

Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
 drivers/rtc/rtc-pcf2123.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 4964d5c..6701e6d 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -178,7 +178,7 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
 	if (ret)
 		return ret;
 
-	ret = kstrtoul(buffer, 10, &val);
+	ret = kstrtoul(buffer, 0, &val);
 	if (ret)
 		return ret;
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1262382 — [PATCH 9/9] rtc-pcf2123: adjust the clock rate via sysfs

FromJoshua Clayton <stillcompiling@gmail.com>
Date2015-11-04 16:40 +0100
Subject[PATCH 9/9] rtc-pcf2123: adjust the clock rate via sysfs
Message-ID<qr8kk-2go-71@gated-at.bofh.it>
In reply to#1262377
pcf2123 has an offset register, which can be used to make minor
adjustments to the clock rate to compensate for temperature or
a crystal that is not exactly right.

The adjustment is calculated in parts per billion. The data sheet
uses parts per million (as do some others), but with 2 digits of
precision. Since floating point is forbidden, parts per billion is
a better fit.

Add a pair of sysfs files to seetand retrieve the offset in ppm.

Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
---
 drivers/rtc/rtc-pcf2123.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index d494638..6d70860 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -77,11 +77,17 @@
 /* PCF2123_REG_SC BITS */
 #define OSC_HAS_STOPPED		(0x80)	/* Clock has been stopped */
 
+/* PCF2123_REG_OFFSET BITS */
+#define OFFSET_COARSE		(0x80)	/* Coarse Mode Offset */
+
 /* READ/WRITE ADDRESS BITS */
 #define PCF2123_SUBADDR		(1 << 4)
 #define PCF2123_WRITE		((0 << 7) | PCF2123_SUBADDR)
 #define PCF2123_READ		((1 << 7) | PCF2123_SUBADDR)
 
+/* offset granularity in parts per billion in fine mode */
+#define OFFSET_STEP		(2170)
+
 static struct spi_driver pcf2123_driver;
 
 /*
@@ -166,6 +172,65 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
 	return count;
 }
 
+static ssize_t pcf2123_adjust_show(struct device *dev,
+				   struct device_attribute *attr, char *buffer)
+{
+	ssize_t ret;
+	s8 reg;
+
+	ret = pcf2123_read(dev, PCF2123_REG_OFFSET, &reg, 1);
+	if (ret < 0)
+		return -EIO;
+
+	if (reg & OFFSET_COARSE) {
+		reg <<= 1;
+	} else {
+		reg &= ~OFFSET_COARSE;
+		reg |= (reg & 0x40) << 1; /* sign extend */
+	}
+
+	return sprintf(buffer, "%ld\n", ((long)reg) * OFFSET_STEP);
+}
+
+static ssize_t pcf2123_adjust_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buffer, size_t count)
+{
+	ssize_t ret;
+	long val;
+	s8 reg;
+
+	ret = kstrtol(buffer, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > OFFSET_STEP * 127)
+		reg = 127;
+	else if (val < OFFSET_STEP * -128)
+		reg = -128;
+	else
+		reg = (s8)((val + (OFFSET_STEP >> 1)) / OFFSET_STEP);
+
+/*
+ * Each even value of the fine adjust overlaps with a value of the coarse
+ * adjustment, and since the coarse adjsutment will spread the adjustments
+ * over both hours, we use coarse for all even values, as well as values
+ * that are beyond the range of fine adjustment
+ */
+	if (reg <= 63 && reg >= -64 && reg & 1) {
+		reg &= ~OFFSET_COARSE;
+	} else {
+		reg >>= 1;
+		reg |= OFFSET_COARSE;
+	}
+
+	pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg);
+	if (ret < 0)
+		return -EIO;
+
+	return count;
+}
+
 static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	u8 rxbuf[7];
@@ -320,6 +385,8 @@ static DEVICE_ATTR(c, S_IRUGO | S_IWUSR, pcf2123_show, pcf2123_store);
 static DEVICE_ATTR(d, S_IRUGO | S_IWUSR, pcf2123_show, pcf2123_store);
 static DEVICE_ATTR(e, S_IRUGO | S_IWUSR, pcf2123_show, pcf2123_store);
 static DEVICE_ATTR(f, S_IRUGO | S_IWUSR, pcf2123_show, pcf2123_store);
+static DEVICE_ATTR(adjust, S_IRUGO | S_IWUSR, pcf2123_adjust_show,
+		   pcf2123_adjust_store);
 
 static struct attribute *pcf2123_attrs[] = {
 	&dev_attr_0.attr,
@@ -338,6 +405,7 @@ static struct attribute *pcf2123_attrs[] = {
 	&dev_attr_d.attr,
 	&dev_attr_e.attr,
 	&dev_attr_f.attr,
+	&dev_attr_adjust.attr,
 	NULL
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web