From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/rtc/rtc-ds1307.c | 1648 +++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 986 insertions(+), 662 deletions(-) diff --git a/kernel/drivers/rtc/rtc-ds1307.c b/kernel/drivers/rtc/rtc-ds1307.c index 94d3177..07a9cc9 100644 --- a/kernel/drivers/rtc/rtc-ds1307.c +++ b/kernel/drivers/rtc/rtc-ds1307.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips. * @@ -5,10 +6,6 @@ * Copyright (C) 2006 David Brownell * Copyright (C) 2009 Matthias Fuchs (rx8025 support) * Copyright (C) 2012 Bertrand Achard (nvram access fixes) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/acpi.h> @@ -25,6 +22,7 @@ #include <linux/hwmon-sysfs.h> #include <linux/clk-provider.h> #include <linux/regmap.h> +#include <linux/watchdog.h> /* * We can't determine type by probing, but if we expect pre-Linux code @@ -114,6 +112,60 @@ # define RX8025_BIT_VDET 0x40 # define RX8025_BIT_XST 0x20 +#define RX8130_REG_ALARM_MIN 0x17 +#define RX8130_REG_ALARM_HOUR 0x18 +#define RX8130_REG_ALARM_WEEK_OR_DAY 0x19 +#define RX8130_REG_EXTENSION 0x1c +#define RX8130_REG_EXTENSION_WADA BIT(3) +#define RX8130_REG_FLAG 0x1d +#define RX8130_REG_FLAG_VLF BIT(1) +#define RX8130_REG_FLAG_AF BIT(3) +#define RX8130_REG_CONTROL0 0x1e +#define RX8130_REG_CONTROL0_AIE BIT(3) +#define RX8130_REG_CONTROL1 0x1f +#define RX8130_REG_CONTROL1_INIEN BIT(4) +#define RX8130_REG_CONTROL1_CHGEN BIT(5) + +#define MCP794XX_REG_CONTROL 0x07 +# define MCP794XX_BIT_ALM0_EN 0x10 +# define MCP794XX_BIT_ALM1_EN 0x20 +#define MCP794XX_REG_ALARM0_BASE 0x0a +#define MCP794XX_REG_ALARM0_CTRL 0x0d +#define MCP794XX_REG_ALARM1_BASE 0x11 +#define MCP794XX_REG_ALARM1_CTRL 0x14 +# define MCP794XX_BIT_ALMX_IF BIT(3) +# define MCP794XX_BIT_ALMX_C0 BIT(4) +# define MCP794XX_BIT_ALMX_C1 BIT(5) +# define MCP794XX_BIT_ALMX_C2 BIT(6) +# define MCP794XX_BIT_ALMX_POL BIT(7) +# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \ + MCP794XX_BIT_ALMX_C1 | \ + MCP794XX_BIT_ALMX_C2) + +#define M41TXX_REG_CONTROL 0x07 +# define M41TXX_BIT_OUT BIT(7) +# define M41TXX_BIT_FT BIT(6) +# define M41TXX_BIT_CALIB_SIGN BIT(5) +# define M41TXX_M_CALIBRATION GENMASK(4, 0) + +#define DS1388_REG_WDOG_HUN_SECS 0x08 +#define DS1388_REG_WDOG_SECS 0x09 +#define DS1388_REG_FLAG 0x0b +# define DS1388_BIT_WF BIT(6) +# define DS1388_BIT_OSF BIT(7) +#define DS1388_REG_CONTROL 0x0c +# define DS1388_BIT_RST BIT(0) +# define DS1388_BIT_WDE BIT(1) +# define DS1388_BIT_nEOSC BIT(7) + +/* negative offset step is -2.034ppm */ +#define M41TXX_NEG_OFFSET_STEP_PPB 2034 +/* positive offset step is +4.068ppm */ +#define M41TXX_POS_OFFSET_STEP_PPB 4068 +/* Min and max values supported with 'offset' interface by M41TXX */ +#define M41TXX_MIN_OFFSET ((-31) * M41TXX_NEG_OFFSET_STEP_PPB) +#define M41TXX_MAX_OFFSET ((31) * M41TXX_POS_OFFSET_STEP_PPB) + struct ds1307 { enum ds_type type; unsigned long flags; @@ -142,19 +194,776 @@ u16 trickle_charger_reg; u8 (*do_trickle_setup)(struct ds1307 *, u32, bool); + /* Does the RTC require trickle-resistor-ohms to select the value of + * the resistor between Vcc and Vbackup? + */ + bool requires_trickle_resistor; + /* Some RTC's batteries and supercaps were charged by default, others + * allow charging but were not configured previously to do so. + * Remember this behavior to stay backwards compatible. + */ + bool charge_default; }; -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 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); -static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t); -static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled); -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 const struct chip_desc chips[last_ds_type]; + +static int ds1307_get_time(struct device *dev, struct rtc_time *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + int tmp, ret; + const struct chip_desc *chip = &chips[ds1307->type]; + u8 regs[7]; + + if (ds1307->type == rx_8130) { + unsigned int regflag; + ret = regmap_read(ds1307->regmap, RX8130_REG_FLAG, ®flag); + if (ret) { + dev_err(dev, "%s error %d\n", "read", ret); + return ret; + } + + if (regflag & RX8130_REG_FLAG_VLF) { + dev_warn_once(dev, "oscillator failed, set time!\n"); + return -EINVAL; + } + } + + /* read the RTC date and time registers all at once */ + ret = regmap_bulk_read(ds1307->regmap, chip->offset, regs, + sizeof(regs)); + if (ret) { + dev_err(dev, "%s error %d\n", "read", ret); + return ret; + } + + dev_dbg(dev, "%s: %7ph\n", "read", regs); + + /* if oscillator fail bit is set, no data can be trusted */ + if (ds1307->type == m41t0 && + regs[DS1307_REG_MIN] & M41T0_BIT_OF) { + dev_warn_once(dev, "oscillator failed, set time!\n"); + return -EINVAL; + } + + tmp = regs[DS1307_REG_SECS]; + switch (ds1307->type) { + case ds_1307: + case m41t0: + case m41t00: + case m41t11: + if (tmp & DS1307_BIT_CH) + return -EINVAL; + break; + case ds_1308: + case ds_1338: + if (tmp & DS1307_BIT_CH) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &tmp); + if (ret) + return ret; + if (tmp & DS1338_BIT_OSF) + return -EINVAL; + break; + case ds_1340: + if (tmp & DS1340_BIT_nEOSC) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp); + if (ret) + return ret; + if (tmp & DS1340_BIT_OSF) + return -EINVAL; + break; + case ds_1388: + ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp); + if (ret) + return ret; + if (tmp & DS1388_BIT_OSF) + return -EINVAL; + break; + case mcp794xx: + if (!(tmp & MCP794XX_BIT_ST)) + return -EINVAL; + + break; + default: + break; + } + + t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f); + t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f); + tmp = regs[DS1307_REG_HOUR] & 0x3f; + 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); + else + t->tm_wday = bcd2bin(regs[DS1307_REG_WDAY] & 0x07) - 1; + t->tm_mday = bcd2bin(regs[DS1307_REG_MDAY] & 0x3f); + tmp = regs[DS1307_REG_MONTH] & 0x1f; + t->tm_mon = bcd2bin(tmp) - 1; + t->tm_year = bcd2bin(regs[DS1307_REG_YEAR]) + 100; + + if (regs[chip->century_reg] & chip->century_bit && + IS_ENABLED(CONFIG_RTC_DRV_DS1307_CENTURY)) + t->tm_year += 100; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "read", t->tm_sec, t->tm_min, + t->tm_hour, t->tm_mday, + t->tm_mon, t->tm_year, t->tm_wday); + + return 0; +} + +static int ds1307_set_time(struct device *dev, struct rtc_time *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + const struct chip_desc *chip = &chips[ds1307->type]; + int result; + int tmp; + u8 regs[7]; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "write", t->tm_sec, t->tm_min, + t->tm_hour, t->tm_mday, + t->tm_mon, t->tm_year, t->tm_wday); + + if (t->tm_year < 100) + return -EINVAL; + +#ifdef CONFIG_RTC_DRV_DS1307_CENTURY + if (t->tm_year > (chip->century_bit ? 299 : 199)) + return -EINVAL; +#else + if (t->tm_year > 199) + return -EINVAL; +#endif + + regs[DS1307_REG_SECS] = bin2bcd(t->tm_sec); + regs[DS1307_REG_MIN] = bin2bcd(t->tm_min); + regs[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); + /* rx8130 is bit position, not BCD */ + if (ds1307->type == rx_8130) + regs[DS1307_REG_WDAY] = 1 << t->tm_wday; + else + regs[DS1307_REG_WDAY] = bin2bcd(t->tm_wday + 1); + regs[DS1307_REG_MDAY] = bin2bcd(t->tm_mday); + regs[DS1307_REG_MONTH] = bin2bcd(t->tm_mon + 1); + + /* assume 20YY not 19YY */ + tmp = t->tm_year - 100; + regs[DS1307_REG_YEAR] = bin2bcd(tmp); + + if (chip->century_enable_bit) + regs[chip->century_reg] |= chip->century_enable_bit; + if (t->tm_year > 199 && chip->century_bit) + regs[chip->century_reg] |= chip->century_bit; + + switch (ds1307->type) { + case ds_1308: + case ds_1338: + 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_1388: + regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG, + DS1388_BIT_OSF, 0); + break; + case mcp794xx: + /* + * these bits were cleared when preparing the date/time + * values and need to be set again before writing the + * regsfer out to the device. + */ + regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST; + regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN; + break; + default: + break; + } + + dev_dbg(dev, "%s: %7ph\n", "write", regs); + + result = regmap_bulk_write(ds1307->regmap, chip->offset, regs, + sizeof(regs)); + if (result) { + dev_err(dev, "%s error %d\n", "write", result); + return result; + } + + if (ds1307->type == rx_8130) { + /* clear Voltage Loss Flag as data is available now */ + result = regmap_write(ds1307->regmap, RX8130_REG_FLAG, + ~(u8)RX8130_REG_FLAG_VLF); + if (result) { + dev_err(dev, "%s error %d\n", "write", result); + return result; + } + } + + return 0; +} + +static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + int ret; + u8 regs[9]; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + /* read all ALARM1, ALARM2, and status registers at once */ + ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, + regs, sizeof(regs)); + if (ret) { + dev_err(dev, "%s error %d\n", "alarm read", ret); + return ret; + } + + dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read", + ®s[0], ®s[4], ®s[7]); + + /* + * report alarm time (ALARM1); assume 24 hour and day-of-month modes, + * and that all four fields are checked matches + */ + t->time.tm_sec = bcd2bin(regs[0] & 0x7f); + t->time.tm_min = bcd2bin(regs[1] & 0x7f); + t->time.tm_hour = bcd2bin(regs[2] & 0x3f); + t->time.tm_mday = bcd2bin(regs[3] & 0x3f); + + /* ... and status */ + t->enabled = !!(regs[7] & DS1337_BIT_A1IE); + t->pending = !!(regs[8] & DS1337_BIT_A1I); + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, enabled=%d, pending=%d\n", + "alarm read", t->time.tm_sec, t->time.tm_min, + t->time.tm_hour, t->time.tm_mday, + t->enabled, t->pending); + + return 0; +} + +static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + unsigned char regs[9]; + u8 control, status; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, enabled=%d, pending=%d\n", + "alarm set", t->time.tm_sec, t->time.tm_min, + t->time.tm_hour, t->time.tm_mday, + t->enabled, t->pending); + + /* read current status of both alarms and the chip */ + ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, regs, + sizeof(regs)); + if (ret) { + dev_err(dev, "%s error %d\n", "alarm write", ret); + return ret; + } + control = regs[7]; + status = regs[8]; + + dev_dbg(dev, "%s: %4ph, %3ph, %02x %02x\n", "alarm set (old status)", + ®s[0], ®s[4], control, status); + + /* set ALARM1, using 24 hour and day-of-month modes */ + regs[0] = bin2bcd(t->time.tm_sec); + regs[1] = bin2bcd(t->time.tm_min); + regs[2] = bin2bcd(t->time.tm_hour); + regs[3] = bin2bcd(t->time.tm_mday); + + /* set ALARM2 to non-garbage */ + regs[4] = 0; + regs[5] = 0; + regs[6] = 0; + + /* disable alarms */ + regs[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE); + regs[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); + + ret = regmap_bulk_write(ds1307->regmap, DS1339_REG_ALARM1_SECS, regs, + sizeof(regs)); + if (ret) { + dev_err(dev, "can't set alarm time\n"); + return ret; + } + + /* optionally enable ALARM1 */ + if (t->enabled) { + dev_dbg(dev, "alarm IRQ armed\n"); + regs[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */ + regmap_write(ds1307->regmap, DS1337_REG_CONTROL, regs[7]); + } + + return 0; +} + +static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -ENOTTY; + + return regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL, + DS1337_BIT_A1IE, + enabled ? DS1337_BIT_A1IE : 0); +} + +static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, u32 ohms, bool diode) +{ + u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE : + DS1307_TRICKLE_CHARGER_NO_DIODE; + + setup |= DS13XX_TRICKLE_CHARGER_MAGIC; + + switch (ohms) { + case 250: + setup |= DS1307_TRICKLE_CHARGER_250_OHM; + break; + case 2000: + setup |= DS1307_TRICKLE_CHARGER_2K_OHM; + break; + case 4000: + setup |= DS1307_TRICKLE_CHARGER_4K_OHM; + break; + default: + dev_warn(ds1307->dev, + "Unsupported ohm value %u in dt\n", ohms); + return 0; + } + return setup; +} + +static u8 do_trickle_setup_rx8130(struct ds1307 *ds1307, u32 ohms, bool diode) +{ + /* make sure that the backup battery is enabled */ + u8 setup = RX8130_REG_CONTROL1_INIEN; + if (diode) + setup |= RX8130_REG_CONTROL1_CHGEN; + + return setup; +} + +static irqreturn_t rx8130_irq(int irq, void *dev_id) +{ + struct ds1307 *ds1307 = dev_id; + struct mutex *lock = &ds1307->rtc->ops_lock; + u8 ctl[3]; + int ret; + + mutex_lock(lock); + + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, + sizeof(ctl)); + if (ret < 0) + goto out; + if (!(ctl[1] & RX8130_REG_FLAG_AF)) + goto out; + ctl[1] &= ~RX8130_REG_FLAG_AF; + ctl[2] &= ~RX8130_REG_CONTROL0_AIE; + + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, + sizeof(ctl)); + if (ret < 0) + goto out; + + rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); + +out: + mutex_unlock(lock); + + return IRQ_HANDLED; +} + +static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 ald[3], ctl[3]; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + /* Read alarm registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, + sizeof(ald)); + if (ret < 0) + return ret; + + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, + sizeof(ctl)); + if (ret < 0) + return ret; + + t->enabled = !!(ctl[2] & RX8130_REG_CONTROL0_AIE); + t->pending = !!(ctl[1] & RX8130_REG_FLAG_AF); + + /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ + t->time.tm_sec = -1; + t->time.tm_min = bcd2bin(ald[0] & 0x7f); + t->time.tm_hour = bcd2bin(ald[1] & 0x7f); + t->time.tm_wday = -1; + t->time.tm_mday = bcd2bin(ald[2] & 0x7f); + t->time.tm_mon = -1; + t->time.tm_year = -1; + t->time.tm_yday = -1; + t->time.tm_isdst = -1; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d enabled=%d\n", + __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled); + + return 0; +} + +static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 ald[3], ctl[3]; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d pending=%d\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, + t->enabled, t->pending); + + /* Read control registers. */ + ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, + sizeof(ctl)); + if (ret < 0) + return ret; + + ctl[0] &= RX8130_REG_EXTENSION_WADA; + ctl[1] &= ~RX8130_REG_FLAG_AF; + ctl[2] &= ~RX8130_REG_CONTROL0_AIE; + + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, + sizeof(ctl)); + if (ret < 0) + return ret; + + /* Hardware alarm precision is 1 minute! */ + ald[0] = bin2bcd(t->time.tm_min); + ald[1] = bin2bcd(t->time.tm_hour); + ald[2] = bin2bcd(t->time.tm_mday); + + ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, + sizeof(ald)); + if (ret < 0) + return ret; + + if (!t->enabled) + return 0; + + ctl[2] |= RX8130_REG_CONTROL0_AIE; + + return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, ctl[2]); +} + +static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + int ret, reg; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + ret = regmap_read(ds1307->regmap, RX8130_REG_CONTROL0, ®); + if (ret < 0) + return ret; + + if (enabled) + reg |= RX8130_REG_CONTROL0_AIE; + else + reg &= ~RX8130_REG_CONTROL0_AIE; + + return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg); +} + +static irqreturn_t mcp794xx_irq(int irq, void *dev_id) +{ + struct ds1307 *ds1307 = dev_id; + struct mutex *lock = &ds1307->rtc->ops_lock; + int reg, ret; + + mutex_lock(lock); + + /* Check and clear alarm 0 interrupt flag. */ + ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, ®); + if (ret) + goto out; + if (!(reg & MCP794XX_BIT_ALMX_IF)) + goto out; + reg &= ~MCP794XX_BIT_ALMX_IF; + ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg); + if (ret) + goto out; + + /* Disable alarm 0. */ + ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, + MCP794XX_BIT_ALM0_EN, 0); + if (ret) + goto out; + + rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); + +out: + mutex_unlock(lock); + + return IRQ_HANDLED; +} + +static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 regs[10]; + int ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + /* Read control and alarm 0 registers. */ + ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, + sizeof(regs)); + if (ret) + return ret; + + t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN); + + /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ + t->time.tm_sec = bcd2bin(regs[3] & 0x7f); + t->time.tm_min = bcd2bin(regs[4] & 0x7f); + t->time.tm_hour = bcd2bin(regs[5] & 0x3f); + t->time.tm_wday = bcd2bin(regs[6] & 0x7) - 1; + t->time.tm_mday = bcd2bin(regs[7] & 0x3f); + t->time.tm_mon = bcd2bin(regs[8] & 0x1f) - 1; + t->time.tm_year = -1; + t->time.tm_yday = -1; + t->time.tm_isdst = -1; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d polarity=%d irq=%d match=%lu\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, + !!(regs[6] & MCP794XX_BIT_ALMX_POL), + !!(regs[6] & MCP794XX_BIT_ALMX_IF), + (regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4); + + return 0; +} + +/* + * We may have a random RTC weekday, therefore calculate alarm weekday based + * on current weekday we read from the RTC timekeeping regs + */ +static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm) +{ + struct rtc_time tm_now; + int days_now, days_alarm, ret; + + ret = ds1307_get_time(dev, &tm_now); + if (ret) + return ret; + + days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60); + days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60); + + return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1; +} + +static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + unsigned char regs[10]; + int wday, ret; + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + wday = mcp794xx_alm_weekday(dev, &t->time); + if (wday < 0) + return wday; + + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " + "enabled=%d pending=%d\n", __func__, + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, + t->enabled, t->pending); + + /* Read control and alarm 0 registers. */ + ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, + sizeof(regs)); + if (ret) + return ret; + + /* Set alarm 0, using 24-hour and day-of-month modes. */ + regs[3] = bin2bcd(t->time.tm_sec); + regs[4] = bin2bcd(t->time.tm_min); + regs[5] = bin2bcd(t->time.tm_hour); + regs[6] = wday; + regs[7] = bin2bcd(t->time.tm_mday); + regs[8] = bin2bcd(t->time.tm_mon + 1); + + /* Clear the alarm 0 interrupt flag. */ + regs[6] &= ~MCP794XX_BIT_ALMX_IF; + /* Set alarm match: second, minute, hour, day, date, month. */ + regs[6] |= MCP794XX_MSK_ALMX_MATCH; + /* Disable interrupt. We will not enable until completely programmed */ + regs[0] &= ~MCP794XX_BIT_ALM0_EN; + + ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs, + sizeof(regs)); + if (ret) + return ret; + + if (!t->enabled) + return 0; + regs[0] |= MCP794XX_BIT_ALM0_EN; + return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]); +} + +static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + + if (!test_bit(HAS_ALARM, &ds1307->flags)) + return -EINVAL; + + return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, + MCP794XX_BIT_ALM0_EN, + 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 * M41TXX_POS_OFFSET_STEP_PPB); + else + *offset = -(val * M41TXX_NEG_OFFSET_STEP_PPB); + + 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; + + if (offset >= 0) { + ctrl_reg = DIV_ROUND_CLOSEST(offset, + M41TXX_POS_OFFSET_STEP_PPB); + ctrl_reg |= M41TXX_BIT_CALIB_SIGN; + } else { + ctrl_reg = DIV_ROUND_CLOSEST(abs(offset), + M41TXX_NEG_OFFSET_STEP_PPB); + } + + return regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL, + M41TXX_M_CALIBRATION | M41TXX_BIT_CALIB_SIGN, + ctrl_reg); +} + +#ifdef CONFIG_WATCHDOG_CORE +static int ds1388_wdt_start(struct watchdog_device *wdt_dev) +{ + struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev); + u8 regs[2]; + int ret; + + ret = regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG, + DS1388_BIT_WF, 0); + if (ret) + return ret; + + ret = regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL, + DS1388_BIT_WDE | DS1388_BIT_RST, 0); + if (ret) + return ret; + + /* + * watchdog timeouts are measured in seconds. So ignore hundredths of + * seconds field. + */ + regs[0] = 0; + regs[1] = bin2bcd(wdt_dev->timeout); + + ret = regmap_bulk_write(ds1307->regmap, DS1388_REG_WDOG_HUN_SECS, regs, + sizeof(regs)); + if (ret) + return ret; + + return regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL, + DS1388_BIT_WDE | DS1388_BIT_RST, + DS1388_BIT_WDE | DS1388_BIT_RST); +} + +static int ds1388_wdt_stop(struct watchdog_device *wdt_dev) +{ + struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev); + + return regmap_update_bits(ds1307->regmap, DS1388_REG_CONTROL, + DS1388_BIT_WDE | DS1388_BIT_RST, 0); +} + +static int ds1388_wdt_ping(struct watchdog_device *wdt_dev) +{ + struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev); + u8 regs[2]; + + return regmap_bulk_read(ds1307->regmap, DS1388_REG_WDOG_HUN_SECS, regs, + sizeof(regs)); +} + +static int ds1388_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int val) +{ + struct ds1307 *ds1307 = watchdog_get_drvdata(wdt_dev); + u8 regs[2]; + + wdt_dev->timeout = val; + regs[0] = 0; + regs[1] = bin2bcd(wdt_dev->timeout); + + return regmap_bulk_write(ds1307->regmap, DS1388_REG_WDOG_HUN_SECS, regs, + sizeof(regs)); +} +#endif static const struct rtc_class_ops rx8130_rtc_ops = { .read_time = ds1307_get_time, @@ -170,6 +979,16 @@ .read_alarm = mcp794xx_read_alarm, .set_alarm = mcp794xx_set_alarm, .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] = { @@ -197,6 +1016,8 @@ .bbsqi_bit = DS1339_BIT_BBSQI, .trickle_charger_reg = 0x10, .do_trickle_setup = &do_trickle_setup_ds1339, + .requires_trickle_resistor = true, + .charge_default = true, }, [ds_1340] = { .century_reg = DS1307_REG_HOUR, @@ -204,6 +1025,8 @@ .century_bit = DS1340_BIT_CENTURY, .do_trickle_setup = &do_trickle_setup_ds1339, .trickle_charger_reg = 0x08, + .requires_trickle_resistor = true, + .charge_default = true, }, [ds_1341] = { .century_reg = DS1307_REG_MONTH, @@ -227,11 +1050,20 @@ .offset = 0x10, .irq_handler = rx8130_irq, .rtc_ops = &rx8130_rtc_ops, + .trickle_charger_reg = RX8130_REG_CONTROL1, + .do_trickle_setup = &do_trickle_setup_rx8130, + }, + [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, @@ -406,238 +1238,6 @@ /*----------------------------------------------------------------------*/ -static int ds1307_get_time(struct device *dev, struct rtc_time *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - int tmp, ret; - const struct chip_desc *chip = &chips[ds1307->type]; - u8 regs[7]; - - /* read the RTC date and time registers all at once */ - ret = regmap_bulk_read(ds1307->regmap, chip->offset, regs, - sizeof(regs)); - if (ret) { - dev_err(dev, "%s error %d\n", "read", ret); - return ret; - } - - dev_dbg(dev, "%s: %7ph\n", "read", regs); - - /* if oscillator fail bit is set, no data can be trusted */ - if (ds1307->type == m41t0 && - regs[DS1307_REG_MIN] & M41T0_BIT_OF) { - dev_warn_once(dev, "oscillator failed, set time!\n"); - return -EINVAL; - } - - t->tm_sec = bcd2bin(regs[DS1307_REG_SECS] & 0x7f); - t->tm_min = bcd2bin(regs[DS1307_REG_MIN] & 0x7f); - tmp = regs[DS1307_REG_HOUR] & 0x3f; - 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); - else - t->tm_wday = bcd2bin(regs[DS1307_REG_WDAY] & 0x07) - 1; - t->tm_mday = bcd2bin(regs[DS1307_REG_MDAY] & 0x3f); - tmp = regs[DS1307_REG_MONTH] & 0x1f; - t->tm_mon = bcd2bin(tmp) - 1; - t->tm_year = bcd2bin(regs[DS1307_REG_YEAR]) + 100; - - if (regs[chip->century_reg] & chip->century_bit && - IS_ENABLED(CONFIG_RTC_DRV_DS1307_CENTURY)) - t->tm_year += 100; - - dev_dbg(dev, "%s secs=%d, mins=%d, " - "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", - "read", t->tm_sec, t->tm_min, - t->tm_hour, t->tm_mday, - t->tm_mon, t->tm_year, t->tm_wday); - - return 0; -} - -static int ds1307_set_time(struct device *dev, struct rtc_time *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - const struct chip_desc *chip = &chips[ds1307->type]; - int result; - int tmp; - u8 regs[7]; - - dev_dbg(dev, "%s secs=%d, mins=%d, " - "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", - "write", t->tm_sec, t->tm_min, - t->tm_hour, t->tm_mday, - t->tm_mon, t->tm_year, t->tm_wday); - - if (t->tm_year < 100) - return -EINVAL; - -#ifdef CONFIG_RTC_DRV_DS1307_CENTURY - if (t->tm_year > (chip->century_bit ? 299 : 199)) - return -EINVAL; -#else - if (t->tm_year > 199) - return -EINVAL; -#endif - - regs[DS1307_REG_SECS] = bin2bcd(t->tm_sec); - regs[DS1307_REG_MIN] = bin2bcd(t->tm_min); - regs[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); - /* rx8130 is bit position, not BCD */ - if (ds1307->type == rx_8130) - regs[DS1307_REG_WDAY] = 1 << t->tm_wday; - else - regs[DS1307_REG_WDAY] = bin2bcd(t->tm_wday + 1); - regs[DS1307_REG_MDAY] = bin2bcd(t->tm_mday); - regs[DS1307_REG_MONTH] = bin2bcd(t->tm_mon + 1); - - /* assume 20YY not 19YY */ - tmp = t->tm_year - 100; - regs[DS1307_REG_YEAR] = bin2bcd(tmp); - - if (chip->century_enable_bit) - regs[chip->century_reg] |= chip->century_enable_bit; - if (t->tm_year > 199 && chip->century_bit) - regs[chip->century_reg] |= chip->century_bit; - - if (ds1307->type == mcp794xx) { - /* - * these bits were cleared when preparing the date/time - * values and need to be set again before writing the - * regsfer out to the device. - */ - regs[DS1307_REG_SECS] |= MCP794XX_BIT_ST; - regs[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN; - } - - dev_dbg(dev, "%s: %7ph\n", "write", regs); - - result = regmap_bulk_write(ds1307->regmap, chip->offset, regs, - sizeof(regs)); - if (result) { - dev_err(dev, "%s error %d\n", "write", result); - return result; - } - return 0; -} - -static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - int ret; - u8 regs[9]; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - /* read all ALARM1, ALARM2, and status registers at once */ - ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, - regs, sizeof(regs)); - if (ret) { - dev_err(dev, "%s error %d\n", "alarm read", ret); - return ret; - } - - dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read", - ®s[0], ®s[4], ®s[7]); - - /* - * report alarm time (ALARM1); assume 24 hour and day-of-month modes, - * and that all four fields are checked matches - */ - t->time.tm_sec = bcd2bin(regs[0] & 0x7f); - t->time.tm_min = bcd2bin(regs[1] & 0x7f); - t->time.tm_hour = bcd2bin(regs[2] & 0x3f); - t->time.tm_mday = bcd2bin(regs[3] & 0x3f); - - /* ... and status */ - t->enabled = !!(regs[7] & DS1337_BIT_A1IE); - t->pending = !!(regs[8] & DS1337_BIT_A1I); - - dev_dbg(dev, "%s secs=%d, mins=%d, " - "hours=%d, mday=%d, enabled=%d, pending=%d\n", - "alarm read", t->time.tm_sec, t->time.tm_min, - t->time.tm_hour, t->time.tm_mday, - t->enabled, t->pending); - - return 0; -} - -static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - unsigned char regs[9]; - u8 control, status; - int ret; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - dev_dbg(dev, "%s secs=%d, mins=%d, " - "hours=%d, mday=%d, enabled=%d, pending=%d\n", - "alarm set", t->time.tm_sec, t->time.tm_min, - t->time.tm_hour, t->time.tm_mday, - t->enabled, t->pending); - - /* read current status of both alarms and the chip */ - ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, regs, - sizeof(regs)); - if (ret) { - dev_err(dev, "%s error %d\n", "alarm write", ret); - return ret; - } - control = regs[7]; - status = regs[8]; - - dev_dbg(dev, "%s: %4ph, %3ph, %02x %02x\n", "alarm set (old status)", - ®s[0], ®s[4], control, status); - - /* set ALARM1, using 24 hour and day-of-month modes */ - regs[0] = bin2bcd(t->time.tm_sec); - regs[1] = bin2bcd(t->time.tm_min); - regs[2] = bin2bcd(t->time.tm_hour); - regs[3] = bin2bcd(t->time.tm_mday); - - /* set ALARM2 to non-garbage */ - regs[4] = 0; - regs[5] = 0; - regs[6] = 0; - - /* disable alarms */ - regs[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE); - regs[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - - ret = regmap_bulk_write(ds1307->regmap, DS1339_REG_ALARM1_SECS, regs, - sizeof(regs)); - if (ret) { - dev_err(dev, "can't set alarm time\n"); - return ret; - } - - /* optionally enable ALARM1 */ - if (t->enabled) { - dev_dbg(dev, "alarm IRQ armed\n"); - regs[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */ - regmap_write(ds1307->regmap, DS1337_REG_CONTROL, regs[7]); - } - - return 0; -} - -static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -ENOTTY; - - return regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL, - DS1337_BIT_A1IE, - enabled ? DS1337_BIT_A1IE : 0); -} - static const struct rtc_class_ops ds13xx_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, @@ -646,338 +1246,67 @@ .alarm_irq_enable = ds1307_alarm_irq_enable, }; -/*----------------------------------------------------------------------*/ - -/* - * Alarm support for rx8130 devices. - */ - -#define RX8130_REG_ALARM_MIN 0x07 -#define RX8130_REG_ALARM_HOUR 0x08 -#define RX8130_REG_ALARM_WEEK_OR_DAY 0x09 -#define RX8130_REG_EXTENSION 0x0c -#define RX8130_REG_EXTENSION_WADA BIT(3) -#define RX8130_REG_FLAG 0x0d -#define RX8130_REG_FLAG_AF BIT(3) -#define RX8130_REG_CONTROL0 0x0e -#define RX8130_REG_CONTROL0_AIE BIT(3) - -static irqreturn_t rx8130_irq(int irq, void *dev_id) +static ssize_t frequency_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct ds1307 *ds1307 = dev_id; - struct mutex *lock = &ds1307->rtc->ops_lock; - u8 ctl[3]; + struct ds1307 *ds1307 = dev_get_drvdata(dev->parent); + bool freq_test_en; int ret; - mutex_lock(lock); + ret = kstrtobool(buf, &freq_test_en); + if (ret) { + dev_err(dev, "Failed to store RTC Frequency Test attribute\n"); + return ret; + } - /* Read control registers. */ - ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); - if (ret < 0) - goto out; - if (!(ctl[1] & RX8130_REG_FLAG_AF)) - goto out; - ctl[1] &= ~RX8130_REG_FLAG_AF; - ctl[2] &= ~RX8130_REG_CONTROL0_AIE; + regmap_update_bits(ds1307->regmap, M41TXX_REG_CONTROL, M41TXX_BIT_FT, + freq_test_en ? M41TXX_BIT_FT : 0); - ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); - if (ret < 0) - goto out; - - rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); - -out: - mutex_unlock(lock); - - return IRQ_HANDLED; + return count; } -static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t) +static ssize_t frequency_test_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct ds1307 *ds1307 = dev_get_drvdata(dev); - u8 ald[3], ctl[3]; - int ret; + struct ds1307 *ds1307 = dev_get_drvdata(dev->parent); + unsigned int ctrl_reg; - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; + regmap_read(ds1307->regmap, M41TXX_REG_CONTROL, &ctrl_reg); - /* Read alarm registers. */ - ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, - sizeof(ald)); - if (ret < 0) - return ret; + return scnprintf(buf, PAGE_SIZE, (ctrl_reg & M41TXX_BIT_FT) ? "on\n" : + "off\n"); +} - /* Read control registers. */ - ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); - if (ret < 0) - return ret; +static DEVICE_ATTR_RW(frequency_test); - t->enabled = !!(ctl[2] & RX8130_REG_CONTROL0_AIE); - t->pending = !!(ctl[1] & RX8130_REG_FLAG_AF); +static struct attribute *rtc_freq_test_attrs[] = { + &dev_attr_frequency_test.attr, + NULL, +}; - /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ - t->time.tm_sec = -1; - t->time.tm_min = bcd2bin(ald[0] & 0x7f); - t->time.tm_hour = bcd2bin(ald[1] & 0x7f); - t->time.tm_wday = -1; - t->time.tm_mday = bcd2bin(ald[2] & 0x7f); - t->time.tm_mon = -1; - t->time.tm_year = -1; - t->time.tm_yday = -1; - t->time.tm_isdst = -1; +static const struct attribute_group rtc_freq_test_attr_group = { + .attrs = rtc_freq_test_attrs, +}; - dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d enabled=%d\n", - __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled); +static int ds1307_add_frequency_test(struct ds1307 *ds1307) +{ + int err; + + switch (ds1307->type) { + case m41t0: + case m41t00: + case m41t11: + err = rtc_add_group(ds1307->rtc, &rtc_freq_test_attr_group); + if (err) + return err; + break; + default: + break; + } return 0; -} - -static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - u8 ald[3], ctl[3]; - int ret; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " - "enabled=%d pending=%d\n", __func__, - t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, - t->enabled, t->pending); - - /* Read control registers. */ - ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); - if (ret < 0) - return ret; - - ctl[0] &= RX8130_REG_EXTENSION_WADA; - ctl[1] &= ~RX8130_REG_FLAG_AF; - ctl[2] &= ~RX8130_REG_CONTROL0_AIE; - - ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); - if (ret < 0) - return ret; - - /* Hardware alarm precision is 1 minute! */ - ald[0] = bin2bcd(t->time.tm_min); - ald[1] = bin2bcd(t->time.tm_hour); - ald[2] = bin2bcd(t->time.tm_mday); - - ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, - sizeof(ald)); - if (ret < 0) - return ret; - - if (!t->enabled) - return 0; - - ctl[2] |= RX8130_REG_CONTROL0_AIE; - - return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, ctl[2]); -} - -static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - int ret, reg; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - ret = regmap_read(ds1307->regmap, RX8130_REG_CONTROL0, ®); - if (ret < 0) - return ret; - - if (enabled) - reg |= RX8130_REG_CONTROL0_AIE; - else - reg &= ~RX8130_REG_CONTROL0_AIE; - - return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg); -} - -/*----------------------------------------------------------------------*/ - -/* - * Alarm support for mcp794xx devices. - */ - -#define MCP794XX_REG_CONTROL 0x07 -# define MCP794XX_BIT_ALM0_EN 0x10 -# define MCP794XX_BIT_ALM1_EN 0x20 -#define MCP794XX_REG_ALARM0_BASE 0x0a -#define MCP794XX_REG_ALARM0_CTRL 0x0d -#define MCP794XX_REG_ALARM1_BASE 0x11 -#define MCP794XX_REG_ALARM1_CTRL 0x14 -# define MCP794XX_BIT_ALMX_IF BIT(3) -# define MCP794XX_BIT_ALMX_C0 BIT(4) -# define MCP794XX_BIT_ALMX_C1 BIT(5) -# define MCP794XX_BIT_ALMX_C2 BIT(6) -# define MCP794XX_BIT_ALMX_POL BIT(7) -# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \ - MCP794XX_BIT_ALMX_C1 | \ - MCP794XX_BIT_ALMX_C2) - -static irqreturn_t mcp794xx_irq(int irq, void *dev_id) -{ - struct ds1307 *ds1307 = dev_id; - struct mutex *lock = &ds1307->rtc->ops_lock; - int reg, ret; - - mutex_lock(lock); - - /* Check and clear alarm 0 interrupt flag. */ - ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, ®); - if (ret) - goto out; - if (!(reg & MCP794XX_BIT_ALMX_IF)) - goto out; - reg &= ~MCP794XX_BIT_ALMX_IF; - ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg); - if (ret) - goto out; - - /* Disable alarm 0. */ - ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, - MCP794XX_BIT_ALM0_EN, 0); - if (ret) - goto out; - - rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); - -out: - mutex_unlock(lock); - - return IRQ_HANDLED; -} - -static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - u8 regs[10]; - int ret; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - /* Read control and alarm 0 registers. */ - ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, - sizeof(regs)); - if (ret) - return ret; - - t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN); - - /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ - t->time.tm_sec = bcd2bin(regs[3] & 0x7f); - t->time.tm_min = bcd2bin(regs[4] & 0x7f); - t->time.tm_hour = bcd2bin(regs[5] & 0x3f); - t->time.tm_wday = bcd2bin(regs[6] & 0x7) - 1; - t->time.tm_mday = bcd2bin(regs[7] & 0x3f); - t->time.tm_mon = bcd2bin(regs[8] & 0x1f) - 1; - t->time.tm_year = -1; - t->time.tm_yday = -1; - t->time.tm_isdst = -1; - - dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " - "enabled=%d polarity=%d irq=%d match=%lu\n", __func__, - t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, - !!(regs[6] & MCP794XX_BIT_ALMX_POL), - !!(regs[6] & MCP794XX_BIT_ALMX_IF), - (regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4); - - return 0; -} - -/* - * We may have a random RTC weekday, therefore calculate alarm weekday based - * on current weekday we read from the RTC timekeeping regs - */ -static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm) -{ - struct rtc_time tm_now; - int days_now, days_alarm, ret; - - ret = ds1307_get_time(dev, &tm_now); - if (ret) - return ret; - - days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60); - days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60); - - return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1; -} - -static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - unsigned char regs[10]; - int wday, ret; - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - wday = mcp794xx_alm_weekday(dev, &t->time); - if (wday < 0) - return wday; - - dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " - "enabled=%d pending=%d\n", __func__, - t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, - t->enabled, t->pending); - - /* Read control and alarm 0 registers. */ - ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, - sizeof(regs)); - if (ret) - return ret; - - /* Set alarm 0, using 24-hour and day-of-month modes. */ - regs[3] = bin2bcd(t->time.tm_sec); - regs[4] = bin2bcd(t->time.tm_min); - regs[5] = bin2bcd(t->time.tm_hour); - regs[6] = wday; - regs[7] = bin2bcd(t->time.tm_mday); - regs[8] = bin2bcd(t->time.tm_mon + 1); - - /* Clear the alarm 0 interrupt flag. */ - regs[6] &= ~MCP794XX_BIT_ALMX_IF; - /* Set alarm match: second, minute, hour, day, date, month. */ - regs[6] |= MCP794XX_MSK_ALMX_MATCH; - /* Disable interrupt. We will not enable until completely programmed */ - regs[0] &= ~MCP794XX_BIT_ALM0_EN; - - ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs, - sizeof(regs)); - if (ret) - return ret; - - if (!t->enabled) - return 0; - regs[0] |= MCP794XX_BIT_ALM0_EN; - return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]); -} - -static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct ds1307 *ds1307 = dev_get_drvdata(dev); - - if (!test_bit(HAS_ALARM, &ds1307->flags)) - return -EINVAL; - - return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL, - MCP794XX_BIT_ALM0_EN, - enabled ? MCP794XX_BIT_ALM0_EN : 0); } /*----------------------------------------------------------------------*/ @@ -1004,45 +1333,40 @@ /*----------------------------------------------------------------------*/ -static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307, - u32 ohms, bool diode) -{ - u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE : - DS1307_TRICKLE_CHARGER_NO_DIODE; - - switch (ohms) { - case 250: - setup |= DS1307_TRICKLE_CHARGER_250_OHM; - break; - case 2000: - setup |= DS1307_TRICKLE_CHARGER_2K_OHM; - break; - case 4000: - setup |= DS1307_TRICKLE_CHARGER_4K_OHM; - break; - default: - dev_warn(ds1307->dev, - "Unsupported ohm value %u in dt\n", ohms); - return 0; - } - return setup; -} - static u8 ds1307_trickle_init(struct ds1307 *ds1307, const struct chip_desc *chip) { - u32 ohms; - bool diode = true; + u32 ohms, chargeable; + bool diode = chip->charge_default; if (!chip->do_trickle_setup) return 0; if (device_property_read_u32(ds1307->dev, "trickle-resistor-ohms", - &ohms)) + &ohms) && chip->requires_trickle_resistor) return 0; - if (device_property_read_bool(ds1307->dev, "trickle-diode-disable")) + /* aux-voltage-chargeable takes precedence over the deprecated + * trickle-diode-disable + */ + if (!device_property_read_u32(ds1307->dev, "aux-voltage-chargeable", + &chargeable)) { + switch (chargeable) { + case 0: + diode = false; + break; + case 1: + diode = true; + break; + default: + dev_warn(ds1307->dev, + "unsupported aux-voltage-chargeable value\n"); + break; + } + } else if (device_property_read_bool(ds1307->dev, + "trickle-diode-disable")) { diode = false; + } return chip->do_trickle_setup(ds1307, ohms, diode); } @@ -1388,6 +1712,54 @@ #endif /* CONFIG_COMMON_CLK */ +#ifdef CONFIG_WATCHDOG_CORE +static const struct watchdog_info ds1388_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "DS1388 watchdog", +}; + +static const struct watchdog_ops ds1388_wdt_ops = { + .owner = THIS_MODULE, + .start = ds1388_wdt_start, + .stop = ds1388_wdt_stop, + .ping = ds1388_wdt_ping, + .set_timeout = ds1388_wdt_set_timeout, + +}; + +static void ds1307_wdt_register(struct ds1307 *ds1307) +{ + struct watchdog_device *wdt; + int err; + int val; + + if (ds1307->type != ds_1388) + return; + + wdt = devm_kzalloc(ds1307->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return; + + err = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &val); + if (!err && val & DS1388_BIT_WF) + wdt->bootstatus = WDIOF_CARDRESET; + + wdt->info = &ds1388_wdt_info; + wdt->ops = &ds1388_wdt_ops; + wdt->timeout = 99; + wdt->max_timeout = 99; + wdt->min_timeout = 1; + + watchdog_init_timeout(wdt, 0, ds1307->dev); + watchdog_set_drvdata(wdt, ds1307); + devm_watchdog_register_device(ds1307->dev, wdt); +} +#else +static void ds1307_wdt_register(struct ds1307 *ds1307) +{ +} +#endif /* CONFIG_WATCHDOG_CORE */ + static const struct regmap_config regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -1448,7 +1820,6 @@ trickle_charger_setup = pdata->trickle_charger_setup; if (trickle_charger_setup && chip->trickle_charger_reg) { - trickle_charger_setup |= DS13XX_TRICKLE_CHARGER_MAGIC; dev_dbg(ds1307->dev, "writing trickle charger info 0x%x to 0x%x\n", trickle_charger_setup, chip->trickle_charger_reg); @@ -1571,11 +1942,23 @@ DS1307_REG_HOUR << 4 | 0x08, hour); } break; + case ds_1388: + err = regmap_read(ds1307->regmap, DS1388_REG_CONTROL, &tmp); + if (err) { + dev_dbg(ds1307->dev, "read error %d\n", err); + goto exit; + } + + /* oscillator off? turn it on, so clock can tick. */ + if (tmp & DS1388_BIT_nEOSC) { + tmp &= ~DS1388_BIT_nEOSC; + regmap_write(ds1307->regmap, DS1388_REG_CONTROL, tmp); + } + break; default: break; } -read_rtc: /* read RTC registers */ err = regmap_bulk_read(ds1307->regmap, chip->offset, regs, sizeof(regs)); @@ -1584,75 +1967,11 @@ goto exit; } - /* - * minimal sanity checking; some chips (like DS1340) don't - * specify the extra bits as must-be-zero, but there are - * still a few values that are clearly out-of-range. - */ - tmp = regs[DS1307_REG_SECS]; - switch (ds1307->type) { - 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); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - break; - case ds_1308: - case ds_1338: - /* clock halted? turn it on, so clock can tick. */ - if (tmp & DS1307_BIT_CH) - regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - - /* oscillator fault? clear flag, and warn */ - if (regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) { - regmap_write(ds1307->regmap, DS1307_REG_CONTROL, - regs[DS1307_REG_CONTROL] & - ~DS1338_BIT_OSF); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - break; - case ds_1340: - /* clock halted? turn it on, so clock can tick. */ - if (tmp & DS1340_BIT_nEOSC) - regmap_write(ds1307->regmap, DS1307_REG_SECS, 0); - - err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp); - if (err) { - dev_dbg(ds1307->dev, "read error %d\n", err); - goto exit; - } - - /* oscillator fault? clear flag, and warn */ - if (tmp & DS1340_BIT_OSF) { - regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0); - dev_warn(ds1307->dev, "SET TIME!\n"); - } - break; - case mcp794xx: - /* make sure that the backup battery is enabled */ - if (!(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { - regmap_write(ds1307->regmap, DS1307_REG_WDAY, - regs[DS1307_REG_WDAY] | - MCP794XX_BIT_VBATEN); - } - - /* clock halted? turn it on, so clock can tick. */ - if (!(tmp & MCP794XX_BIT_ST)) { - regmap_write(ds1307->regmap, DS1307_REG_SECS, - MCP794XX_BIT_ST); - dev_warn(ds1307->dev, "SET TIME!\n"); - goto read_rtc; - } - - break; - default: - break; + if (ds1307->type == mcp794xx && + !(regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { + regmap_write(ds1307->regmap, DS1307_REG_WDAY, + regs[DS1307_REG_WDAY] | + MCP794XX_BIT_VBATEN); } tmp = regs[DS1307_REG_HOUR]; @@ -1717,6 +2036,10 @@ } ds1307->rtc->ops = chip->rtc_ops ?: &ds13xx_rtc_ops; + err = ds1307_add_frequency_test(ds1307); + if (err) + return err; + err = rtc_register_device(ds1307->rtc); if (err) return err; @@ -1738,6 +2061,7 @@ ds1307_hwmon_register(ds1307); ds1307_clks_register(ds1307); + ds1307_wdt_register(ds1307); return 0; -- Gitblit v1.6.2