All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kirill Kapranov <kirill.kapranov@compulab.co.il>
To: a.zummo@towertech.it, alexandre.belloni@bootlin.com,
	phdm@macqel.be, linux-rtc@vger.kernel.org,
	linux-kernel@vger.kernel.org
Cc: Kirill Kapranov <kirill.kapranov@compulab.co.il>
Subject: [PATCH 2/4] rtc: abx80x: Enable SQW output
Date: Mon, 29 Mar 2021 00:02:30 +0300	[thread overview]
Message-ID: <20210328210232.10395-3-kirill.kapranov@compulab.co.il> (raw)
In-Reply-To: <20210328210232.10395-1-kirill.kapranov@compulab.co.il>

The RTCs of the family are able to produce square wave output for RTC
calibration purposes or for an external usage.

Signed-off-by: Kirill Kapranov <kirill.kapranov@compulab.co.il>
---
 drivers/rtc/rtc-abx80x.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 9b0138d07232..153d89b56da9 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -51,6 +51,9 @@
 #define ABX8XX_IRQ_AIE		BIT(2)
 #define ABX8XX_IRQ_IM_1_4	(0x3 << 5)
 
+#define ABX8XX_REG_SQW		0x13
+#define ABX8XX_SQW_MODE_BITS	5
+
 #define ABX8XX_REG_CD_TIMER_CTL	0x18
 
 #define ABX8XX_REG_OSC		0x1c
@@ -117,6 +120,15 @@ struct abx80x_priv {
 	struct watchdog_device wdog;
 };
 
+union abx8xx_reg_sqw {
+	struct {
+		unsigned int sqws:5;
+		int:2;
+		unsigned int sqwe:2;
+	};
+	int val;
+} __packed;
+
 static int abx80x_write_config_key(struct i2c_client *client, u8 key)
 {
 	if (i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, key) < 0) {
@@ -486,9 +498,119 @@ static ssize_t oscillator_show(struct device *dev,
 
 static DEVICE_ATTR_RW(oscillator);
 
+#define SQFS_COUNT (1 << ABX8XX_SQW_MODE_BITS)
+/* The index of the array is the value to be written to the 'Square Wave Function
+ * Select' register to make the RTC generate the required square wave.
+ */
+static const char *const sqfs[SQFS_COUNT] = {
+	"1_century", "32768_Hz", "8192_Hz", "4096_Hz",
+	"2048_Hz", "1024_Hz", "512_Hz", "256_Hz",
+	"128_Hz", "64_Hz", "32_Hz", "16_Hz",
+	"8_Hz", "4_Hz", "2_Hz", "1_Hz",
+	"1/2_Hz", "1/4_Hz", "1/8_Hz", "1/16_Hz",
+	"1/32_Hz", "1_min", "16384_Hz", "100_Hz",
+	"1_hour", "1_day", "TIRQ", "nTIRQ",
+	"1_year", "1_Hz_to_Counters", "1/32_Hz_from_Acal", "1/8_Hz_from_Acal",
+};
+
+static const bool valid_for_rc_mode[SQFS_COUNT] = {
+	true, false, false, false,
+	false, false, false, false,
+	true, true, true, true,
+	true, true, true, true,
+	true, true, true, true,
+	true, true, false, false,
+	true, true, true, true,
+	true, true, true, true,
+};
+
+static int sqw_set(struct i2c_client *client, const char *buf)
+{
+	union abx8xx_reg_sqw reg_sqw;
+	int retval;
+
+	reg_sqw.val = i2c_smbus_read_byte_data(client, ABX8XX_REG_SQW);
+	if (reg_sqw.val < 0)
+		goto err;
+
+	if (sysfs_streq(buf, "none")) {
+		reg_sqw.sqwe = 0;
+		dev_info(&client->dev, "sqw output disabled\n");
+	} else {
+		int idx = __sysfs_match_string(sqfs, SQFS_COUNT, buf);
+
+		if (idx < 0)
+			return idx;
+
+		if (abx80x_is_rc_mode(client) && !valid_for_rc_mode[idx])
+			dev_warn(&client->dev, "sqw frequency %s valid only in xt mode\n",
+				sqfs[idx]);
+
+		dev_info(&client->dev, "sqw output enabled @ %s\n", sqfs[idx]);
+		reg_sqw.sqwe = 1;
+		reg_sqw.sqws = idx;
+	}
+
+	retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_SQW, reg_sqw.val);
+	if (retval < 0)
+		goto err;
+
+	return 0;
+err:
+	dev_err(&client->dev, "Failed to set SQW\n");
+	return retval;
+
+}
+
+static ssize_t sqw_store(struct device *dev,
+			 struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	int retval;
+
+	retval = sqw_set(to_i2c_client(dev->parent), buf);
+	if (retval)
+		return retval;
+	else
+		return count;
+}
+
+static ssize_t sqw_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev->parent);
+	union abx8xx_reg_sqw reg_sqw;
+	int len = 0;
+	int i;
+
+	reg_sqw.val = i2c_smbus_read_byte_data(client, ABX8XX_REG_SQW);
+	if (reg_sqw.val < 0) {
+		dev_err(dev, "Failed to read SQW\n");
+		sprintf(buf, "\n");
+		return reg_sqw.val;
+	}
+
+	if (reg_sqw.sqwe)
+		len += scnprintf(buf+len, PAGE_SIZE - len, "none ");
+	else
+		len += scnprintf(buf+len, PAGE_SIZE - len, "[none] ");
+
+	for (i = 0; i < SQFS_COUNT; ++i) {
+		if (reg_sqw.sqwe && i == reg_sqw.sqws)
+			len += scnprintf(buf+len, PAGE_SIZE - len, "[%s] ", sqfs[i]);
+		else
+			len += scnprintf(buf+len, PAGE_SIZE - len, "%s ", sqfs[i]);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR_RW(sqw);
+
 static struct attribute *rtc_calib_attrs[] = {
 	&dev_attr_autocalibration.attr,
 	&dev_attr_oscillator.attr,
+	&dev_attr_sqw.attr,
 	NULL,
 };
 
@@ -686,6 +808,7 @@ static int abx80x_probe(struct i2c_client *client,
 	unsigned int lot;
 	unsigned int wafer;
 	unsigned int uid;
+	const char *sqw_mode_name;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
@@ -800,6 +923,9 @@ static int abx80x_probe(struct i2c_client *client,
 		abx80x_enable_trickle_charger(client, trickle_cfg);
 	}
 
+	if (!of_property_read_string(np, "sqw", &sqw_mode_name))
+		sqw_set(client, sqw_mode_name);
+
 	err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL,
 					BIT(2));
 	if (err)
-- 
2.11.0


  parent reply	other threads:[~2021-03-28 21:30 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-28 21:02 [PATCH 0/4] rtc:abx80x: Enable distributed digital calibration Kirill Kapranov
2021-03-28 21:02 ` [PATCH 1/4] dt-bindings: rtc: abracon,abx80x: Add sqw property Kirill Kapranov
2021-03-28 21:02 ` Kirill Kapranov [this message]
2021-03-29  0:34   ` [PATCH 2/4] rtc: abx80x: Enable SQW output kernel test robot
2021-03-29  0:34     ` kernel test robot
2021-03-29  6:19   ` Dan Carpenter
2021-03-29  6:19     ` Dan Carpenter
2021-03-29  6:19     ` Dan Carpenter
2021-03-30 15:28     ` Kirill Kapranov
2021-03-30 15:28       ` Kirill Kapranov
2021-03-28 21:02 ` [PATCH 3/4] dt-bindings: rtc: abracon,abx80x: Add xt-frequency property Kirill Kapranov
2021-03-28 21:02 ` [PATCH 4/4] rtc:abx80x: Enable xt digital calibration Kirill Kapranov
2021-04-09 10:46   ` Pavel Machek
2021-04-09 16:56     ` Kirill Kapranov
2021-03-28 21:14 ` [PATCH 0/4] rtc:abx80x: Enable distributed " Alexandre Belloni
2021-03-29  3:26 [PATCH 2/4] rtc: abx80x: Enable SQW output kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210328210232.10395-3-kirill.kapranov@compulab.co.il \
    --to=kirill.kapranov@compulab.co.il \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=phdm@macqel.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.