lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1443777442-15920-4-git-send-email-u.kleine-koenig@pengutronix.de>
Date:	Fri,  2 Oct 2015 11:17:21 +0200
From:	Uwe Kleine-König 
	<u.kleine-koenig@...gutronix.de>
To:	Alexandre Belloni <alexandre.belloni@...e-electrons.com>
Cc:	Alessandro Zummo <a.zummo@...ertech.it>,
	rtc-linux@...glegroups.com, kernel@...gutronix.de,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	linux-kernel@...r.kernel.org
Subject: [PATCH v1 3/4 RFC] rtc: pcf2127: implement reading battery status bits

The rtc features a battery switch-over function. Export battery status
and if a switch-over occured via sysfs.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@...gutronix.de>
---

Notes:
    Note this patch is wrong, don't merge!
    
    Calling sysfs_create_files in the driver's probe is too late. I didn't
    find a nice alternative though. But in case someone feels like pointing
    me in the right direction or using this even with this being wrong, here
    comes the patch anyhow.

 drivers/rtc/rtc-pcf2127.c | 132 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 2 deletions(-)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 7eb6ff26185e..db057db88031 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -22,7 +22,11 @@
 
 #define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
 #define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
+
 #define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
+#define PCF2127_REG_CTRL3_BF		0x08
+#define PCF2127_REG_CTRL3_BLF		0x04
+
 #define PCF2127_REG_SC          (0x03)  /* datetime */
 #define PCF2127_REG_MN          (0x04)
 #define PCF2127_REG_HR          (0x05)
@@ -54,7 +58,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 		return -EIO;
 	}
 
-	if (buf[PCF2127_REG_CTRL3] & 0x04)
+	if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF)
 		dev_info(&client->dev,
 			"low voltage detected, check/replace RTC battery.\n");
 
@@ -186,10 +190,116 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
 	.set_time	= pcf2127_rtc_set_time,
 };
 
+struct pcf2127_bitattr {
+	struct device_attribute attr;
+	unsigned bitmask;
+};
+
+static ssize_t pcf2127_bitattr_clear(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned char i2cbuf[2] = { PCF2127_REG_CTRL3, };
+	struct pcf2127_bitattr *bitattr =
+		container_of(attr, struct pcf2127_bitattr, attr);
+	int ret;
+	long val;
+
+	if (!count)
+		return 0;
+
+	ret = kstrtol(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	/* we only accept writing 0 */
+	if (val != 0)
+		return -EINVAL;
+
+	ret = i2c_master_send(client, i2cbuf, 1);
+	if (!ret)
+		ret = -EIO;
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(client, i2cbuf + 1, 1);
+	if (!ret)
+		ret = -EIO;
+	if (ret < 0)
+		return ret;
+
+	i2cbuf[1] &= ~bitattr->bitmask;
+
+	ret = i2c_master_send(client, i2cbuf, 2);
+	if (!ret)
+		ret = -EIO;
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t pcf2127_bitattr_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned char reg = PCF2127_REG_CTRL3;
+	struct pcf2127_bitattr *bitattr =
+		container_of(attr, struct pcf2127_bitattr, attr);
+	int ret;
+
+	ret = i2c_master_send(client, &reg, 1);
+	if (!ret)
+		ret = -EIO;
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(client, &reg, 1);
+	if (!ret)
+		ret = -EIO;
+	if (ret < 0)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE,
+			 "%d\n", !!(reg & bitattr->bitmask));
+}
+
+static struct pcf2127_bitattr pcf2127_battery_low = {
+	.attr = {
+		.attr = {
+			.name = "battery_low",
+			.mode = S_IRUGO,
+		},
+		.show = pcf2127_bitattr_show,
+	},
+	.bitmask = PCF2127_REG_CTRL3_BLF,
+};
+
+static struct pcf2127_bitattr pcf2127_battery_switch_over = {
+	.attr = {
+		.attr = {
+			.name = "battery_switch_over",
+			.mode = S_IWUSR | S_IRUGO,
+		},
+		.show = pcf2127_bitattr_show,
+		.store = pcf2127_bitattr_clear,
+	},
+	.bitmask = PCF2127_REG_CTRL3_BF,
+};
+
+static const struct attribute *pcf2127_attributes[] = {
+	&pcf2127_battery_low.attr.attr,
+	&pcf2127_battery_switch_over.attr.attr,
+	NULL
+};
+
 static int pcf2127_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
 	struct pcf2127 *pcf2127;
+	int ret;
 
 	dev_dbg(&client->dev, "%s\n", __func__);
 
@@ -203,11 +313,28 @@ static int pcf2127_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, pcf2127);
 
+	ret = sysfs_create_files(&client->dev.kobj, pcf2127_attributes);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to register sysfs attributes\n");
+		return ret;
+	}
+
 	pcf2127->rtc = devm_rtc_device_register(&client->dev,
 				pcf2127_driver.driver.name,
 				&pcf2127_rtc_ops, THIS_MODULE);
 
-	return PTR_ERR_OR_ZERO(pcf2127->rtc);
+	if (IS_ERR(pcf2127->rtc)) {
+		ret = PTR_ERR(pcf2127->rtc);
+		sysfs_remove_files(&client->dev.kobj, pcf2127_attributes);
+	}
+
+	return ret;
+}
+
+static int pcf2127_remove(struct i2c_client *client)
+{
+	sysfs_remove_files(&client->dev.kobj, pcf2127_attributes);
+	return 0;
 }
 
 static const struct i2c_device_id pcf2127_id[] = {
@@ -231,6 +358,7 @@ static struct i2c_driver pcf2127_driver = {
 		.of_match_table = of_match_ptr(pcf2127_of_match),
 	},
 	.probe		= pcf2127_probe,
+	.remove		= pcf2127_remove,
 	.id_table	= pcf2127_id,
 };
 
-- 
2.6.0

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ