[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250110061401.358371-7-markus.burri@mt.com>
Date: Fri, 10 Jan 2025 07:14:00 +0100
From: Markus Burri <markus.burri@...com>
To: linux-kernel@...r.kernel.org
Cc: Markus Burri <markus.burri@...com>,
Alexandre Belloni <alexandre.belloni@...tlin.com>,
Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Marek Vasut <marex@...x.de>,
linux-rtc@...r.kernel.org,
devicetree@...r.kernel.org,
Manuel Traut <manuel.traut@...com>
Subject: [PATCH v1 6/7] rtc-rv8803: make tamper function configurable via sysfs
Make the following settings via sysfs configurable:
- For the input pins: input resistor, trigger edge, de-jitter filter.
- For the buffer: overwrite or inhibit mode for the FIFO.
Signed-off-by: Markus Burri <markus.burri@...com>
---
drivers/rtc/rtc-rv8803.c | 262 +++++++++++++++++++++++++++++++++++++++
1 file changed, 262 insertions(+)
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index c479cc7..cc8aa53 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -681,6 +681,31 @@ static int rv8803_nvram_read(void *priv, unsigned int offset,
return 0;
}
+static int cfg2val(const struct cfg_val_txt *cfg, const char *text, u8 *value)
+{
+ if (!value)
+ return -EINVAL;
+
+ do {
+ if (strcasecmp(cfg->txt, text) == 0) {
+ *value = cfg->val;
+ return 0;
+ }
+ } while (++cfg && cfg->txt);
+
+ return -EINVAL;
+}
+
+static char *cfg2txt(const struct cfg_val_txt *cfg, u8 value)
+{
+ do {
+ if (cfg->val == value)
+ return cfg->txt;
+ } while (++cfg && cfg->txt);
+
+ return NULL;
+}
+
static int rv8803_ts_event_write_evin(int evin, struct rv8803_data *rv8803, int pullup_down,
int trigger, int filter)
{
@@ -719,6 +744,31 @@ static int rv8803_ts_event_write_evin(int evin, struct rv8803_data *rv8803, int
return 0;
}
+static int rv8803_ts_event_read_evin(int evin, struct rv8803_data *rv8803,
+ int *pullup_down, int *trigger, int *filter)
+
+{
+ int ret;
+ struct i2c_client *client = rv8803->client;
+
+ /* get EVENTx pull-up edge trigger */
+ ret = rv8803_read_reg(client, evin_cfg_reg[evin]);
+ if (ret < 0)
+ return ret;
+
+ *pullup_down = FIELD_GET(RX8901_EVENTx_CFG_PUPD, ret);
+ *trigger = FIELD_GET(RX8901_EVENTx_CFG_POL, ret);
+
+ /* get EVENTx noise filter */
+ ret = rv8803_read_reg(client, evin_flt_reg[evin]);
+ if (ret < 0)
+ return ret;
+
+ *filter = ret;
+
+ return 0;
+}
+
static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -968,14 +1018,226 @@ static ssize_t trigger_store(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t cfg_evin_available_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i;
+ int offset = 0;
+
+ offset += sprintf(buf + offset, "pull-resistor:\n");
+
+ for (i = 0; pull_resistor_txt[i].txt; ++i)
+ if (!pull_resistor_txt[i].hide)
+ offset += sprintf(buf + offset, " %s\n", cfg2txt(pull_resistor_txt, i));
+ offset += sprintf(buf + offset, "\n");
+
+ offset += sprintf(buf + offset, "trigger:\n");
+ for (i = 0; trigger_txt[i].txt; ++i)
+ if (!trigger_txt[i].hide)
+ offset += sprintf(buf + offset, " %s\n", cfg2txt(trigger_txt, i));
+ offset += sprintf(buf + offset, "\n");
+
+ offset += sprintf(buf + offset, "filter [ms]:\n");
+ for (i = 0; i <= EVIN_FILTER_MAX; ++i)
+ if (i != 1)
+ offset += sprintf(buf + offset, " %d\n", EVIN_FILTER_FACTOR * i);
+
+ return offset;
+}
+
+static ssize_t cfg_evin_show(struct device *dev, int event, char *buf)
+{
+ int err;
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev->parent);
+
+ int pullup_down;
+ int trigger;
+ int filter;
+
+ --event;
+ if (event >= NO_OF_EVIN)
+ return -ENOENT;
+
+ guard(mutex)(&rv8803->flags_lock);
+ err = rv8803_ts_event_read_evin(event, rv8803,
+ &pullup_down, &trigger, &filter);
+ if (err)
+ return err;
+
+ return sprintf(buf, "pull-resistor=%s, trigger=%s, filter=%dms\n",
+ cfg2txt(pull_resistor_txt, pullup_down),
+ cfg2txt(trigger_txt, trigger),
+ EVIN_FILTER_FACTOR * filter);
+}
+
+static ssize_t cfg_evin1_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return cfg_evin_show(dev, 1, buf);
+}
+
+static ssize_t cfg_evin2_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return cfg_evin_show(dev, 2, buf);
+}
+
+static ssize_t cfg_evin3_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return cfg_evin_show(dev, 3, buf);
+}
+
+static ssize_t cfg_evin_store(struct device *dev, int event, const char *buf, size_t count)
+{
+ int err;
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev->parent);
+
+ char *buf_cpy;
+ char *token;
+ const char *startptr;
+ int pullup_down = -1;
+ int trigger = -1;
+ int filter = -1;
+ u8 v;
+
+ --event;
+ if (event >= NO_OF_EVIN)
+ return -ENOENT;
+
+ buf_cpy = kmalloc(count + 1, GFP_KERNEL);
+ if (!buf_cpy)
+ return -ENOMEM;
+
+ strscpy(buf_cpy, buf, count);
+ token = buf_cpy;
+ while ((startptr = strsep(&token, " ,\n"))) {
+ if (strstr(startptr, "pull-resistor=") == startptr)
+ if (cfg2val(pull_resistor_txt, strchr(startptr, '=') + 1, &v) == 0)
+ pullup_down = v;
+ if (strstr(startptr, "trigger=") == startptr)
+ if (cfg2val(trigger_txt, strchr(startptr, '=') + 1, &v) == 0)
+ trigger = v;
+ if (strstr(startptr, "filter=") == startptr)
+ filter = strtoul(strchr(startptr, '=') + 1, NULL, 0) / EVIN_FILTER_FACTOR;
+ }
+
+ kfree(buf_cpy);
+
+ guard(mutex)(&rv8803->flags_lock);
+ err = rv8803_ts_event_write_evin(event, rv8803, pullup_down, trigger, filter);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static ssize_t cfg_evin1_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return cfg_evin_store(dev, 1, buf, count);
+}
+
+static ssize_t cfg_evin2_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return cfg_evin_store(dev, 2, buf, count);
+}
+
+static ssize_t cfg_evin3_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return cfg_evin_store(dev, 3, buf, count);
+}
+
+static ssize_t cfg_buf_available_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int i;
+ int offset = 0;
+
+ offset += sprintf(buf + offset, "mode:\n");
+ for (i = 0; buffer_mode_txt[i].txt; ++i)
+ if (!buffer_mode_txt[i].hide)
+ offset += sprintf(buf + offset, " %s\n", cfg2txt(buffer_mode_txt, i));
+
+ return offset;
+}
+
+static ssize_t cfg_buf_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev->parent);
+
+ guard(mutex)(&rv8803->flags_lock);
+
+ ret = rv8803_read_reg(client, RX8901_BUF1_CFG1);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "mode:%s\n",
+ cfg2txt(buffer_mode_txt, FIELD_GET(BIT(6), ret)));
+}
+
+static ssize_t cfg_buf_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ char *buf_cpy;
+ char *token;
+ char *startptr;
+ int mode = -1;
+ u8 v;
+
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ struct rv8803_data *rv8803 = dev_get_drvdata(dev->parent);
+
+ buf_cpy = kmalloc(count + 1, GFP_KERNEL);
+ if (!buf_cpy)
+ return -ENOMEM;
+
+ strscpy(buf_cpy, buf, count);
+ token = buf_cpy;
+ while ((startptr = strsep(&token, " ,\n"))) {
+ if (strstr(startptr, "mode:") == startptr)
+ if (cfg2val(buffer_mode_txt, strchr(startptr, ':') + 1, &v) == 0)
+ mode = v;
+ }
+
+ kfree(buf_cpy);
+
+ if (mode != -1) {
+ guard(mutex)(&rv8803->flags_lock);
+
+ ret = rv8803_read_reg(client, RX8901_BUF1_CFG1);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~BIT(6);
+ ret |= FIELD_PREP(BIT(6), mode);
+ ret = rv8803_write_reg(client, RX8901_BUF1_CFG1, ret);
+ if (ret < 0)
+ return ret;
+ }
+ return count;
+}
+
static DEVICE_ATTR_WO(enable);
static DEVICE_ATTR_RO(read);
static DEVICE_ATTR_WO(trigger);
+static DEVICE_ATTR_RO(cfg_evin_available);
+static DEVICE_ATTR_RO(cfg_buf_available);
+static DEVICE_ATTR_RW(cfg_evin1);
+static DEVICE_ATTR_RW(cfg_evin2);
+static DEVICE_ATTR_RW(cfg_evin3);
+static DEVICE_ATTR_RW(cfg_buf);
static struct attribute *rv8803_rtc_event_attrs[] = {
&dev_attr_enable.attr,
&dev_attr_read.attr,
&dev_attr_trigger.attr,
+ &dev_attr_cfg_evin_available.attr,
+ &dev_attr_cfg_buf_available.attr,
+ &dev_attr_cfg_evin1.attr,
+ &dev_attr_cfg_evin2.attr,
+ &dev_attr_cfg_evin3.attr,
+ &dev_attr_cfg_buf.attr,
NULL
};
--
2.39.5
Powered by blists - more mailing lists