rtc: m41t93: add new features alarm, clock out, watchdog
Subsystems (2)
v3 cover rtc: m41t93: add new features alarm, clock out, watchdog
This patch series adds following to m41t93 rtc driver.
Functionalities:
- Alarm support (support to configure alarm 1)
- Square wave output support
- Watchdog support
Code improvements:
this series migrates existing driver to use standard regmap interface for spi instead of direct spi calls and uses regmap for new features.
Device tree support:
Adds device tree support to the driver along with binding documentation.
Testing:
This patch series is validated on TI am62x board with m41t93 rtc chip connected to spi0 bus.
regmap migration is additionally tested by observing spi transfers with the help of logic analyzer. Short summary of test flow is added in commit message of respective features.
Datasheet:
https://www.st.com/resource/en/datasheet/m41t93.pdf
patch 4 to 6 depend on patch 3 (regmap patch)
---
Changes in v3:
- Address comments on bindings from Krzysztof and add myself
as a maintainer.
- Re-validation/testing on top of v6.17-rc6
- Link to v2: https://lore.kernel.org/lkml/[email protected]/
Changes in v2:
- Address DTS and bindings coding style feedback from Krzysztof
- Verify bindings using $ make dt_binding_check
- Update example in binding documentation after testing.
- Analyze and Fix build warnings as suggested by kernel test robot.
- Drop patch 5 from series (device detect logic change).
This will be taken separately. Focus on functionalities in this series.
- Update commit messages with short test steps for each feature.
- Link to v1: https://lore.kernel.org/lkml/[email protected]/
---
Akhilesh Patil (6):
dt-bindings: rtc: Add ST m41t93
rtc: m41t93: add device tree support
rtc: m41t93: migrate to regmap api for register access
rtc: m41t93: Add alarm support
rtc: m41t93: Add square wave clock provider support
rtc: m41t93: Add watchdog support
.../devicetree/bindings/rtc/st,m41t93.yaml | 50 ++ drivers/rtc/rtc-m41t93.c | 488 ++++++++++++++++-- 2 files changed, 486 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml
Signature · 1 line
2.34.1
PATCH v3 1/6 dt-bindings: rtc: Add ST m41t93
Document DT bindings for m41t93 rtc which supports time, date, alarm, watchdog, square wave clock output provider, user sram and 8 bit timer.
--- .../devicetree/bindings/rtc/st,m41t93.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml
Documentation/devicetree/bindings/rtc/st,m41t93.yaml new file +50 -0
@@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/st,m41t93.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ST M41T93 RTC and compatible + +maintainers: + - Akhilesh Patil <[email protected]> + +description: + ST M41T93 is spi based Real Time Clock (RTC) with time, date, + alarm, watchdog, square wave clock output, 8 bit timer and + 7 bytes of user SRAM. + +properties: + compatible: + enum: + - st,m41t93 + + reg: + maxItems: 1 + + "#clock-cells": + const: 0 + +required: + - compatible + - reg + +allOf: + - $ref: rtc.yaml + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + rtc@0 { + compatible = "st,m41t93"; + reg = <0>; + #clock-cells = <0>; + spi-max-frequency = <2000000>; + }; + }; +
Signature · 1 line
2.34.1
Re: [PATCH v3 1/6] dt-bindings: rtc: Add ST m41t93
Quoted 10 lines · Akhilesh Patil
Document DT bindings for m41t93 rtc which supports time, date, alarm, watchdog, square wave clock output provider, user sram and 8 bit timer.
Signed-off-by Akhilesh Patil <[email protected]>--- .../devicetree/bindings/rtc/st,m41t93.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yaml
PATCH v3 2/6 rtc: m41t93: add device tree support
In reply to Akhilesh PatilAdd device tree support for m41t93 rtc by adding of_match_table. Define compatible string - "st,m41t93" which can be used to instantiate this rtc device via DT node.
--- drivers/rtc/rtc-m41t93.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/rtc/rtc-m41t93.c +7 -0
@@ -191,9 +191,16 @@ static int m41t93_probe(struct spi_device *spi)return 0 ; } +static const struct of_device_id m41t93_dt_match[] = { + { .compatible ="st,m41t93" }, + { } +}; +MODULE_DEVICE_TABLE (of, m41t93_dt_match); +static struct spi_driver m41t93_driver = { .driver = { .name ="rtc-m41t93" , + .of_match_table = m41t93_dt_match, }, .probe = m41t93_probe, };
Signature · 1 line
2.34.1
PATCH v3 3/6 rtc: m41t93: migrate to regmap api for register access
In reply to Akhilesh PatilAdapt driver to use regmap api with spi bus instead of direct spi subsystem calls to access device registers. Simplify and standardize the register interactions using more abstract and bus agnostic regmap api to reduce code duplication and improve maintainability. Define spi regmap config suitable for m41t93 spi bus protocol to achieve same transactions on spi bus.
Tested on TI am62x sk board with m41t93 rtc chip connected over spi0. Validated set and get time using hwclock tool and verified spi bus transfers using logic analyzer.
--- drivers/rtc/rtc-m41t93.c | 121 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 51 deletions(-)
drivers/rtc/rtc-m41t93.c +70 -51
@@ -12,6 +12,7 @@#include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/spi/spi.h> +#include <linux/regmap.h> #define M41T93_REG_SSEC 0#define M41T93_REG_ST_SEC 1
@@ -31,23 +32,17 @@#define M41T93_FLAG_BL (1 << 4)#define M41T93_FLAG_HT (1 << 6) -static inline int m41t93_set_reg (struct spi_device *spi,u8 addr,u8 data) -{ -u8 buf[2 ]; - -/* MSB must be '1' to write */ - buf[0 ] = addr |0x80 ; - buf[1 ] = data; - -return spi_write (spi, buf,sizeof (buf)); -} +struct m41t93_data { +struct rtc_device *rtc; +struct regmap *regmap; +};static int m41t93_set_time (struct device *dev,struct rtc_time *tm) { -struct spi_device *spi =to_spi_device (dev); -int tmp; -u8 buf[9 ] = {0x80 };/* write cmd + 8 data bytes */ -u8 *const data = &buf[1 ];/* ptr to first data byte */ +struct m41t93_data *m41t93 =dev_get_drvdata (dev); +int tmp, ret; +u8 buf[8 ] = {0 };/* 8 data bytes */ +u8 *const data = &buf[0 ];/* ptr to first data byte */ dev_dbg(dev, "%s secs=%d, mins=%d, " "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -56,31 +51,31 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm) tm->tm_mon, tm->tm_year, tm->tm_wday);if (tm->tm_year <100 ) { -dev_warn (&spi->dev,"unsupported date (before 2000-01-01).\n" ); +dev_warn (dev,"unsupported date (before 2000-01-01).\n" );return -EINVAL ; } - tmp =spi_w8r8 (spi,M41T93_REG_FLAGS ); -if (tmp <0 ) -return tmp; + ret =regmap_read (m41t93->regmap,M41T93_REG_FLAGS , &tmp); +if (ret <0 ) +return ret;if (tmp &M41T93_FLAG_OF ) { -dev_warn (&spi->dev,"OF bit is set, resetting.\n" ); -m41t93_set_reg (spi,M41T93_REG_FLAGS , tmp & ~M41T93_FLAG_OF ); +dev_warn (dev,"OF bit is set, resetting.\n" ); +regmap_write (m41t93->regmap,M41T93_REG_FLAGS , tmp & ~M41T93_FLAG_OF ); - tmp =spi_w8r8 (spi,M41T93_REG_FLAGS ); -if (tmp <0 ) { -return tmp; + ret =regmap_read (m41t93->regmap,M41T93_REG_FLAGS , &tmp); +if (ret <0 ) { +return ret; }else if (tmp &M41T93_FLAG_OF ) {/* OF cannot be immediately reset: oscillator has to be * restarted. */ u8 reset_osc = buf[M41T93_REG_ST_SEC ] |M41T93_FLAG_ST ; -dev_warn (&spi->dev, +dev_warn (dev,"OF bit is still set, kickstarting clock.\n" ); -m41t93_set_reg (spi,M41T93_REG_ST_SEC , reset_osc); +regmap_write (m41t93->regmap,M41T93_REG_ST_SEC , reset_osc); reset_osc &= ~M41T93_FLAG_ST ; -m41t93_set_reg (spi,M41T93_REG_ST_SEC , reset_osc); +regmap_write (m41t93->regmap,M41T93_REG_ST_SEC , reset_osc); } }
@@ -94,14 +89,13 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm) data[M41T93_REG_MON ] =bin2bcd (tm->tm_mon +1 ); data[M41T93_REG_YEAR ] =bin2bcd (tm->tm_year %100 ); -return spi_write (spi, buf,sizeof (buf)); +return regmap_bulk_write (m41t93->regmap,M41T93_REG_SSEC , buf,sizeof (buf)); }static int m41t93_get_time (struct device *dev,struct rtc_time *tm) { -struct spi_device *spi =to_spi_device (dev); -const u8 start_addr =0 ; +struct m41t93_data *m41t93 =dev_get_drvdata (dev);u8 buf[8 ];int century_after_1900;int tmp;
@@ -113,32 +107,32 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)case after poweron. Time is valid after resetting HT bit. 2. oscillator fail bit (OF) is set: time is invalid. */ - tmp =spi_w8r8 (spi,M41T93_REG_ALM_HOUR_HT ); -if (tmp <0 ) -return tmp; + ret =regmap_read (m41t93->regmap,M41T93_REG_ALM_HOUR_HT , &tmp); +if (ret <0 ) +return ret;if (tmp &M41T93_FLAG_HT ) { -dev_dbg (&spi->dev,"HT bit is set, reenable clock update.\n" ); -m41t93_set_reg (spi,M41T93_REG_ALM_HOUR_HT , - tmp & ~M41T93_FLAG_HT ); +dev_dbg (dev,"HT bit is set, reenable clock update.\n" ); +regmap_write (m41t93->regmap,M41T93_REG_ALM_HOUR_HT , + tmp & ~M41T93_FLAG_HT ); } - tmp =spi_w8r8 (spi,M41T93_REG_FLAGS ); -if (tmp <0 ) -return tmp; + ret =regmap_read (m41t93->regmap,M41T93_REG_FLAGS , &tmp); +if (ret <0 ) +return ret;if (tmp &M41T93_FLAG_OF ) { ret = -EINVAL ; -dev_warn (&spi->dev,"OF bit is set, write time to restart.\n" ); +dev_warn (dev,"OF bit is set, write time to restart.\n" ); }if (tmp &M41T93_FLAG_BL ) -dev_warn (&spi->dev,"BL bit is set, replace battery.\n" ); +dev_warn (dev,"BL bit is set, replace battery.\n" );/* read actual time/date */ - tmp =spi_write_then_read (spi, &start_addr,1 , buf,sizeof (buf)); -if (tmp <0 ) -return tmp; + ret =regmap_bulk_read (m41t93->regmap,M41T93_REG_SSEC , buf,sizeof (buf)); +if (ret <0 ) +return ret; tm->tm_sec =bcd2bin (buf[M41T93_REG_ST_SEC ]); tm->tm_min =bcd2bin (buf[M41T93_REG_MIN ]);
@@ -167,26 +161,51 @@ static const struct rtc_class_ops m41t93_rtc_ops = {static struct spi_driver m41t93_driver; +static const struct regmap_config regmap_config = { + .reg_bits =8 , + .val_bits =8 , + .read_flag_mask =0x00 , + .write_flag_mask =0x80 , + .zero_flag_mask = true, +}; +static int m41t93_probe (struct spi_device *spi) { -struct rtc_device *rtc; -int res; +int res, ret; +struct m41t93_data *m41t93; spi->bits_per_word =8 ;spi_setup (spi); - res =spi_w8r8 (spi,M41T93_REG_WDAY ); + m41t93 =devm_kzalloc (&spi->dev,sizeof (struct m41t93_data ),GFP_KERNEL ); + +if (!m41t93) +return -ENOMEM ; + +/* Set up regmap to access device registers*/ + m41t93->regmap =devm_regmap_init_spi (spi, ®map_config); +if (IS_ERR (m41t93->regmap)) { +dev_err (&spi->dev,"regmap init failure\n" ); +return PTR_ERR (m41t93->regmap); + } + + ret =regmap_read (m41t93->regmap,M41T93_REG_WDAY , &res); +if (ret <0 ) { +dev_err (&spi->dev,"IO error\n" ); +return -EIO ; + } +if (res <0 || (res &0xf8 ) !=0 ) {dev_err (&spi->dev,"not found 0x%x.\n" , res);return -ENODEV ; } - rtc =devm_rtc_device_register (&spi->dev, m41t93_driver.driver.name, - &m41t93_rtc_ops,THIS_MODULE ); -if (IS_ERR (rtc)) -return PTR_ERR (rtc); +spi_set_drvdata (spi, m41t93); -spi_set_drvdata (spi, rtc); + m41t93->rtc =devm_rtc_device_register (&spi->dev, m41t93_driver.driver.name, + &m41t93_rtc_ops,THIS_MODULE ); +if (IS_ERR (m41t93->rtc)) +return PTR_ERR (m41t93->rtc);return 0 ; }
Signature · 1 line
2.34.1
PATCH v3 4/6 rtc: m41t93: Add alarm support
In reply to Akhilesh PatilImplement alarm feature for rtc-m41t93 by adding necessary callbacks - set_alarm, read_alarm and alarm_irq_enable. Enable support to configure alarm 1 out of 2 alarms present in this rtc. Support only alarm configuration in this commit. This commit does not implement alarm irq handling.
Use selftests/rtc/rtctest for testing. Tested by observing IRQ pin (pin 12 of SOX18 package) on logic analyzer going low after alarm condition is met.
--- drivers/rtc/rtc-m41t93.c | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+)
drivers/rtc/rtc-m41t93.c +105 -0
@@ -22,6 +22,14 @@#define M41T93_REG_DAY 5#define M41T93_REG_MON 6#define M41T93_REG_YEAR 7 +#define M41T93_REG_AL1_MONTH 0xa +#define M41T93_REG_AL1_DATE 0xb +#define M41T93_REG_AL1_HOUR 0xc +#define M41T93_REG_AL1_MIN 0xd +#define M41T93_REG_AL1_SEC 0xe +#define M41T93_BIT_A1IE BIT(7) +#define M41T93_BIT_ABE BIT(5) +#define M41T93_FLAG_AF1 BIT(6)#define M41T93_REG_ALM_HOUR_HT 0xc
@@ -153,10 +161,107 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)return ret; } +static int m41t93_set_alarm (struct device *dev,struct rtc_wkalrm *alrm) +{ +struct m41t93_data *m41t93 =dev_get_drvdata (dev); +int ret; +unsigned int val; +u8 alarm_vals[5 ] = {0 }; + + ret =regmap_bulk_write (m41t93->regmap,M41T93_REG_AL1_DATE , alarm_vals,4 ); +if (ret) +return ret; + +/* Set alarm values */ + alarm_vals[0 ] =bin2bcd (alrm->time.tm_mon +1 ) &0x1f ; + alarm_vals[1 ] =bin2bcd (alrm->time.tm_mday) &0x3f ; + alarm_vals[2 ] =bin2bcd (alrm->time.tm_hour) &0x3f ; + alarm_vals[3 ] =bin2bcd (alrm->time.tm_min) &0x7f ; + alarm_vals[4 ] =bin2bcd (alrm->time.tm_sec) &0x7f ; + +if (alrm->enabled) { +/* Enable alarm IRQ generation */ + alarm_vals[0 ] |=M41T93_BIT_A1IE |M41T93_BIT_ABE ; + } + +/* Preserve SQWE bit */ + ret =regmap_read (m41t93->regmap,M41T93_REG_AL1_MONTH , &val); +if (ret) +return ret; + + alarm_vals[0 ] |= val &0x40 ; + + ret =regmap_bulk_write (m41t93->regmap,M41T93_REG_AL1_MONTH , + alarm_vals,sizeof (alarm_vals)); +if (ret) +return ret; + +/* Device address pointer is now at FLAG register, move it to other location +* to finish setting alarm, as recommended by the datasheet. +* We do read of AL1_MONTH register to achieve this. +*/ + ret =regmap_read (m41t93->regmap,M41T93_REG_AL1_MONTH , &val); +if (ret) +return ret; + +if (bcd2bin (val &0x1f ) == (alrm->time.tm_mon &0x1f )) +dev_notice (dev,"Alarm set successfully\n" ); + +return 0 ; +} + +static int m41t93_get_alarm (struct device *dev,struct rtc_wkalrm *alrm) +{ +struct m41t93_data *m41t93 =dev_get_drvdata (dev); +int ret; +unsigned int val; +u8 alarm_vals[5 ] = {0 }; + + ret =regmap_bulk_read (m41t93->regmap,M41T93_REG_AL1_MONTH , + alarm_vals,sizeof (alarm_vals)); +if (ret) +return ret; + + alrm->time.tm_mon =bcd2bin (alarm_vals[0 ] &0x1f ) -1 ; + alrm->time.tm_mday =bcd2bin (alarm_vals[1 ] &0x3f ); + alrm->time.tm_hour =bcd2bin (alarm_vals[2 ] &0x3f ); + alrm->time.tm_min =bcd2bin (alarm_vals[3 ] &0x7f ); + alrm->time.tm_sec =bcd2bin (alarm_vals[4 ] &0x7f ); + + alrm->enabled = !!(alarm_vals[0 ] &M41T93_BIT_A1IE ); + + ret =regmap_read (m41t93->regmap,M41T93_REG_FLAGS , &val); +if (ret) +return ret; + + alrm->pending = (val &M41T93_FLAG_AF1 ) && alrm->enabled; + +return 0 ; +} + +static int m41t93_alarm_irq_enable (struct device *dev,unsigned int enabled) +{ +struct m41t93_data *m41t93 =dev_get_drvdata (dev); +unsigned int val; +int ret; + + val = enabled ?M41T93_BIT_A1IE |M41T93_BIT_ABE :0 ; + + ret =regmap_update_bits (m41t93->regmap,M41T93_REG_AL1_MONTH , +M41T93_BIT_A1IE |M41T93_BIT_ABE , val); +if (ret) +return ret; + +return 0 ; +} +static const struct rtc_class_ops m41t93_rtc_ops = { .read_time = m41t93_get_time, .set_time = m41t93_set_time, + .set_alarm = m41t93_set_alarm, + .read_alarm = m41t93_get_alarm, + .alarm_irq_enable = m41t93_alarm_irq_enable, };static struct spi_driver m41t93_driver;
Signature · 1 line
2.34.1
PATCH v3 5/6 rtc: m41t93: Add square wave clock provider support
In reply to Akhilesh PatilImplement support to configure square wave output (SQW) of m41t93 rtc via common clock framework clock provider api. Add clock provider callbacks to control output frequency ranging from 1Hz to 32KHz as supported by this rtc chip.
Use clock framework debugfs interface or clock consumer DT node to test. Tested by measuring various frequencies on pull-up connected SWQ(7) pin of m41t93 rtc chip using logic analyzer.
--- drivers/rtc/rtc-m41t93.c | 156 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-)
drivers/rtc/rtc-m41t93.c +155 -1
@@ -13,6 +13,7 @@#include <linux/rtc.h> #include <linux/spi/spi.h> #include <linux/regmap.h> +#include <linux/clk-provider.h> #define M41T93_REG_SSEC 0#define M41T93_REG_ST_SEC 1
@@ -30,7 +31,11 @@#define M41T93_BIT_A1IE BIT(7)#define M41T93_BIT_ABE BIT(5)#define M41T93_FLAG_AF1 BIT(6) - +#define M41T93_SRAM_BASE 0x19 +#define M41T93_REG_SQW 0x13 +#define M41T93_SQW_RS_MASK 0xf0 +#define M41T93_SQW_RS_SHIFT 4 +#define M41T93_BIT_SQWE BIT(6)#define M41T93_REG_ALM_HOUR_HT 0xc#define M41T93_REG_FLAGS 0xf
@@ -43,6 +48,9 @@struct m41t93_data {struct rtc_device *rtc;struct regmap *regmap; +#ifdef CONFIG_COMMON_CLK +struct clk_hw clks; +#endif };static int m41t93_set_time (struct device *dev,struct rtc_time *tm)
@@ -264,6 +272,146 @@ static const struct rtc_class_ops m41t93_rtc_ops = { .alarm_irq_enable = m41t93_alarm_irq_enable, }; +#ifdef CONFIG_COMMON_CLK +#define clk_sqw_to_m41t93_data (clk) \ + container_of(clk, struct m41t93_data, clks) + +/* m41t93 RTC clock output support */ +static unsigned long m41t93_clk_rates[] = { +0 , +32768 ,/* RS3:RS0 = 0b0001 */ +8192 , +4096 , +2048 , +1024 , +512 , +256 , +128 , +64 , +32 , +16 , +8 , +4 , +2 , +1 ,/* RS3:RS0 = 0b1111 */ +}; + +static unsigned long m41t93_clk_sqw_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +int ret; +unsigned int rate_id; +struct m41t93_data *m41t93 =clk_sqw_to_m41t93_data (hw); + + ret =regmap_read (m41t93->regmap,M41T93_REG_SQW , &rate_id); +if (ret) +return ret; + + rate_id &=M41T93_SQW_RS_MASK ; + rate_id >>=M41T93_SQW_RS_SHIFT ; + +return m41t93_clk_rates[rate_id]; +} + +static int m41t93_clk_sqw_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) +{ +int i; + +for (i =1 ; i <ARRAY_SIZE (m41t93_clk_rates); i++) { +if (req->rate >= m41t93_clk_rates[i]) { + req->rate = m41t93_clk_rates[i]; +return 0 ; + } + } + +return 0 ; +} + +static int m41t93_clk_sqw_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +int id, ret; +struct m41t93_data *m41t93 =clk_sqw_to_m41t93_data (hw); + +for (id =0 ; id <ARRAY_SIZE (m41t93_clk_rates); id++) { +if (m41t93_clk_rates[id] == rate) +break ; + } + +if (id >=ARRAY_SIZE (m41t93_clk_rates)) +return -EINVAL ; + + ret =regmap_update_bits (m41t93->regmap,M41T93_REG_SQW , +M41T93_SQW_RS_MASK , id <<M41T93_SQW_RS_SHIFT ); + +return ret; +} + +static int m41t93_clk_sqw_prepare (struct clk_hw *hw) +{ +int ret; +struct m41t93_data *m41t93 =clk_sqw_to_m41t93_data (hw); + + ret =regmap_update_bits (m41t93->regmap,M41T93_REG_AL1_MONTH , +M41T93_BIT_SQWE ,M41T93_BIT_SQWE ); + +return ret; +} + +static void m41t93_clk_sqw_unprepare (struct clk_hw *hw) +{ +struct m41t93_data *m41t93 =clk_sqw_to_m41t93_data (hw); + +regmap_update_bits (m41t93->regmap,M41T93_REG_AL1_MONTH , +M41T93_BIT_SQWE ,0 ); +} + +static int m41t93_clk_sqw_is_prepared (struct clk_hw *hw) +{ +int ret; +struct m41t93_data *m41t93 =clk_sqw_to_m41t93_data (hw); +unsigned int status; + + ret =regmap_read (m41t93->regmap,M41T93_REG_AL1_MONTH , &status); +if (ret) +return ret; + +return !!(status &M41T93_BIT_SQWE ); +} + +static const struct clk_ops m41t93_clk_sqw_ops = { + .prepare = m41t93_clk_sqw_prepare, + .unprepare = m41t93_clk_sqw_unprepare, + .is_prepared = m41t93_clk_sqw_is_prepared, + .recalc_rate = m41t93_clk_sqw_recalc_rate, + .set_rate = m41t93_clk_sqw_set_rate, + .determine_rate = m41t93_clk_sqw_determine_rate, +}; + +static int rtc_m41t93_clks_register (struct device *dev,struct m41t93_data *m41t93) +{ +struct device_node *node = dev->of_node; +struct clk *clk; +struct clk_init_data init = {0 }; + + init.name ="m41t93_clk_sqw" ; + init.ops = &m41t93_clk_sqw_ops; + + m41t93->clks.init = &init; + +/* Register the clock with CCF */ + clk =devm_clk_register (dev, &m41t93->clks); +if (IS_ERR (clk)) +return PTR_ERR (clk); + +if (node) +of_clk_add_provider (node, of_clk_src_simple_get, clk); + +return 0 ; +} +#endif +static struct spi_driver m41t93_driver;static const struct regmap_config regmap_config = {
@@ -312,6 +460,12 @@ static int m41t93_probe(struct spi_device *spi)if (IS_ERR (m41t93->rtc))return PTR_ERR (m41t93->rtc); +#ifdef CONFIG_COMMON_CLK + ret =rtc_m41t93_clks_register (&spi->dev, m41t93); +if (ret) +dev_warn (&spi->dev,"Unable to register clock\n" ); +#endif +return 0 ; }
Signature · 1 line
2.34.1
PATCH v3 6/6 rtc: m41t93: Add watchdog support
In reply to Akhilesh PatilImplement watchdog feature for m41t93 rtc with 1s resolution. Implement alarm only support (WDIOF_ALARMONLY) in this commit. Define start, stop, ping, and set_timeout callbacks as needed by the watchdog framework.
Use selftests/watchdog/watchdog-test kselftest for testing. Observed IRQ pin(12) of rtc chip going low after late pinging the watchdog.
--- drivers/rtc/rtc-m41t93.c | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
drivers/rtc/rtc-m41t93.c +99 -0
@@ -14,6 +14,7 @@#include <linux/spi/spi.h> #include <linux/regmap.h> #include <linux/clk-provider.h> +#include <linux/watchdog.h> #define M41T93_REG_SSEC 0#define M41T93_REG_ST_SEC 1
@@ -36,6 +37,10 @@#define M41T93_SQW_RS_MASK 0xf0#define M41T93_SQW_RS_SHIFT 4#define M41T93_BIT_SQWE BIT(6) +#define M41T93_REG_WATCHDOG 0x9 +#define M41T93_WDT_RB_MASK 0x3 +#define M41T93_WDT_BMB_MASK 0x7c +#define M41T93_WDT_BMB_SHIFT 2#define M41T93_REG_ALM_HOUR_HT 0xc#define M41T93_REG_FLAGS 0xf
@@ -51,6 +56,9 @@ struct m41t93_data {#ifdef CONFIG_COMMON_CLK struct clk_hw clks;#endif +#ifdef CONFIG_WATCHDOG +struct watchdog_device wdd; +#endif };static int m41t93_set_time (struct device *dev,struct rtc_time *tm)
@@ -412,6 +420,92 @@ static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t }#endif +#ifdef CONFIG_WATCHDOG +static int m41t93_wdt_ping (struct watchdog_device *wdd) +{ +u8 resolution, mult; +u8 val =0 ; +int ret; +struct m41t93_data *m41t93 =watchdog_get_drvdata (wdd); + +/* Resolution supported by hardware +* 0b00 : 1/16 seconds +* 0b01 : 1/4 second +* 0b10 : 1 second +* 0b11 : 4 seconds +*/ + resolution =0x2 ;/* hardcode resolution to 1s */ + mult = wdd->timeout; + val = resolution | (mult <<M41T93_WDT_BMB_SHIFT &M41T93_WDT_BMB_MASK ); + + ret =regmap_write_bits (m41t93->regmap,M41T93_REG_WATCHDOG , +M41T93_WDT_RB_MASK |M41T93_WDT_BMB_MASK , val); + +return ret; +} + +static int m41t93_wdt_start (struct watchdog_device *wdd) +{ +return m41t93_wdt_ping (wdd); +} + +static int m41t93_wdt_stop (struct watchdog_device *wdd) +{ +struct m41t93_data *m41t93 =watchdog_get_drvdata (wdd); + +/* Write 0 to watchdog register */ +return regmap_write_bits (m41t93->regmap,M41T93_REG_WATCHDOG , +M41T93_WDT_RB_MASK |M41T93_WDT_BMB_MASK ,0 ); +} + +static int m41t93_wdt_set_timeout (struct watchdog_device *wdd, +unsigned int new_timeout) +{ + wdd->timeout = new_timeout; + +return 0 ; +} + +static const struct watchdog_info m41t93_wdt_info = { + .identity ="m41t93 rtc Watchdog" , + .options =WDIOF_ALARMONLY |WDIOF_SETTIMEOUT |WDIOF_KEEPALIVEPING , +}; + +static const struct watchdog_ops m41t93_watchdog_ops = { + .owner =THIS_MODULE , + .start = m41t93_wdt_start, + .stop = m41t93_wdt_stop, + .ping = m41t93_wdt_ping, + .set_timeout = m41t93_wdt_set_timeout, +}; + +static int m41t93_watchdog_register (struct device *dev,struct m41t93_data *m41t93) +{ +int ret; + + m41t93->wdd.parent = dev; + m41t93->wdd.info = &m41t93_wdt_info; + m41t93->wdd.ops = &m41t93_watchdog_ops; + m41t93->wdd.min_timeout =0 ; + m41t93->wdd.max_timeout =10 ; + m41t93->wdd.timeout =3 ;/* Default timeout is 3 sec */ + m41t93->wdd.status =WATCHDOG_NOWAYOUT_INIT_STATUS ; + +watchdog_set_drvdata (&m41t93->wdd, m41t93); + + ret =devm_watchdog_register_device (dev, &m41t93->wdd); +if (ret) { +dev_warn (dev,"Failed to register watchdog\n" ); +return ret; + } + +/* Disable watchdog at start */ + ret =m41t93_wdt_stop (&m41t93->wdd); + +return ret; +} +#endif +static struct spi_driver m41t93_driver;static const struct regmap_config regmap_config = {
@@ -465,6 +559,11 @@ static int m41t93_probe(struct spi_device *spi)if (ret)dev_warn (&spi->dev,"Unable to register clock\n" );#endif +#ifdef CONFIG_WATCHDOG + ret =m41t93_watchdog_register (&spi->dev, m41t93); +if (ret) +dev_warn (&spi->dev,"Unable to register watchdog\n" ); +#endif return 0 ; }
Signature · 1 line
2.34.1
Quoted 21 lines · Akhilesh Patil
This patch series adds following to m41t93 rtc driver.
Functionalities:
- Alarm support (support to configure alarm 1)
- Square wave output support
- Watchdog supportCode improvements:
this series migrates existing driver to use standard regmap interface for spi instead of direct spi calls and uses regmap for new features.Device tree support:
Adds device tree support to the driver along with binding documentation.Testing:
This patch series is validated on TI am62x board with m41t93 rtc chip connected to spi0 bus.
regmap migration is additionally tested by observing spi transfers with the help of logic analyzer. Short summary of test flow is added in commit message of respective features.
Quoted 7 lines
Datasheet:
https://www.st.com/resource/en/datasheet/m41t93.pdfpatch 4 to 6 depend on patch 3 (regmap patch)
Signed-off-by Akhilesh Patil <[email protected]>---
Hi Alexandre, I would like to follow-up on this patch series for review and feedback for rtc code. Let me know if any additional improvements needed. I am willing to volunteer to support this driver in the kernel, in case needed, as a reviewer/maintainer. I have this m41t93 RTC hardware with me. Given we are in 6.18 merge window, looking forward for
this patch series.
Regards,
Akhilesh
Quoted 33 lines
Changes in v3:
- Address comments on bindings from Krzysztof and add myself
as a maintainer.
- Re-validation/testing on top of v6.17-rc6
- Link to v2: https://lore.kernel.org/lkml/[email protected]/Changes in v2:
- Address DTS and bindings coding style feedback from Krzysztof
- Verify bindings using $ makedt_binding_check
- Update example in binding documentation after testing.
- Analyze and Fix build warnings as suggested by kernel test robot.
- Drop patch 5 from series (device detect logic change).
This will be taken separately. Focus on functionalities in this series.
- Update commit messages with short test steps for each feature.
- Link to v1: https://lore.kernel.org/lkml/[email protected]/
---Akhilesh Patil (6):
dt-bindings: rtc: Add ST m41t93
rtc: m41t93: add device tree support
rtc: m41t93: migrate to regmap api for register access
rtc: m41t93: Add alarm support
rtc: m41t93: Add square wave clock provider support
rtc: m41t93: Add watchdog support.../devicetree/bindings/rtc/st,m41t93.yaml | 50 ++ drivers/rtc/rtc-m41t93.c | 488 ++++++++++++++++-- 2 files changed, 486 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/st,m41t93.yamlSignature · 1 line
2.34.1
Quoted 8 lines · Akhilesh Patil
This patch series adds following to m41t93 rtc driver.
Functionalities:
- Alarm support (support to configure alarm 1)
- Square wave output support
- Watchdog support[...]
Applied, thanks!
[1/6] dt-bindings: rtc: Add ST m41t93
https://git.kernel.org/abelloni/c/b70598b3769e [2/6] rtc: m41t93: add device tree support https://git.kernel.org/abelloni/c/081e3de28c76 [3/6] rtc: m41t93: migrate to regmap api for register access https://git.kernel.org/abelloni/c/d86e8682593c [4/6] rtc: m41t93: Add alarm support https://git.kernel.org/abelloni/c/5b55ff7cace4 [5/6] rtc: m41t93: Add square wave clock provider support https://git.kernel.org/abelloni/c/5cb6816cd81b [6/6] rtc: m41t93: Add watchdog support https://git.kernel.org/abelloni/c/15ec2ce19962
Best regards,
Signature · 3 lines
Alexandre Belloni, co-owner and COO, Bootlin Embedded Linux and Kernel engineering https://bootlin.com