diff options
Diffstat (limited to 'drivers/rtc/rtc-pcf8523.c')
| -rw-r--r-- | drivers/rtc/rtc-pcf8523.c | 89 |
1 files changed, 55 insertions, 34 deletions
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index c93acade7205..2c63c0ffd05a 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -21,7 +21,7 @@ #define PCF8523_CONTROL2_AF BIT(3) #define PCF8523_REG_CONTROL3 0x02 -#define PCF8523_CONTROL3_PM GENMASK(7,5) +#define PCF8523_CONTROL3_PM GENMASK(7, 5) #define PCF8523_PM_STANDBY 0x7 #define PCF8523_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ #define PCF8523_CONTROL3_BSF BIT(3) @@ -65,7 +65,7 @@ static int pcf8523_load_capacitance(struct pcf8523 *pcf8523, struct device_node load); fallthrough; case 12500: - value |= PCF8523_CONTROL1_CAP_SEL; + value = PCF8523_CONTROL1_CAP_SEL; break; case 7000: break; @@ -99,24 +99,24 @@ static irqreturn_t pcf8523_irq(int irq, void *dev_id) static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf8523 *pcf8523 = dev_get_drvdata(dev); - u8 regs[7]; + u8 regs[10]; int err; - err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_SECONDS, regs, + err = regmap_bulk_read(pcf8523->regmap, PCF8523_REG_CONTROL1, regs, sizeof(regs)); if (err < 0) return err; - if (regs[0] & PCF8523_SECONDS_OS) + if ((regs[0] & PCF8523_CONTROL1_STOP) || (regs[3] & PCF8523_SECONDS_OS)) return -EINVAL; - tm->tm_sec = bcd2bin(regs[0] & 0x7f); - tm->tm_min = bcd2bin(regs[1] & 0x7f); - tm->tm_hour = bcd2bin(regs[2] & 0x3f); - tm->tm_mday = bcd2bin(regs[3] & 0x3f); - tm->tm_wday = regs[4] & 0x7; - tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1; - tm->tm_year = bcd2bin(regs[6]) + 100; + tm->tm_sec = bcd2bin(regs[3] & 0x7f); + tm->tm_min = bcd2bin(regs[4] & 0x7f); + tm->tm_hour = bcd2bin(regs[5] & 0x3f); + tm->tm_mday = bcd2bin(regs[6] & 0x3f); + tm->tm_wday = regs[7] & 0x7; + tm->tm_mon = bcd2bin(regs[8] & 0x1f) - 1; + tm->tm_year = bcd2bin(regs[9]) + 100; return 0; } @@ -212,14 +212,6 @@ static int pcf8523_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) if (err < 0) return err; - /* The alarm has no seconds, round up to nearest minute */ - if (tm->time.tm_sec) { - time64_t alarm_time = rtc_tm_to_time64(&tm->time); - - alarm_time += 60 - tm->time.tm_sec; - rtc_time64_to_tm(alarm_time, &tm->time); - } - regs[0] = bin2bcd(tm->time.tm_min); regs[1] = bin2bcd(tm->time.tm_hour); regs[2] = bin2bcd(tm->time.tm_mday); @@ -240,10 +232,9 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) { struct pcf8523 *pcf8523 = dev_get_drvdata(dev); int ret; + u32 value; - switch(param->param) { - u32 value; - + switch (param->param) { case RTC_PARAM_BACKUP_SWITCH_MODE: ret = regmap_read(pcf8523->regmap, PCF8523_REG_CONTROL3, &value); if (ret < 0) @@ -251,7 +242,7 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) value = FIELD_GET(PCF8523_CONTROL3_PM, value); - switch(value) { + switch (value) { case 0x0: case 0x4: param->uvalue = RTC_BSM_LEVEL; @@ -279,9 +270,9 @@ static int pcf8523_param_get(struct device *dev, struct rtc_param *param) static int pcf8523_param_set(struct device *dev, struct rtc_param *param) { struct pcf8523 *pcf8523 = dev_get_drvdata(dev); + u8 mode; - switch(param->param) { - u8 mode; + switch (param->param) { case RTC_PARAM_BACKUP_SWITCH_MODE: switch (param->uvalue) { case RTC_BSM_DISABLED: @@ -379,6 +370,30 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset) return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value); } +#ifdef CONFIG_PM_SLEEP +static int pcf8523_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + if (client->irq > 0 && device_may_wakeup(dev)) + enable_irq_wake(client->irq); + + return 0; +} + +static int pcf8523_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + if (client->irq > 0 && device_may_wakeup(dev)) + disable_irq_wake(client->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pcf8523_pm, pcf8523_suspend, pcf8523_resume); + static const struct rtc_class_ops pcf8523_rtc_ops = { .read_time = pcf8523_rtc_read_time, .set_time = pcf8523_rtc_set_time, @@ -393,13 +408,12 @@ static const struct rtc_class_ops pcf8523_rtc_ops = { }; static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x13, + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x13, }; -static int pcf8523_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcf8523_probe(struct i2c_client *client) { struct pcf8523 *pcf8523; struct rtc_device *rtc; @@ -450,16 +464,22 @@ static int pcf8523_probe(struct i2c_client *client, rtc->ops = &pcf8523_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; - rtc->uie_unsupported = 1; + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); if (err < 0) return err; err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8523_irq, - IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, + IRQF_SHARED | IRQF_ONESHOT | irqflags, dev_name(&rtc->dev), pcf8523); if (err) return err; @@ -475,7 +495,7 @@ static int pcf8523_probe(struct i2c_client *client, } static const struct i2c_device_id pcf8523_id[] = { - { "pcf8523", 0 }, + { "pcf8523" }, { } }; MODULE_DEVICE_TABLE(i2c, pcf8523_id); @@ -491,6 +511,7 @@ static struct i2c_driver pcf8523_driver = { .driver = { .name = "rtc-pcf8523", .of_match_table = pcf8523_of_match, + .pm = &pcf8523_pm, }, .probe = pcf8523_probe, .id_table = pcf8523_id, |
