[PATCH v1 4/4 RFC] rtc: pcf2127: implement access to nvram

From: Uwe Kleine-KÃnig
Date: Fri Oct 02 2015 - 05:17:37 EST


The rtc features a 512 byte battery backed RAM. Make it available via
sysfs.

Signed-off-by: Uwe Kleine-KÃnig <u.kleine-koenig@xxxxxxxxxxxxxx>
---

Notes:
This patch is broken in the same way as the previous one. Don't merge!

drivers/rtc/rtc-pcf2127.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index db057db88031..e21dc5dfc9fb 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -35,6 +35,10 @@
#define PCF2127_REG_MO (0x08)
#define PCF2127_REG_YR (0x09)

+#define PCF2127_REG_RAM_addr_MSB 0x1a
+#define PCF2127_REG_RAM_wrt_cmd 0x1c
+#define PCF2127_REG_RAM_rd_cmd 0x1d
+
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */

static struct i2c_driver pcf2127_driver;
@@ -295,6 +299,106 @@ static const struct attribute *pcf2127_attributes[] = {
NULL
};

+#define PCF2127_NVRAM_SIZE 512
+
+static ssize_t pcf2127_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct i2c_client *client;
+ int ret;
+ unsigned char i2cbuf[3] = { PCF2127_REG_RAM_addr_MSB, off >> 8, off };
+
+ if (off >= PCF2127_NVRAM_SIZE)
+ return 0;
+
+ if (count > PCF2127_NVRAM_SIZE - off)
+ count = PCF2127_NVRAM_SIZE - off;
+
+ if (!count)
+ return 0;
+
+ client = kobj_to_i2c_client(kobj);
+
+ /* set offset */
+ ret = i2c_master_send(client, i2cbuf, 3);
+ if (!ret)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to set RAM address\n");
+ return ret;
+ }
+
+ i2cbuf[0] = PCF2127_REG_RAM_rd_cmd;
+ ret = i2c_master_send(client, i2cbuf, 1);
+ if (!ret)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to issue read command\n");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, buf, count);
+ if (!ret)
+ ret = -EIO;
+ if (ret < 0)
+ dev_err(&client->dev, "failed to read data\n");
+
+ return ret;
+}
+
+static ssize_t pcf2127a_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct i2c_client *client;
+ int ret;
+ unsigned char i2cbuf[PCF2127_NVRAM_SIZE + 1] = {
+ PCF2127_REG_RAM_addr_MSB, off >> 8, off };
+
+ if (off >= PCF2127_NVRAM_SIZE)
+ return 0;
+
+ if (count > PCF2127_NVRAM_SIZE - off)
+ count = PCF2127_NVRAM_SIZE - off;
+
+ if (!count)
+ return 0;
+
+ client = kobj_to_i2c_client(kobj);
+
+ /* set offset */
+ ret = i2c_master_send(client, i2cbuf, 3);
+ if (!ret)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to set RAM address\n");
+ return ret;
+ }
+
+ i2cbuf[0] = PCF2127_REG_RAM_wrt_cmd;
+ memcpy(i2cbuf + 1, buf, count);
+ ret = i2c_master_send(client, i2cbuf, count + 1);
+ if (!ret)
+ ret = -EIO;
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to issue write command\n");
+ return ret;
+ }
+
+ return ret - 1;
+}
+
+static const struct bin_attribute pcf2127_nvram = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IWUSR | S_IRUGO,
+ },
+ .read = pcf2127_nvram_read,
+ .write = pcf2127a_nvram_write,
+ .size = PCF2127_NVRAM_SIZE,
+};
+
static int pcf2127_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -319,12 +423,21 @@ static int pcf2127_probe(struct i2c_client *client,
return ret;
}

+ ret = sysfs_create_bin_file(&client->dev.kobj, &pcf2127_nvram);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "failed to register sysfs nvram attribute\n");
+ goto err_create_bin_file;
+ }
+
pcf2127->rtc = devm_rtc_device_register(&client->dev,
pcf2127_driver.driver.name,
&pcf2127_rtc_ops, THIS_MODULE);

if (IS_ERR(pcf2127->rtc)) {
ret = PTR_ERR(pcf2127->rtc);
+ sysfs_remove_bin_file(&client->dev.kobj, &pcf2127_nvram);
+err_create_bin_file:
sysfs_remove_files(&client->dev.kobj, pcf2127_attributes);
}

@@ -333,6 +446,7 @@ static int pcf2127_probe(struct i2c_client *client,

static int pcf2127_remove(struct i2c_client *client)
{
+ sysfs_remove_bin_file(&client->dev.kobj, &pcf2127_nvram);
sysfs_remove_files(&client->dev.kobj, pcf2127_attributes);
return 0;
}
--
2.6.0

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