diff options
Diffstat (limited to 'drivers/rtc/rtc-pcf2127.c')
| -rw-r--r-- | drivers/rtc/rtc-pcf2127.c | 123 |
1 files changed, 75 insertions, 48 deletions
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index ed6316992cbb..d13c20a2adf7 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -26,6 +26,7 @@ /* Control register 1 */ #define PCF2127_REG_CTRL1 0x00 +#define PCF2127_BIT_CTRL1_POR_OVRD BIT(3) #define PCF2127_BIT_CTRL1_TSF1 BIT(4) /* Control register 2 */ #define PCF2127_REG_CTRL2 0x01 @@ -57,6 +58,9 @@ #define PCF2127_REG_ALARM_DM 0x0D #define PCF2127_REG_ALARM_DW 0x0E #define PCF2127_BIT_ALARM_AE BIT(7) +/* CLKOUT control register */ +#define PCF2127_REG_CLKOUT 0x0f +#define PCF2127_BIT_CLKOUT_OTPR BIT(5) /* Watchdog registers */ #define PCF2127_REG_WD_CTL 0x10 #define PCF2127_BIT_WD_CTL_TF0 BIT(0) @@ -225,12 +229,6 @@ static int pcf2127_rtc_ioctl(struct device *dev, } } -static const struct rtc_class_ops pcf2127_rtc_ops = { - .ioctl = pcf2127_rtc_ioctl, - .read_time = pcf2127_rtc_read_time, - .set_time = pcf2127_rtc_set_time, -}; - static int pcf2127_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes) { @@ -243,10 +241,8 @@ static int pcf2127_nvmem_read(void *priv, unsigned int offset, if (ret) return ret; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_RD_CMD, - val, bytes); - - return ret ?: bytes; + return regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_RD_CMD, + val, bytes); } static int pcf2127_nvmem_write(void *priv, unsigned int offset, @@ -261,10 +257,8 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, if (ret) return ret; - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_WRT_CMD, - val, bytes); - - return ret ?: bytes; + return regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_WRT_CMD, + val, bytes); } /* watchdog driver */ @@ -335,6 +329,37 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { .set_timeout = pcf2127_wdt_set_timeout, }; +static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) +{ + u32 wdd_timeout; + int ret; + + if (!IS_ENABLED(CONFIG_WATCHDOG) || + !device_property_read_bool(dev, "reset-source")) + return 0; + + pcf2127->wdd.parent = dev; + pcf2127->wdd.info = &pcf2127_wdt_info; + pcf2127->wdd.ops = &pcf2127_watchdog_ops; + pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; + pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; + pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; + pcf2127->wdd.min_hw_heartbeat_ms = 500; + pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS; + + watchdog_set_drvdata(&pcf2127->wdd, pcf2127); + + /* Test if watchdog timer is started by bootloader */ + ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); + if (ret) + return ret; + + if (wdd_timeout) + set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + + return devm_watchdog_register_device(dev, &pcf2127->wdd); +} + /* Alarm */ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { @@ -432,7 +457,7 @@ static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) return IRQ_HANDLED; } -static const struct rtc_class_ops pcf2127_rtc_alrm_ops = { +static const struct rtc_class_ops pcf2127_rtc_ops = { .ioctl = pcf2127_rtc_ioctl, .read_time = pcf2127_rtc_read_time, .set_time = pcf2127_rtc_set_time, @@ -533,11 +558,11 @@ static const struct attribute_group pcf2127_attr_group = { }; static int pcf2127_probe(struct device *dev, struct regmap *regmap, - int alarm_irq, const char *name, bool has_nvmem) + int alarm_irq, const char *name, bool is_pcf2127) { struct pcf2127 *pcf2127; - u32 wdd_timeout; int ret = 0; + unsigned int val; dev_dbg(dev, "%s\n", __func__); @@ -558,8 +583,9 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ pcf2127->rtc->uie_unsupported = 1; + clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); - if (alarm_irq >= 0) { + if (alarm_irq > 0) { ret = devm_request_threaded_irq(dev, alarm_irq, NULL, pcf2127_rtc_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, @@ -570,23 +596,12 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, } } - if (alarm_irq >= 0 || device_property_read_bool(dev, "wakeup-source")) { + if (alarm_irq > 0 || device_property_read_bool(dev, "wakeup-source")) { device_init_wakeup(dev, true); - pcf2127->rtc->ops = &pcf2127_rtc_alrm_ops; + set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } - pcf2127->wdd.parent = dev; - pcf2127->wdd.info = &pcf2127_wdt_info; - pcf2127->wdd.ops = &pcf2127_watchdog_ops; - pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; - pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; - pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; - pcf2127->wdd.min_hw_heartbeat_ms = 500; - pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS; - - watchdog_set_drvdata(&pcf2127->wdd, pcf2127); - - if (has_nvmem) { + if (is_pcf2127) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, .reg_read = pcf2127_nvmem_read, @@ -594,13 +609,37 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, .size = 512, }; - ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); + ret = devm_rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); + } + + /* + * The "Power-On Reset Override" facility prevents the RTC to do a reset + * after power on. For normal operation the PORO must be disabled. + */ + regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_POR_OVRD); + + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CLKOUT, &val); + if (ret < 0) + return ret; + + if (!(val & PCF2127_BIT_CLKOUT_OTPR)) { + ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CLKOUT, + PCF2127_BIT_CLKOUT_OTPR); + if (ret < 0) + return ret; + + msleep(100); } /* * Watchdog timer enabled and reset pin /RST activated when timed out. * Select 1Hz clock source for watchdog timer. * Note: Countdown timer disabled and not available. + * For pca2129, pcf2129, only bit[7] is for Symbol WD_CD + * of register watchdg_tim_ctl. The bit[6] is labeled + * as T. Bits labeled as T must always be written with + * logic 0. */ ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL, PCF2127_BIT_WD_CTL_CD1 | @@ -608,26 +647,14 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, PCF2127_BIT_WD_CTL_TF1 | PCF2127_BIT_WD_CTL_TF0, PCF2127_BIT_WD_CTL_CD1 | - PCF2127_BIT_WD_CTL_CD0 | + (is_pcf2127 ? PCF2127_BIT_WD_CTL_CD0 : 0) | PCF2127_BIT_WD_CTL_TF1); if (ret) { dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); return ret; } - /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); - if (ret) - return ret; - - if (wdd_timeout) - set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); - -#ifdef CONFIG_WATCHDOG - ret = devm_watchdog_register_device(dev, &pcf2127->wdd); - if (ret) - return ret; -#endif /* CONFIG_WATCHDOG */ + pcf2127_watchdog_init(dev, pcf2127); /* * Disable battery low/switch-over timestamp and interrupts. @@ -680,7 +707,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, return ret; } - return rtc_register_device(pcf2127->rtc); + return devm_rtc_register_device(pcf2127->rtc); } #ifdef CONFIG_OF |