diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 21:00:37 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 21:00:37 +0000 |
commit | 94ac2ab3fff96814d7460a27a0e9d004abbd4128 (patch) | |
tree | 9a4eb8cc234b540b0f4b93363109cdd37a20540b /drivers/rtc/rtc-ds1511.c | |
parent | Adding debian version 6.8.12-1. (diff) | |
download | linux-94ac2ab3fff96814d7460a27a0e9d004abbd4128.tar.xz linux-94ac2ab3fff96814d7460a27a0e9d004abbd4128.zip |
Merging upstream version 6.9.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/rtc/rtc-ds1511.c')
-rw-r--r-- | drivers/rtc/rtc-ds1511.c | 340 |
1 files changed, 104 insertions, 236 deletions
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 1109cad838..8b087d9556 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -22,26 +22,24 @@ #include <linux/io.h> #include <linux/module.h> -enum ds1511reg { - DS1511_SEC = 0x0, - DS1511_MIN = 0x1, - DS1511_HOUR = 0x2, - DS1511_DOW = 0x3, - DS1511_DOM = 0x4, - DS1511_MONTH = 0x5, - DS1511_YEAR = 0x6, - DS1511_CENTURY = 0x7, - DS1511_AM1_SEC = 0x8, - DS1511_AM2_MIN = 0x9, - DS1511_AM3_HOUR = 0xa, - DS1511_AM4_DATE = 0xb, - DS1511_WD_MSEC = 0xc, - DS1511_WD_SEC = 0xd, - DS1511_CONTROL_A = 0xe, - DS1511_CONTROL_B = 0xf, - DS1511_RAMADDR_LSB = 0x10, - DS1511_RAMDATA = 0x13 -}; +#define DS1511_SEC 0x0 +#define DS1511_MIN 0x1 +#define DS1511_HOUR 0x2 +#define DS1511_DOW 0x3 +#define DS1511_DOM 0x4 +#define DS1511_MONTH 0x5 +#define DS1511_YEAR 0x6 +#define DS1511_CENTURY 0x7 +#define DS1511_AM1_SEC 0x8 +#define DS1511_AM2_MIN 0x9 +#define DS1511_AM3_HOUR 0xa +#define DS1511_AM4_DATE 0xb +#define DS1511_WD_MSEC 0xc +#define DS1511_WD_SEC 0xd +#define DS1511_CONTROL_A 0xe +#define DS1511_CONTROL_B 0xf +#define DS1511_RAMADDR_LSB 0x10 +#define DS1511_RAMDATA 0x13 #define DS1511_BLF1 0x80 #define DS1511_BLF2 0x40 @@ -61,35 +59,10 @@ enum ds1511reg { #define DS1511_WDS 0x01 #define DS1511_RAM_MAX 0x100 -#define RTC_CMD DS1511_CONTROL_B -#define RTC_CMD1 DS1511_CONTROL_A - -#define RTC_ALARM_SEC DS1511_AM1_SEC -#define RTC_ALARM_MIN DS1511_AM2_MIN -#define RTC_ALARM_HOUR DS1511_AM3_HOUR -#define RTC_ALARM_DATE DS1511_AM4_DATE - -#define RTC_SEC DS1511_SEC -#define RTC_MIN DS1511_MIN -#define RTC_HOUR DS1511_HOUR -#define RTC_DOW DS1511_DOW -#define RTC_DOM DS1511_DOM -#define RTC_MON DS1511_MONTH -#define RTC_YEAR DS1511_YEAR -#define RTC_CENTURY DS1511_CENTURY - -#define RTC_TIE DS1511_TIE -#define RTC_TE DS1511_TE - -struct rtc_plat_data { +struct ds1511_data { struct rtc_device *rtc; void __iomem *ioaddr; /* virtual base address */ int irq; - unsigned int irqen; - int alrm_sec; - int alrm_min; - int alrm_hour; - int alrm_mday; spinlock_t lock; }; @@ -98,95 +71,33 @@ static DEFINE_SPINLOCK(ds1511_lock); static __iomem char *ds1511_base; static u32 reg_spacing = 1; -static noinline void -rtc_write(uint8_t val, uint32_t reg) +static void rtc_write(uint8_t val, uint32_t reg) { writeb(val, ds1511_base + (reg * reg_spacing)); } -static noinline uint8_t -rtc_read(enum ds1511reg reg) +static uint8_t rtc_read(uint32_t reg) { return readb(ds1511_base + (reg * reg_spacing)); } -static inline void -rtc_disable_update(void) +static void rtc_disable_update(void) { - rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD); + rtc_write((rtc_read(DS1511_CONTROL_B) & ~DS1511_TE), DS1511_CONTROL_B); } -static void -rtc_enable_update(void) +static void rtc_enable_update(void) { - rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD); -} - -/* - * #define DS1511_WDOG_RESET_SUPPORT - * - * Uncomment this if you want to use these routines in - * some platform code. - */ -#ifdef DS1511_WDOG_RESET_SUPPORT -/* - * just enough code to set the watchdog timer so that it - * will reboot the system - */ -void -ds1511_wdog_set(unsigned long deciseconds) -{ - /* - * the wdog timer can take 99.99 seconds - */ - deciseconds %= 10000; - /* - * set the wdog values in the wdog registers - */ - rtc_write(bin2bcd(deciseconds % 100), DS1511_WD_MSEC); - rtc_write(bin2bcd(deciseconds / 100), DS1511_WD_SEC); - /* - * set wdog enable and wdog 'steering' bit to issue a reset - */ - rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD); -} - -void -ds1511_wdog_disable(void) -{ - /* - * clear wdog enable and wdog 'steering' bits - */ - rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD); - /* - * clear the wdog counter - */ - rtc_write(0, DS1511_WD_MSEC); - rtc_write(0, DS1511_WD_SEC); + rtc_write((rtc_read(DS1511_CONTROL_B) | DS1511_TE), DS1511_CONTROL_B); } -#endif -/* - * set the rtc chip's idea of the time. - * stupidly, some callers call with year unmolested; - * and some call with year = year - 1900. thanks. - */ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) { u8 mon, day, dow, hrs, min, sec, yrs, cen; unsigned long flags; - /* - * won't have to change this for a while - */ - if (rtc_tm->tm_year < 1900) - rtc_tm->tm_year += 1900; - - if (rtc_tm->tm_year < 1970) - return -EINVAL; - yrs = rtc_tm->tm_year % 100; - cen = rtc_tm->tm_year / 100; + cen = 19 + rtc_tm->tm_year / 100; mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ day = rtc_tm->tm_mday; dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */ @@ -194,15 +105,6 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) min = rtc_tm->tm_min; sec = rtc_tm->tm_sec; - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - /* * each register is a different number of valid bits */ @@ -216,14 +118,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) spin_lock_irqsave(&ds1511_lock, flags); rtc_disable_update(); - rtc_write(cen, RTC_CENTURY); - rtc_write(yrs, RTC_YEAR); - rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON); - rtc_write(day, RTC_DOM); - rtc_write(hrs, RTC_HOUR); - rtc_write(min, RTC_MIN); - rtc_write(sec, RTC_SEC); - rtc_write(dow, RTC_DOW); + rtc_write(cen, DS1511_CENTURY); + rtc_write(yrs, DS1511_YEAR); + rtc_write((rtc_read(DS1511_MONTH) & 0xe0) | mon, DS1511_MONTH); + rtc_write(day, DS1511_DOM); + rtc_write(hrs, DS1511_HOUR); + rtc_write(min, DS1511_MIN); + rtc_write(sec, DS1511_SEC); + rtc_write(dow, DS1511_DOW); rtc_enable_update(); spin_unlock_irqrestore(&ds1511_lock, flags); @@ -238,14 +140,14 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) spin_lock_irqsave(&ds1511_lock, flags); rtc_disable_update(); - rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f; - rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f; - rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f; - rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f; - rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7; - rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f; - rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f; - century = rtc_read(RTC_CENTURY); + rtc_tm->tm_sec = rtc_read(DS1511_SEC) & 0x7f; + rtc_tm->tm_min = rtc_read(DS1511_MIN) & 0x7f; + rtc_tm->tm_hour = rtc_read(DS1511_HOUR) & 0x3f; + rtc_tm->tm_mday = rtc_read(DS1511_DOM) & 0x3f; + rtc_tm->tm_wday = rtc_read(DS1511_DOW) & 0x7; + rtc_tm->tm_mon = rtc_read(DS1511_MONTH) & 0x1f; + rtc_tm->tm_year = rtc_read(DS1511_YEAR) & 0x7f; + century = rtc_read(DS1511_CENTURY); rtc_enable_update(); spin_unlock_irqrestore(&ds1511_lock, flags); @@ -271,106 +173,67 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) return 0; } -/* - * write the alarm register settings - * - * we only have the use to interrupt every second, otherwise - * known as the update interrupt, or the interrupt if the whole - * date/hours/mins/secs matches. the ds1511 has many more - * permutations, but the kernel doesn't. - */ -static void -ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) +static void ds1511_rtc_alarm_enable(unsigned int enabled) { - unsigned long flags; - - spin_lock_irqsave(&pdata->lock, flags); - rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? - 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, - RTC_ALARM_DATE); - rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ? - 0x80 : bin2bcd(pdata->alrm_hour) & 0x3f, - RTC_ALARM_HOUR); - rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ? - 0x80 : bin2bcd(pdata->alrm_min) & 0x7f, - RTC_ALARM_MIN); - rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ? - 0x80 : bin2bcd(pdata->alrm_sec) & 0x7f, - RTC_ALARM_SEC); - rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); - rtc_read(RTC_CMD1); /* clear interrupts */ - spin_unlock_irqrestore(&pdata->lock, flags); + rtc_write(rtc_read(DS1511_CONTROL_B) | (enabled ? DS1511_TIE : 0), DS1511_CONTROL_B); } -static int -ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +static int ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct rtc_plat_data *pdata = dev_get_drvdata(dev); + struct ds1511_data *ds1511 = dev_get_drvdata(dev); + unsigned long flags; - if (pdata->irq <= 0) - return -EINVAL; + spin_lock_irqsave(&ds1511->lock, flags); + rtc_write(bin2bcd(alrm->time.tm_mday) & 0x3f, DS1511_AM4_DATE); + rtc_write(bin2bcd(alrm->time.tm_hour) & 0x3f, DS1511_AM3_HOUR); + rtc_write(bin2bcd(alrm->time.tm_min) & 0x7f, DS1511_AM2_MIN); + rtc_write(bin2bcd(alrm->time.tm_sec) & 0x7f, DS1511_AM1_SEC); + ds1511_rtc_alarm_enable(alrm->enabled); - pdata->alrm_mday = alrm->time.tm_mday; - pdata->alrm_hour = alrm->time.tm_hour; - pdata->alrm_min = alrm->time.tm_min; - pdata->alrm_sec = alrm->time.tm_sec; - if (alrm->enabled) - pdata->irqen |= RTC_AF; + rtc_read(DS1511_CONTROL_A); /* clear interrupts */ + spin_unlock_irqrestore(&ds1511->lock, flags); - ds1511_rtc_update_alarm(pdata); return 0; } -static int -ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +static int ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - - if (pdata->irq <= 0) - return -EINVAL; + alrm->time.tm_mday = bcd2bin(rtc_read(DS1511_AM4_DATE) & 0x3f); + alrm->time.tm_hour = bcd2bin(rtc_read(DS1511_AM3_HOUR) & 0x3f); + alrm->time.tm_min = bcd2bin(rtc_read(DS1511_AM2_MIN) & 0x7f); + alrm->time.tm_sec = bcd2bin(rtc_read(DS1511_AM1_SEC) & 0x7f); + alrm->enabled = !!(rtc_read(DS1511_CONTROL_B) & DS1511_TIE); - alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; - alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; - alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; - alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec; - alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0; return 0; } -static irqreturn_t -ds1511_interrupt(int irq, void *dev_id) +static irqreturn_t ds1511_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + struct ds1511_data *ds1511 = platform_get_drvdata(pdev); unsigned long events = 0; - spin_lock(&pdata->lock); + spin_lock(&ds1511->lock); /* * read and clear interrupt */ - if (rtc_read(RTC_CMD1) & DS1511_IRQF) { - events = RTC_IRQF; - if (rtc_read(RTC_ALARM_SEC) & 0x80) - events |= RTC_UF; - else - events |= RTC_AF; - rtc_update_irq(pdata->rtc, 1, events); + if (rtc_read(DS1511_CONTROL_A) & DS1511_IRQF) { + events = RTC_IRQF | RTC_AF; + rtc_update_irq(ds1511->rtc, 1, events); } - spin_unlock(&pdata->lock); + spin_unlock(&ds1511->lock); return events ? IRQ_HANDLED : IRQ_NONE; } static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_AF; - else - pdata->irqen &= ~RTC_AF; - ds1511_rtc_update_alarm(pdata); + struct ds1511_data *ds1511 = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ds1511->lock, flags); + ds1511_rtc_alarm_enable(enabled); + spin_unlock_irqrestore(&ds1511->lock, flags); + return 0; } @@ -408,7 +271,7 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf, static int ds1511_rtc_probe(struct platform_device *pdev) { - struct rtc_plat_data *pdata; + struct ds1511_data *ds1511; int ret = 0; struct nvmem_config ds1511_nvmem_cfg = { .name = "ds1511_nvram", @@ -420,21 +283,21 @@ static int ds1511_rtc_probe(struct platform_device *pdev) .priv = &pdev->dev, }; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) + ds1511 = devm_kzalloc(&pdev->dev, sizeof(*ds1511), GFP_KERNEL); + if (!ds1511) return -ENOMEM; ds1511_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ds1511_base)) return PTR_ERR(ds1511_base); - pdata->ioaddr = ds1511_base; - pdata->irq = platform_get_irq(pdev, 0); + ds1511->ioaddr = ds1511_base; + ds1511->irq = platform_get_irq(pdev, 0); /* * turn on the clock and the crystal, etc. */ - rtc_write(DS1511_BME, RTC_CMD); - rtc_write(0, RTC_CMD1); + rtc_write(DS1511_BME, DS1511_CONTROL_B); + rtc_write(0, DS1511_CONTROL_A); /* * clear the wdog counter */ @@ -448,38 +311,43 @@ static int ds1511_rtc_probe(struct platform_device *pdev) /* * check for a dying bat-tree */ - if (rtc_read(RTC_CMD1) & DS1511_BLF1) + if (rtc_read(DS1511_CONTROL_A) & DS1511_BLF1) dev_warn(&pdev->dev, "voltage-low detected.\n"); - spin_lock_init(&pdata->lock); - platform_set_drvdata(pdev, pdata); - - pdata->rtc = devm_rtc_allocate_device(&pdev->dev); - if (IS_ERR(pdata->rtc)) - return PTR_ERR(pdata->rtc); - - pdata->rtc->ops = &ds1511_rtc_ops; + spin_lock_init(&ds1511->lock); + platform_set_drvdata(pdev, ds1511); - ret = devm_rtc_register_device(pdata->rtc); - if (ret) - return ret; + ds1511->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(ds1511->rtc)) + return PTR_ERR(ds1511->rtc); - devm_rtc_nvmem_register(pdata->rtc, &ds1511_nvmem_cfg); + ds1511->rtc->ops = &ds1511_rtc_ops; + ds1511->rtc->range_max = RTC_TIMESTAMP_END_2099; + ds1511->rtc->alarm_offset_max = 28 * 24 * 60 * 60 - 1; /* * if the platform has an interrupt in mind for this device, * then by all means, set it */ - if (pdata->irq > 0) { - rtc_read(RTC_CMD1); - if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt, + if (ds1511->irq > 0) { + rtc_read(DS1511_CONTROL_A); + if (devm_request_irq(&pdev->dev, ds1511->irq, ds1511_interrupt, IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = 0; + ds1511->irq = 0; } } + if (ds1511->irq == 0) + clear_bit(RTC_FEATURE_ALARM, ds1511->rtc->features); + + ret = devm_rtc_register_device(ds1511->rtc); + if (ret) + return ret; + + devm_rtc_nvmem_register(ds1511->rtc, &ds1511_nvmem_cfg); + return 0; } |