diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-27 11:00:18 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-27 11:00:18 -0700 |
| commit | da7ca04e331e3e83f661e29c30d381a91e6ca245 (patch) | |
| tree | 60b462354bb5ed314712aaf236b724d1eaa7cd25 /drivers/rtc/rtc-ds1307.c | |
| parent | 6ca693ea903df5748809f61b290831004036978d (diff) | |
| parent | 3c8f28578a0d68bc7fb91d881b832d55f734270c (diff) | |
Merge tag 'rtc-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"Most of the work and improvements are for features of the m41t93.
The ds1307 also gets support for OSF (Oscillator Stop Flag) for
new variants.
The pcap driver is being removed as the Motorola EZX support was
removed a while ago.
Subsystem:
- add rtc_read_next_alarm() to read next expiring timer
Drivers:
- ds1307: handle OSF for ds1337/ds1339/ds3231, add clock provider for
ds1307, fix wday for rx8130
- m41t93: DT support, alarm, clock provider, watchdog support
- mv: add suspend/resume support for wakeup
- pcap: remove driver
- renesas-rtca3: many fixes"
* tag 'rtc-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (36 commits)
rtc: ds1307: update reference to removed CONFIG_RTC_DRV_DS1307_HWMON
platform/x86: amd-pmc: Fix S0i3 wakeup with alarmtimer
rtc: s35390a: fix typo in comment
rtc: cmos: unregister HPET IRQ handler on probe failure
rtc: ds1307: Fix off-by-one issue with wday for rx8130
dt-bindings: rtc: ds1307: Add epson,rx8901
rtc: bq32000: add delay between RTC reads
rtc: m41t93: Add watchdog support
rtc: m41t93: Add square wave clock provider support
rtc: m41t93: Add alarm support
rtc: m41t93: migrate to regmap api for register access
rtc: m41t93: add device tree support
dt-bindings: rtc: Add ST m41t93
rtc: ds1307: add support for clock provider in ds1307
rtc: mv: add suspend/resume support for wakeup
rtc: aspeed: add AST2700 compatible
dt-bindings: rtc: add ASPEED AST2700 compatible
rtc: interface: fix typos in rtc_handle_legacy_irq() documentation
rtc: msc313: fix NULL deref in shared IRQ handler at probe
rtc: remove unused pcap driver
...
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 207 |
1 files changed, 174 insertions, 33 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 7205c59ff729..0707ded5368b 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -269,6 +269,16 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) if (tmp & DS1338_BIT_OSF) return -EINVAL; break; + case ds_1337: + case ds_1339: + case ds_1341: + case ds_3231: + ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp); + if (ret) + return ret; + if (tmp & DS1337_BIT_OSF) + return -EINVAL; + break; case ds_1340: if (tmp & DS1340_BIT_nEOSC) return -EINVAL; @@ -279,13 +289,6 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) if (tmp & DS1340_BIT_OSF) return -EINVAL; break; - case ds_1341: - ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp); - if (ret) - return ret; - if (tmp & DS1337_BIT_OSF) - return -EINVAL; - break; case ds_1388: ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp); if (ret) @@ -308,7 +311,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_hour = bcd2bin(tmp); /* rx8130 is bit position, not BCD */ if (ds1307->type == rx_8130) - t->tm_wday = fls(regs[DS1307_REG_WDAY] & 0x7f); + t->tm_wday = fls(regs[DS1307_REG_WDAY] & 0x7f) - 1; else t->tm_wday = bcd2bin(regs[DS1307_REG_WDAY] & 0x07) - 1; t->tm_mday = bcd2bin(regs[DS1307_REG_MDAY] & 0x3f); @@ -380,14 +383,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL, DS1338_BIT_OSF, 0); break; - case ds_1340: - regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG, - DS1340_BIT_OSF, 0); - break; + case ds_1337: + case ds_1339: case ds_1341: + case ds_3231: regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS, DS1337_BIT_OSF, 0); break; + case ds_1340: + regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG, + DS1340_BIT_OSF, 0); + break; case ds_1388: regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG, DS1388_BIT_OSF, 0); @@ -1063,24 +1069,24 @@ static const struct chip_desc chips[last_ds_type] = { }; static const struct i2c_device_id ds1307_id[] = { - { "ds1307", ds_1307 }, - { "ds1308", ds_1308 }, - { "ds1337", ds_1337 }, - { "ds1338", ds_1338 }, - { "ds1339", ds_1339 }, - { "ds1388", ds_1388 }, - { "ds1340", ds_1340 }, - { "ds1341", ds_1341 }, - { "ds3231", ds_3231 }, - { "m41t0", m41t0 }, - { "m41t00", m41t00 }, - { "m41t11", m41t11 }, - { "mcp7940x", mcp794xx }, - { "mcp7941x", mcp794xx }, - { "pt7c4338", ds_1307 }, - { "rx8025", rx_8025 }, - { "isl12057", ds_1337 }, - { "rx8130", rx_8130 }, + { .name = "ds1307", .driver_data = ds_1307 }, + { .name = "ds1308", .driver_data = ds_1308 }, + { .name = "ds1337", .driver_data = ds_1337 }, + { .name = "ds1338", .driver_data = ds_1338 }, + { .name = "ds1339", .driver_data = ds_1339 }, + { .name = "ds1388", .driver_data = ds_1388 }, + { .name = "ds1340", .driver_data = ds_1340 }, + { .name = "ds1341", .driver_data = ds_1341 }, + { .name = "ds3231", .driver_data = ds_3231 }, + { .name = "m41t0", .driver_data = m41t0 }, + { .name = "m41t00", .driver_data = m41t00 }, + { .name = "m41t11", .driver_data = m41t11 }, + { .name = "mcp7940x", .driver_data = mcp794xx }, + { .name = "mcp7941x", .driver_data = mcp794xx }, + { .name = "pt7c4338", .driver_data = ds_1307 }, + { .name = "rx8025", .driver_data = rx_8025 }, + { .name = "isl12057", .driver_data = ds_1337 }, + { .name = "rx8130", .driver_data = rx_8130 }, { } }; MODULE_DEVICE_TABLE(i2c, ds1307_id); @@ -1409,7 +1415,7 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307) { } -#endif /* CONFIG_RTC_DRV_DS1307_HWMON */ +#endif /* IS_REACHABLE(CONFIG_HWMON) */ /*----------------------------------------------------------------------*/ @@ -1658,18 +1664,153 @@ static int ds3231_clks_register(struct ds1307 *ds1307) return 0; } +/* ds1307 RTC clock output support */ +static unsigned long ds1307_clk_rates[] = { + 1, + 4096, + 8192, + 32768, +}; + +static unsigned long ds1307_clk_sqw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int ret; + unsigned int rate_id; + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &rate_id); + if (ret) + return ret; + + rate_id &= (DS1307_BIT_RS1 | DS1307_BIT_RS0); + + return ds1307_clk_rates[rate_id]; +} + +static int ds1307_clk_sqw_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ds1307_clk_rates); i++) { + if (req->rate <= ds1307_clk_rates[i]) { + req->rate = ds1307_clk_rates[i]; + return 0; + } + } + + /* Default rate 1Hz */ + req->rate = ds1307_clk_rates[0]; + + return 0; +} + +static int ds1307_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int id, ret; + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + for (id = 0; id < ARRAY_SIZE(ds1307_clk_rates); id++) { + if (ds1307_clk_rates[id] == rate) + break; + } + + if (id >= ARRAY_SIZE(ds1307_clk_rates)) + return -EINVAL; + + ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL, + DS1307_BIT_RS0 | DS1307_BIT_RS1, id); + + return ret; +} + +static int ds1307_clk_sqw_prepare(struct clk_hw *hw) +{ + int ret; + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL, + DS1307_BIT_SQWE, DS1307_BIT_SQWE); + + return ret; +} + +static void ds1307_clk_sqw_unprepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL, + DS1307_BIT_SQWE, ~DS1307_BIT_SQWE); +} + +static int ds1307_clk_sqw_is_prepared(struct clk_hw *hw) +{ + int ret; + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + unsigned int status; + + ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &status); + if (ret) + return ret; + + return !!(status & DS1307_BIT_SQWE); +} + +static const struct clk_ops ds1307_clk_sqw_ops = { + .prepare = ds1307_clk_sqw_prepare, + .unprepare = ds1307_clk_sqw_unprepare, + .is_prepared = ds1307_clk_sqw_is_prepared, + .recalc_rate = ds1307_clk_sqw_recalc_rate, + .set_rate = ds1307_clk_sqw_set_rate, + .determine_rate = ds1307_clk_sqw_determine_rate, +}; + +static int rtc_ds1307_clks_register(struct ds1307 *ds1307) +{ + struct device_node *node = ds1307->dev->of_node; + struct clk *clk; + struct clk_init_data init = {0}; + + init.name = "ds1307_clk_sqw"; + init.ops = &ds1307_clk_sqw_ops; + + ds1307->clks[0].init = &init; + + /* Register the clock with CCF */ + clk = devm_clk_register(ds1307->dev, &ds1307->clks[0]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + if (node) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return 0; +} + static void ds1307_clks_register(struct ds1307 *ds1307) { int ret; - if (ds1307->type != ds_3231) + switch (ds1307->type) { + case ds_3231: + ret = ds3231_clks_register(ds1307); + break; + + case ds_1307: + ret = rtc_ds1307_clks_register(ds1307); + break; + + default: return; + } - ret = ds3231_clks_register(ds1307); if (ret) { dev_warn(ds1307->dev, "unable to register clock device %d\n", ret); } + } #else |
