2018-05-09 18:29:31

by Giulio Benetti

[permalink] [raw]
Subject: [PATCH v2 1/4] rtc: ds1307: fix data pointer to m41t0

data field points to m41t00, instead it should point to m41t0.
Driver works correctly because on both cases(m41t0 and m41t00) chip_desc
are equal.

Point to right enum m41t0 instead of m41t00.

Signed-off-by: Giulio Benetti <[email protected]>
---
drivers/rtc/rtc-ds1307.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index a13e59edff53..32aadcbc377f 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -298,7 +298,7 @@ static const struct of_device_id ds1307_of_match[] = {
},
{
.compatible = "st,m41t0",
- .data = (void *)m41t00
+ .data = (void *)m41t0
},
{
.compatible = "st,m41t00",
--
2.17.0



2018-05-09 18:29:07

by Giulio Benetti

[permalink] [raw]
Subject: [PATCH v2 4/4] rtc: ds1307: add freq_test sysfs attribute to check tick on m41txx

On m41txx you can enable open-drain OUT pin to check if offset is ok.
Enabling OUT pin with freq_test attribute, OUT pin will tick 512 times
faster than 1s tick base.

Enable or Disable FT bit on CONTROL register if freq_test is 1 or 0.

Signed-off-by: Giulio Benetti <[email protected]>
---
V1 => V2: change frequency test from dt property to dev sysfs attribute
drivers/rtc/rtc-ds1307.c | 86 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)

diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 33895668b363..da71000101da 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1042,6 +1042,67 @@ static int m41txx_rtc_set_offset(struct device *dev, long offset)
return regmap_write(ds1307->regmap, M41TXX_REG_CONTROL, ctrl_reg);
}

+static ssize_t freq_test_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ unsigned long freq_test = 0;
+ unsigned int ctrl_reg;
+ int retval;
+
+ retval = kstrtoul(buf, 10, &freq_test);
+ if ((retval < 0) || (retval > 1)) {
+ dev_err(dev, "Failed to store RTC Frequency Test attribute\n");
+ return -EINVAL;
+ }
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ if (freq_test)
+ ctrl_reg |= M41TXX_BIT_FT;
+ else
+ ctrl_reg &= ~M41TXX_BIT_FT;
+
+ retval = regmap_write(ds1307->regmap, M41TXX_REG_CONTROL, ctrl_reg);
+
+ return retval ? retval : count;
+}
+
+static ssize_t freq_test_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ int freq_test = 0;
+ unsigned int ctrl_reg;
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ if (ctrl_reg & M41TXX_BIT_FT)
+ freq_test = true;
+ else
+ freq_test = false;
+
+ if ((freq_test < 0) || (freq_test > 1)) {
+ dev_err(dev, "Failed to read RTC Frequency Test\n");
+ sprintf(buf, "0\n");
+ return freq_test;
+ }
+
+ return sprintf(buf, "%d\n", freq_test);
+}
+
+static DEVICE_ATTR_RW(freq_test);
+
+static struct attribute *rtc_calib_attrs[] = {
+ &dev_attr_freq_test.attr,
+ NULL,
+};
+
+static const struct attribute_group rtc_calib_attr_group = {
+ .attrs = rtc_calib_attrs,
+};
+
/*----------------------------------------------------------------------*/

static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
@@ -1455,6 +1516,13 @@ static const struct regmap_config regmap_config = {
.val_bits = 8,
};

+static void rtc_calib_remove_sysfs_group(void *_dev)
+{
+ struct device *dev = _dev;
+
+ sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
+}
+
static int ds1307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1783,6 +1851,24 @@ static int ds1307_probe(struct i2c_client *client,
if (err)
return err;

+ /* Export sysfs entries */
+ err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group);
+ if (err) {
+ dev_err(&client->dev, "Failed to create sysfs group: %d\n",
+ err);
+ return err;
+ }
+
+ err = devm_add_action_or_reset(&client->dev,
+ rtc_calib_remove_sysfs_group,
+ &client->dev);
+ if (err) {
+ dev_err(&client->dev,
+ "Failed to add sysfs cleanup action: %d\n",
+ err);
+ return err;
+ }
+
if (chip->nvram_size) {
struct nvmem_config nvmem_cfg = {
.name = "ds1307_nvram",
--
2.17.0


2018-05-09 18:30:02

by Giulio Benetti

[permalink] [raw]
Subject: [PATCH v2 3/4] rtc: ds1307: add offset sysfs for mt41txx chips.

m41txx chips can hold a calibration value to get correct clock bias.
If positive offset is passed, it means adding 512 cycles(@32.768Hz)
every tick(1s).
If negative offset is passed, it means subtracting 256 cycles(@32.768Hz)
every tick(1s).

Add offset handling (ranging between (-31) and 31) via sysfs.

Signed-off-by: Giulio Benetti <[email protected]>
---
V1 => V2: changed "calibration" from dt property to rtc sysfs offset
drivers/rtc/rtc-ds1307.c | 70 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)

diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 0ab0c166da83..33895668b363 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -114,6 +114,16 @@ enum ds_type {
# define RX8025_BIT_VDET 0x40
# define RX8025_BIT_XST 0x20

+#define M41TXX_REG_CONTROL 0x07
+# define M41TXX_BIT_OUT 0x80
+# define M41TXX_BIT_FT 0x40
+# define M41TXX_BIT_CALIB_SIGN 0x20
+# define M41TXX_M_CALIBRATION 0x1f
+
+/* Min and max values supported with 'offset' interface by M41TXX */
+#define M41TXX_MIN_OFFSET (-31)
+#define M41TXX_MAX_OFFSET (31)
+
struct ds1307 {
enum ds_type type;
unsigned long flags;
@@ -146,6 +156,9 @@ struct chip_desc {

static int ds1307_get_time(struct device *dev, struct rtc_time *t);
static int ds1307_set_time(struct device *dev, struct rtc_time *t);
+static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t);
+static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t);
+static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled);
static u8 do_trickle_setup_ds1339(struct ds1307 *, u32 ohms, bool diode);
static irqreturn_t rx8130_irq(int irq, void *dev_id);
static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t);
@@ -155,6 +168,8 @@ static irqreturn_t mcp794xx_irq(int irq, void *dev_id);
static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t);
static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled);
+static int m41txx_rtc_read_offset(struct device *dev, long *offset);
+static int m41txx_rtc_set_offset(struct device *dev, long offset);

static const struct rtc_class_ops rx8130_rtc_ops = {
.read_time = ds1307_get_time,
@@ -172,6 +187,16 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = {
.alarm_irq_enable = mcp794xx_alarm_irq_enable,
};

+static const struct rtc_class_ops m41txx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ .read_alarm = ds1337_read_alarm,
+ .set_alarm = ds1337_set_alarm,
+ .alarm_irq_enable = ds1307_alarm_irq_enable,
+ .read_offset = m41txx_rtc_read_offset,
+ .set_offset = m41txx_rtc_set_offset,
+};
+
static const struct chip_desc chips[last_ds_type] = {
[ds_1307] = {
.nvram_offset = 8,
@@ -227,10 +252,17 @@ static const struct chip_desc chips[last_ds_type] = {
.irq_handler = rx8130_irq,
.rtc_ops = &rx8130_rtc_ops,
},
+ [m41t0] = {
+ .rtc_ops = &m41txx_rtc_ops,
+ },
+ [m41t00] = {
+ .rtc_ops = &m41txx_rtc_ops,
+ },
[m41t11] = {
/* this is battery backed SRAM */
.nvram_offset = 8,
.nvram_size = 56,
+ .rtc_ops = &m41txx_rtc_ops,
},
[mcp794xx] = {
.alarm = 1,
@@ -972,6 +1004,44 @@ static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
enabled ? MCP794XX_BIT_ALM0_EN : 0);
}

+static int m41txx_rtc_read_offset(struct device *dev, long *offset)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ unsigned int ctrl_reg;
+ u8 val;
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ val = ctrl_reg & M41TXX_M_CALIBRATION;
+
+ /* check if positive */
+ if (ctrl_reg & M41TXX_BIT_CALIB_SIGN)
+ *offset = val;
+ else
+ *offset = -val;
+
+ return 0;
+}
+
+static int m41txx_rtc_set_offset(struct device *dev, long offset)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ unsigned int ctrl_reg;
+
+ if ((offset < M41TXX_MIN_OFFSET) || (offset > M41TXX_MAX_OFFSET))
+ return -ERANGE;
+
+ regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg);
+
+ ctrl_reg &= ~M41TXX_M_CALIBRATION;
+ ctrl_reg |= abs(offset) & M41TXX_M_CALIBRATION;
+
+ if (offset >= 0)
+ ctrl_reg |= M41TXX_BIT_CALIB_SIGN;
+
+ return regmap_write(ds1307->regmap, M41TXX_REG_CONTROL, ctrl_reg);
+}
+
/*----------------------------------------------------------------------*/

static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
--
2.17.0


2018-05-09 18:30:07

by Giulio Benetti

[permalink] [raw]
Subject: [PATCH v2 2/4] rtc: ds1307: support m41t11 variant

The m41t11 variant is very similar to the already supported m41t00 and
m41t0, but it has also 56 bytes of NVRAM.

Add it to driver taking into account NVRAM section.

Signed-off-by: Giulio Benetti <[email protected]>
---
.../devicetree/bindings/rtc/rtc-ds1307.txt | 1 +
drivers/rtc/rtc-ds1307.c | 14 ++++++++++++++
2 files changed, 15 insertions(+)

diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt
index d28d6e7f6ae8..ce6469c1a516 100644
--- a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt
+++ b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt
@@ -13,6 +13,7 @@ Required properties:
"maxim,ds3231",
"st,m41t0",
"st,m41t00",
+ "st,m41t11",
"microchip,mcp7940x",
"microchip,mcp7941x",
"pericom,pt7c4338",
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 32aadcbc377f..0ab0c166da83 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -44,6 +44,7 @@ enum ds_type {
ds_3231,
m41t0,
m41t00,
+ m41t11,
mcp794xx,
rx_8025,
rx_8130,
@@ -226,6 +227,11 @@ static const struct chip_desc chips[last_ds_type] = {
.irq_handler = rx8130_irq,
.rtc_ops = &rx8130_rtc_ops,
},
+ [m41t11] = {
+ /* this is battery backed SRAM */
+ .nvram_offset = 8,
+ .nvram_size = 56,
+ },
[mcp794xx] = {
.alarm = 1,
/* this is battery backed SRAM */
@@ -248,6 +254,7 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds3231", ds_3231 },
{ "m41t0", m41t0 },
{ "m41t00", m41t00 },
+ { "m41t11", m41t11 },
{ "mcp7940x", mcp794xx },
{ "mcp7941x", mcp794xx },
{ "pt7c4338", ds_1307 },
@@ -304,6 +311,10 @@ static const struct of_device_id ds1307_of_match[] = {
.compatible = "st,m41t00",
.data = (void *)m41t00
},
+ {
+ .compatible = "st,m41t11",
+ .data = (void *)m41t11
+ },
{
.compatible = "microchip,mcp7940x",
.data = (void *)mcp794xx
@@ -346,6 +357,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS3231", .driver_data = ds_3231 },
{ .id = "M41T0", .driver_data = m41t0 },
{ .id = "M41T00", .driver_data = m41t00 },
+ { .id = "M41T11", .driver_data = m41t11 },
{ .id = "MCP7940X", .driver_data = mcp794xx },
{ .id = "MCP7941X", .driver_data = mcp794xx },
{ .id = "PT7C4338", .driver_data = ds_1307 },
@@ -1574,6 +1586,7 @@ static int ds1307_probe(struct i2c_client *client,
case ds_1307:
case m41t0:
case m41t00:
+ case m41t11:
/* clock halted? turn it on, so clock can tick. */
if (tmp & DS1307_BIT_CH) {
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
@@ -1639,6 +1652,7 @@ static int ds1307_probe(struct i2c_client *client,
case ds_1340:
case m41t0:
case m41t00:
+ case m41t11:
/*
* NOTE: ignores century bits; fix before deploying
* systems that will run through year 2100.
--
2.17.0


2018-05-09 18:46:45

by Giulio Benetti

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] rtc: ds1307: add freq_test sysfs attribute to check tick on m41txx

Sorry everybody,

Il 09/05/2018 20:28, Giulio Benetti ha scritto:
> static int ds1307_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> {
> @@ -1783,6 +1851,24 @@ static int ds1307_probe(struct i2c_client *client,
> if (err)
> return err;
>
> + /* Export sysfs entries */
> + err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group);
> + if (err) {
> + dev_err(&client->dev, "Failed to create sysfs group: %d\n",
> + err);
> + return err;
> + }
> +
> + err = devm_add_action_or_reset(&client->dev,
> + rtc_calib_remove_sysfs_group,
> + &client->dev);
> + if (err) {
> + dev_err(&client->dev,
> + "Failed to add sysfs cleanup action: %d\n",
> + err);
> + return err;
> + }
> +
> if (chip->nvram_size) {
> struct nvmem_config nvmem_cfg = {
> .name = "ds1307_nvram",
>

Adding sysfs must be done only for mt41xx series.
I correct and submit V3 patchest.
Sorry again.

--
Giulio Benetti
CTO

MICRONOVA SRL
Sede: Via A. Niedda 3 - 35010 Vigonza (PD)
Tel. 049/8931563 - Fax 049/8931346
Cod.Fiscale - P.IVA 02663420285
Capitale Sociale ? 26.000 i.v.
Iscritta al Reg. Imprese di Padova N. 02663420285
Numero R.E.A. 258642