// SPDX-License-Identifier: GPL-2.0-only/* * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time * chips. * * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>. * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>. * * References: * DS1685/DS1687 3V/5V Real-Time Clocks, 19-5215, Rev 4/10. * DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10. * DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105. * Application Note 90, Using the Multiplex Bus RTC Extended Features. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/bcd.h>#include <linux/delay.h>#include <linux/io.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/rtc.h>#include <linux/workqueue.h> #include <linux/rtc/ds1685.h> #ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif /* ----------------------------------------------------------------------- *//* * Standard read/write * all registers are mapped in CPU address space */ /** * ds1685_read - read a value from an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to read. */static u8ds1685_read(struct ds1685_priv *rtc, int reg){ return readb((u8 __iomem *)rtc->regs + (reg * rtc->regstep));} /** * ds1685_write - write a value to an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to write. * @value: value to write to the register. */static voidds1685_write(struct ds1685_priv *rtc, int reg, u8 value){ writeb(value, ((u8 __iomem *)rtc->regs + (reg * rtc->regstep)));}/* ----------------------------------------------------------------------- */ /* * Indirect read/write functions * access happens via address and data register mapped in CPU address space */ /** * ds1685_indirect_read - read a value from an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to read. */static u8ds1685_indirect_read(struct ds1685_priv *rtc, int reg){ writeb(reg, rtc->regs); return readb(rtc->data);} /** * ds1685_indirect_write - write a value to an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to write. * @value: value to write to the register. */static voidds1685_indirect_write(struct ds1685_priv *rtc, int reg, u8 value){ writeb(reg, rtc->regs); writeb(value, rtc->data);} /* ----------------------------------------------------------------------- *//* Inlined functions */ /** * ds1685_rtc_bcd2bin - bcd2bin wrapper in case platform doesn't support BCD. * @rtc: pointer to the ds1685 rtc structure. * @val: u8 time value to consider converting. * @bcd_mask: u8 mask value if BCD mode is used. * @bin_mask: u8 mask value if BIN mode is used. * * Returns the value, converted to BIN if originally in BCD and bcd_mode TRUE. */static inline u8ds1685_rtc_bcd2bin(struct ds1685_priv *rtc, u8 val, u8 bcd_mask, u8 bin_mask){ if (rtc->bcd_mode) return (bcd2bin(val) & bcd_mask); return (val & bin_mask);} /** * ds1685_rtc_bin2bcd - bin2bcd wrapper in case platform doesn't support BCD. * @rtc: pointer to the ds1685 rtc structure. * @val: u8 time value to consider converting. * @bin_mask: u8 mask value if BIN mode is used. * @bcd_mask: u8 mask value if BCD mode is used. * * Returns the value, converted to BCD if originally in BIN and bcd_mode TRUE. */static inline u8ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask){ if (rtc->bcd_mode) return (bin2bcd(val) & bcd_mask); return (val & bin_mask);} /** * ds1685_rtc_check_mday - check validity of the day of month. * @rtc: pointer to the ds1685 rtc structure. * @mday: day of month. * * Returns -EDOM if the day of month is not within 1..31 range. */static inline intds1685_rtc_check_mday(struct ds1685_priv *rtc, u8 mday){ if (rtc->bcd_mode) { if (mday < 0x01 || mday > 0x31 || (mday & 0x0f) > 0x09) return -EDOM; } else { if (mday < 1 || mday > 31) return -EDOM; } return 0;} /** * ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0. * @rtc: pointer to the ds1685 rtc structure. */static inline voidds1685_rtc_switch_to_bank0(struct ds1685_priv *rtc){ rtc->write(rtc, RTC_CTRL_A, (rtc->read(rtc, RTC_CTRL_A) & ~(RTC_CTRL_A_DV0)));} /** * ds1685_rtc_switch_to_bank1 - switch the rtc to bank 1. * @rtc: pointer to the ds1685 rtc structure. */static inline voidds1685_rtc_switch_to_bank1(struct ds1685_priv *rtc){ rtc->write(rtc, RTC_CTRL_A, (rtc->read(rtc, RTC_CTRL_A) | RTC_CTRL_A_DV0));} /** * ds1685_rtc_begin_data_access - prepare the rtc for data access. * @rtc: pointer to the ds1685 rtc structure. * * This takes several steps to prepare the rtc for access to get/set time * and alarm values from the rtc registers: * - Sets the SET bit in Control Register B. * - Reads Ext Control Register 4A and checks the INCR bit. * - If INCR is active, a short delay is added before Ext Control Register 4A * is read again in a loop until INCR is inactive. * - Switches the rtc to bank 1. This allows access to all relevant * data for normal rtc operation, as bank 0 contains only the nvram. */static inline voidds1685_rtc_begin_data_access(struct ds1685_priv *rtc){ /* Set the SET bit in Ctrl B */ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET)); /* Switch to Bank 1 */ ds1685_rtc_switch_to_bank1(rtc); /* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */ while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR) cpu_relax();} /** * ds1685_rtc_end_data_access - end data access on the rtc. * @rtc: pointer to the ds1685 rtc structure. * * This ends what was started by ds1685_rtc_begin_data_access: * - Switches the rtc back to bank 0. * - Clears the SET bit in Control Register B. */static inline voidds1685_rtc_end_data_access(struct ds1685_priv *rtc){ /* Switch back to Bank 0 */ ds1685_rtc_switch_to_bank0(rtc); /* Clear the SET bit in Ctrl B */ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET)));} /** * ds1685_rtc_get_ssn - retrieve the silicon serial number. * @rtc: pointer to the ds1685 rtc structure. * @ssn: u8 array to hold the bits of the silicon serial number. * * This number starts at 0x40, and is 8-bytes long, ending at 0x47. The * first byte is the model number, the next six bytes are the serial number * digits, and the final byte is a CRC check byte. Together, they form the * silicon serial number. * * These values are stored in bank1, so ds1685_rtc_switch_to_bank1 must be * called first before calling this function, else data will be read out of * the bank0 NVRAM. Be sure to call ds1685_rtc_switch_to_bank0 when done. */static inline voidds1685_rtc_get_ssn(struct ds1685_priv *rtc, u8 *ssn){ ssn[0] = rtc->read(rtc, RTC_BANK1_SSN_MODEL); ssn[1] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_1); ssn[2] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_2); ssn[3] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_3); ssn[4] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_4); ssn[5] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_5); ssn[6] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_6); ssn[7] = rtc->read(rtc, RTC_BANK1_SSN_CRC);}/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- *//* Read/Set Time & Alarm functions */ /** * ds1685_rtc_read_time - reads the time registers. * @dev: pointer to device structure. * @tm: pointer to rtc_time structure. */static intds1685_rtc_read_time(struct device *dev, struct rtc_time *tm){ struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 century; u8 seconds, minutes, hours, wday, mday, month, years; /* Fetch the time info from the RTC registers. */ ds1685_rtc_begin_data_access(rtc); seconds = rtc->read(rtc, RTC_SECS); minutes = rtc->read(rtc, RTC_MINS); hours = rtc->read(rtc, RTC_HRS); wday = rtc->read(rtc, RTC_WDAY); mday = rtc->read(rtc, RTC_MDAY); month = rtc->read(rtc, RTC_MONTH); years = rtc->read(rtc, RTC_YEAR); century = rtc->read(rtc, RTC_CENTURY); ds1685_rtc_end_data_access(rtc); /* bcd2bin if needed, perform fixups, and store to rtc_time. */ years = ds1685_rtc_bcd2bin(rtc, years, RTC_YEAR_BCD_MASK, RTC_YEAR_BIN_MASK); century = ds1685_rtc_bcd2bin(rtc, century, RTC_CENTURY_MASK, RTC_CENTURY_MASK); tm->tm_sec = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK, RTC_SECS_BIN_MASK); tm->tm_min = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK, RTC_MINS_BIN_MASK); tm->tm_hour = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK, RTC_HRS_24_BIN_MASK); tm->tm_wday = (ds1685_rtc_bcd2bin(rtc, wday, RTC_WDAY_MASK, RTC_WDAY_MASK) - 1); tm->tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK, RTC_MDAY_BIN_MASK); tm->tm_mon = (ds1685_rtc_bcd2bin(rtc, month, RTC_MONTH_BCD_MASK, RTC_MONTH_BIN_MASK) - 1); tm->tm_year = ((years + (century * 100)) - 1900); tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_isdst = 0; /* RTC has hardcoded timezone, so don't use. */ return 0;} /** * ds1685_rtc_set_time - sets the time registers. * @dev: pointer to device structure. * @tm: pointer to rtc_time structure. */static intds1685_rtc_set_time(struct device *dev, struct rtc_time *tm){ struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 ctrlb, seconds, minutes, hours, wday, mday, month, years, century; /* Fetch the time info from rtc_time. */ seconds = ds1685_rtc_bin2bcd(rtc, tm->tm_sec, RTC_SECS_BIN_MASK, RTC_SECS_BCD_MASK); minutes = ds1685_rtc_bin2bcd(rtc, tm->tm_min, RTC_MINS_BIN_MASK, RTC_MINS_BCD_MASK); hours = ds1685_rtc_bin2bcd(rtc, tm->tm_hour, RTC_HRS_24_BIN_MASK, RTC_HRS_24_BCD_MASK); wday = ds1685_rtc_bin2bcd(rtc, (tm->tm_wday + 1), RTC_WDAY_MASK, RTC_WDAY_MASK); mday = ds1685_rtc_bin2bcd(rtc, tm->tm_mday, RTC_MDAY_BIN_MASK, RTC_MDAY_BCD_MASK); month = ds1685_rtc_bin2bcd(rtc, (tm->tm_mon + 1), RTC_MONTH_BIN_MASK, RTC_MONTH_BCD_MASK); years = ds1685_rtc_bin2bcd(rtc, (tm->tm_year % 100), RTC_YEAR_BIN_MASK, RTC_YEAR_BCD_MASK); century = ds1685_rtc_bin2bcd(rtc, ((tm->tm_year + 1900) / 100), RTC_CENTURY_MASK, RTC_CENTURY_MASK); /* * Perform Sanity Checks: * - Months: !> 12, Month Day != 0. * - Month Day !> Max days in current month. * - Hours !>= 24, Mins !>= 60, Secs !>= 60, & Weekday !> 7. */ if ((tm->tm_mon > 11) || (mday == 0)) return -EDOM; if (tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year)) return -EDOM; if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60) || (wday > 7)) return -EDOM; /* * Set the data mode to use and store the time values in the * RTC registers. */ ds1685_rtc_begin_data_access(rtc); ctrlb = rtc->read(rtc, RTC_CTRL_B); if (rtc->bcd_mode) ctrlb &= ~(RTC_CTRL_B_DM); else ctrlb |= RTC_CTRL_B_DM; rtc->write(rtc, RTC_CTRL_B, ctrlb); rtc->write(rtc, RTC_SECS, seconds); rtc->write(rtc, RTC_MINS, minutes); rtc->write(rtc, RTC_HRS, hours); rtc->write(rtc, RTC_WDAY, wday); rtc->write(rtc, RTC_MDAY, mday); rtc->write(rtc, RTC_MONTH, month); rtc->write(rtc, RTC_YEAR, years); rtc->write(rtc, RTC_CENTURY, century); ds1685_rtc_end_data_access(rtc); return 0;} /** * ds1685_rtc_read_alarm - reads the alarm registers. * @dev: pointer to device structure. * @alrm: pointer to rtc_wkalrm structure. * * There are three primary alarm registers: seconds, minutes, and hours. * A fourth alarm register for the month date is also available in bank1 for * kickstart/wakeup features. The DS1685/DS1687 manual states that a * "don't care" value ranging from 0xc0 to 0xff may be written into one or * more of the three alarm bytes to act as a wildcard value. The fourth * byte doesn't support a "don't care" value. */static intds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm){ struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 seconds, minutes, hours, mday, ctrlb, ctrlc; int ret; /* Fetch the alarm info from the RTC alarm registers. */ ds1685_rtc_begin_data_access(rtc); seconds = rtc->read(rtc, RTC_SECS_ALARM); minutes = rtc->read(rtc, RTC_MINS_ALARM); hours = rtc->read(rtc, RTC_HRS_ALARM); mday = rtc->read(rtc, RTC_MDAY_ALARM); ctrlb = rtc->read(rtc, RTC_CTRL_B); ctrlc = rtc->read(rtc, RTC_CTRL_C); ds1685_rtc_end_data_access(rtc); /* Check the month date for validity. */ ret = ds1685_rtc_check_mday(rtc, mday); if (ret) return ret; /* * Check the three alarm bytes. * * The Linux RTC system doesn't support the "don't care" capability * of this RTC chip. We check for it anyways in case support is * added in the future and only assign when we care. */ if (likely(seconds < 0xc0)) alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK, RTC_SECS_BIN_MASK); if (likely(minutes < 0xc0)) alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK, RTC_MINS_BIN_MASK); if (likely(hours < 0xc0)) alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK, RTC_HRS_24_BIN_MASK); /* Write the data to rtc_wkalrm. */ alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK, RTC_MDAY_BIN_MASK); alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE); alrm->pending = !!(ctrlc & RTC_CTRL_C_AF); return 0;} /** * ds1685_rtc_set_alarm - sets the alarm in registers. * @dev: pointer to device structure. * @alrm: pointer to rtc_wkalrm structure. */static intds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm){ struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 ctrlb, seconds, minutes, hours, mday; int ret; /* Fetch the alarm info and convert to BCD. */ seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec, RTC_SECS_BIN_MASK, RTC_SECS_BCD_MASK); minutes = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_min, RTC_MINS_BIN_MASK, RTC_MINS_BCD_MASK); hours = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_hour, RTC_HRS_24_BIN_MASK, RTC_HRS_24_BCD_MASK); mday = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_mday, RTC_MDAY_BIN_MASK, RTC_MDAY_BCD_MASK); /* Check the month date for validity. */ ret = ds1685_rtc_check_mday(rtc, mday); if (ret) return ret; /* * Check the three alarm bytes. * * The Linux RTC system doesn't support the "don't care" capability * of this RTC chip because rtc_valid_tm tries to validate every * field, and we only support four fields. We put the support * here anyways for the future. */ if (unlikely(seconds >= 0xc0)) seconds = 0xff; if (unlikely(minutes >= 0xc0)) minutes = 0xff; if (unlikely(hours >= 0xc0)) hours = 0xff; alrm->time.tm_mon = -1; alrm->time.tm_year = -1; alrm->time.tm_wday = -1; alrm->time.tm_yday = -1; alrm->time.tm_isdst = -1; /* Disable the alarm interrupt first. */ ds1685_rtc_begin_data_access(rtc); ctrlb = rtc->read(rtc, RTC_CTRL_B); rtc->write(rtc, RTC_CTRL_B, (ctrlb & ~(RTC_CTRL_B_AIE))); /* Read ctrlc to clear RTC_CTRL_C_AF. */ rtc->read(rtc, RTC_CTRL_C); /* * Set the data mode to use and store the time values in theLines 1–500 of 1440. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time * chips. * * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>. * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>. * * References: * DS1685/DS1687 3V/5V Real-Time Clocks, 19-5215, Rev 4/10. * DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10. * DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105. * Application Note 90, Using the Multiplex Bus RTC Extended Features. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/bcd.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/workqueue.h> #include <linux/rtc/ds1685.h> #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> #endif /* ----------------------------------------------------------------------- */ /* * Standard read/write * all registers are mapped in CPU address space */ /** * ds1685_read - read a value from an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to read. */ static u8 ds1685_read(struct ds1685_priv *rtc, int reg) { return readb((u8 __iomem *)rtc->regs + (reg * rtc->regstep)); } /** * ds1685_write - write a value to an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to write. * @value: value to write to the register. */ static void ds1685_write(struct ds1685_priv *rtc, int reg, u8 value) { writeb(value, ((u8 __iomem *)rtc->regs + (reg * rtc->regstep))); } /* ----------------------------------------------------------------------- */ /* * Indirect read/write functions * access happens via address and data register mapped in CPU address space */ /** * ds1685_indirect_read - read a value from an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to read. */ static u8 ds1685_indirect_read(struct ds1685_priv *rtc, int reg) { writeb(reg, rtc->regs); return readb(rtc->data); } /** * ds1685_indirect_write - write a value to an rtc register. * @rtc: pointer to the ds1685 rtc structure. * @reg: the register address to write. * @value: value to write to the register. */ static void ds1685_indirect_write(struct ds1685_priv *rtc, int reg, u8 value) { writeb(reg, rtc->regs); writeb(value, rtc->data); } /* ----------------------------------------------------------------------- */ /* Inlined functions */ /** * ds1685_rtc_bcd2bin - bcd2bin wrapper in case platform doesn't support BCD. * @rtc: pointer to the ds1685 rtc structure. * @val: u8 time value to consider converting. * @bcd_mask: u8 mask value if BCD mode is used. * @bin_mask: u8 mask value if BIN mode is used. * * Returns the value, converted to BIN if originally in BCD and bcd_mode TRUE. */ static inline u8 ds1685_rtc_bcd2bin(struct ds1685_priv *rtc, u8 val, u8 bcd_mask, u8 bin_mask) { if (rtc->bcd_mode) return (bcd2bin(val) & bcd_mask); return (val & bin_mask); } /** * ds1685_rtc_bin2bcd - bin2bcd wrapper in case platform doesn't support BCD. * @rtc: pointer to the ds1685 rtc structure. * @val: u8 time value to consider converting. * @bin_mask: u8 mask value if BIN mode is used. * @bcd_mask: u8 mask value if BCD mode is used. * * Returns the value, converted to BCD if originally in BIN and bcd_mode TRUE. */ static inline u8 ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask) { if (rtc->bcd_mode) return (bin2bcd(val) & bcd_mask); return (val & bin_mask); } /** * ds1685_rtc_check_mday - check validity of the day of month. * @rtc: pointer to the ds1685 rtc structure. * @mday: day of month. * * Returns -EDOM if the day of month is not within 1..31 range. */ static inline int ds1685_rtc_check_mday(struct ds1685_priv *rtc, u8 mday) { if (rtc->bcd_mode) { if (mday < 0x01 || mday > 0x31 || (mday & 0x0f) > 0x09) return -EDOM; } else { if (mday < 1 || mday > 31) return -EDOM; } return 0; } /** * ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0. * @rtc: pointer to the ds1685 rtc structure. */ static inline void ds1685_rtc_switch_to_bank0(struct ds1685_priv *rtc) { rtc->write(rtc, RTC_CTRL_A, (rtc->read(rtc, RTC_CTRL_A) & ~(RTC_CTRL_A_DV0))); } /** * ds1685_rtc_switch_to_bank1 - switch the rtc to bank 1. * @rtc: pointer to the ds1685 rtc structure. */ static inline void ds1685_rtc_switch_to_bank1(struct ds1685_priv *rtc) { rtc->write(rtc, RTC_CTRL_A, (rtc->read(rtc, RTC_CTRL_A) | RTC_CTRL_A_DV0)); } /** * ds1685_rtc_begin_data_access - prepare the rtc for data access. * @rtc: pointer to the ds1685 rtc structure. * * This takes several steps to prepare the rtc for access to get/set time * and alarm values from the rtc registers: * - Sets the SET bit in Control Register B. * - Reads Ext Control Register 4A and checks the INCR bit. * - If INCR is active, a short delay is added before Ext Control Register 4A * is read again in a loop until INCR is inactive. * - Switches the rtc to bank 1. This allows access to all relevant * data for normal rtc operation, as bank 0 contains only the nvram. */ static inline void ds1685_rtc_begin_data_access(struct ds1685_priv *rtc) { /* Set the SET bit in Ctrl B */ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET)); /* Switch to Bank 1 */ ds1685_rtc_switch_to_bank1(rtc); /* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */ while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR) cpu_relax(); } /** * ds1685_rtc_end_data_access - end data access on the rtc. * @rtc: pointer to the ds1685 rtc structure. * * This ends what was started by ds1685_rtc_begin_data_access: * - Switches the rtc back to bank 0. * - Clears the SET bit in Control Register B. */ static inline void ds1685_rtc_end_data_access(struct ds1685_priv *rtc) { /* Switch back to Bank 0 */ ds1685_rtc_switch_to_bank0(rtc); /* Clear the SET bit in Ctrl B */ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET))); } /** * ds1685_rtc_get_ssn - retrieve the silicon serial number. * @rtc: pointer to the ds1685 rtc structure. * @ssn: u8 array to hold the bits of the silicon serial number. * * This number starts at 0x40, and is 8-bytes long, ending at 0x47. The * first byte is the model number, the next six bytes are the serial number * digits, and the final byte is a CRC check byte. Together, they form the * silicon serial number. * * These values are stored in bank1, so ds1685_rtc_switch_to_bank1 must be * called first before calling this function, else data will be read out of * the bank0 NVRAM. Be sure to call ds1685_rtc_switch_to_bank0 when done. */ static inline void ds1685_rtc_get_ssn(struct ds1685_priv *rtc, u8 *ssn) { ssn[0] = rtc->read(rtc, RTC_BANK1_SSN_MODEL); ssn[1] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_1); ssn[2] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_2); ssn[3] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_3); ssn[4] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_4); ssn[5] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_5); ssn[6] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_6); ssn[7] = rtc->read(rtc, RTC_BANK1_SSN_CRC); } /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* Read/Set Time & Alarm functions */ /** * ds1685_rtc_read_time - reads the time registers. * @dev: pointer to device structure. * @tm: pointer to rtc_time structure. */ static int ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 century; u8 seconds, minutes, hours, wday, mday, month, years; /* Fetch the time info from the RTC registers. */ ds1685_rtc_begin_data_access(rtc); seconds = rtc->read(rtc, RTC_SECS); minutes = rtc->read(rtc, RTC_MINS); hours = rtc->read(rtc, RTC_HRS); wday = rtc->read(rtc, RTC_WDAY); mday = rtc->read(rtc, RTC_MDAY); month = rtc->read(rtc, RTC_MONTH); years = rtc->read(rtc, RTC_YEAR); century = rtc->read(rtc, RTC_CENTURY); ds1685_rtc_end_data_access(rtc); /* bcd2bin if needed, perform fixups, and store to rtc_time. */ years = ds1685_rtc_bcd2bin(rtc, years, RTC_YEAR_BCD_MASK, RTC_YEAR_BIN_MASK); century = ds1685_rtc_bcd2bin(rtc, century, RTC_CENTURY_MASK, RTC_CENTURY_MASK); tm->tm_sec = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK, RTC_SECS_BIN_MASK); tm->tm_min = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK, RTC_MINS_BIN_MASK); tm->tm_hour = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK, RTC_HRS_24_BIN_MASK); tm->tm_wday = (ds1685_rtc_bcd2bin(rtc, wday, RTC_WDAY_MASK, RTC_WDAY_MASK) - 1); tm->tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK, RTC_MDAY_BIN_MASK); tm->tm_mon = (ds1685_rtc_bcd2bin(rtc, month, RTC_MONTH_BCD_MASK, RTC_MONTH_BIN_MASK) - 1); tm->tm_year = ((years + (century * 100)) - 1900); tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_isdst = 0; /* RTC has hardcoded timezone, so don't use. */ return 0; } /** * ds1685_rtc_set_time - sets the time registers. * @dev: pointer to device structure. * @tm: pointer to rtc_time structure. */ static int ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 ctrlb, seconds, minutes, hours, wday, mday, month, years, century; /* Fetch the time info from rtc_time. */ seconds = ds1685_rtc_bin2bcd(rtc, tm->tm_sec, RTC_SECS_BIN_MASK, RTC_SECS_BCD_MASK); minutes = ds1685_rtc_bin2bcd(rtc, tm->tm_min, RTC_MINS_BIN_MASK, RTC_MINS_BCD_MASK); hours = ds1685_rtc_bin2bcd(rtc, tm->tm_hour, RTC_HRS_24_BIN_MASK, RTC_HRS_24_BCD_MASK); wday = ds1685_rtc_bin2bcd(rtc, (tm->tm_wday + 1), RTC_WDAY_MASK, RTC_WDAY_MASK); mday = ds1685_rtc_bin2bcd(rtc, tm->tm_mday, RTC_MDAY_BIN_MASK, RTC_MDAY_BCD_MASK); month = ds1685_rtc_bin2bcd(rtc, (tm->tm_mon + 1), RTC_MONTH_BIN_MASK, RTC_MONTH_BCD_MASK); years = ds1685_rtc_bin2bcd(rtc, (tm->tm_year % 100), RTC_YEAR_BIN_MASK, RTC_YEAR_BCD_MASK); century = ds1685_rtc_bin2bcd(rtc, ((tm->tm_year + 1900) / 100), RTC_CENTURY_MASK, RTC_CENTURY_MASK); /* * Perform Sanity Checks: * - Months: !> 12, Month Day != 0. * - Month Day !> Max days in current month. * - Hours !>= 24, Mins !>= 60, Secs !>= 60, & Weekday !> 7. */ if ((tm->tm_mon > 11) || (mday == 0)) return -EDOM; if (tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year)) return -EDOM; if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60) || (wday > 7)) return -EDOM; /* * Set the data mode to use and store the time values in the * RTC registers. */ ds1685_rtc_begin_data_access(rtc); ctrlb = rtc->read(rtc, RTC_CTRL_B); if (rtc->bcd_mode) ctrlb &= ~(RTC_CTRL_B_DM); else ctrlb |= RTC_CTRL_B_DM; rtc->write(rtc, RTC_CTRL_B, ctrlb); rtc->write(rtc, RTC_SECS, seconds); rtc->write(rtc, RTC_MINS, minutes); rtc->write(rtc, RTC_HRS, hours); rtc->write(rtc, RTC_WDAY, wday); rtc->write(rtc, RTC_MDAY, mday); rtc->write(rtc, RTC_MONTH, month); rtc->write(rtc, RTC_YEAR, years); rtc->write(rtc, RTC_CENTURY, century); ds1685_rtc_end_data_access(rtc); return 0; } /** * ds1685_rtc_read_alarm - reads the alarm registers. * @dev: pointer to device structure. * @alrm: pointer to rtc_wkalrm structure. * * There are three primary alarm registers: seconds, minutes, and hours. * A fourth alarm register for the month date is also available in bank1 for * kickstart/wakeup features. The DS1685/DS1687 manual states that a * "don't care" value ranging from 0xc0 to 0xff may be written into one or * more of the three alarm bytes to act as a wildcard value. The fourth * byte doesn't support a "don't care" value. */ static int ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 seconds, minutes, hours, mday, ctrlb, ctrlc; int ret; /* Fetch the alarm info from the RTC alarm registers. */ ds1685_rtc_begin_data_access(rtc); seconds = rtc->read(rtc, RTC_SECS_ALARM); minutes = rtc->read(rtc, RTC_MINS_ALARM); hours = rtc->read(rtc, RTC_HRS_ALARM); mday = rtc->read(rtc, RTC_MDAY_ALARM); ctrlb = rtc->read(rtc, RTC_CTRL_B); ctrlc = rtc->read(rtc, RTC_CTRL_C); ds1685_rtc_end_data_access(rtc); /* Check the month date for validity. */ ret = ds1685_rtc_check_mday(rtc, mday); if (ret) return ret; /* * Check the three alarm bytes. * * The Linux RTC system doesn't support the "don't care" capability * of this RTC chip. We check for it anyways in case support is * added in the future and only assign when we care. */ if (likely(seconds < 0xc0)) alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK, RTC_SECS_BIN_MASK); if (likely(minutes < 0xc0)) alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK, RTC_MINS_BIN_MASK); if (likely(hours < 0xc0)) alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK, RTC_HRS_24_BIN_MASK); /* Write the data to rtc_wkalrm. */ alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK, RTC_MDAY_BIN_MASK); alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE); alrm->pending = !!(ctrlc & RTC_CTRL_C_AF); return 0; } /** * ds1685_rtc_set_alarm - sets the alarm in registers. * @dev: pointer to device structure. * @alrm: pointer to rtc_wkalrm structure. */ static int ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct ds1685_priv *rtc = dev_get_drvdata(dev); u8 ctrlb, seconds, minutes, hours, mday; int ret; /* Fetch the alarm info and convert to BCD. */ seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec, RTC_SECS_BIN_MASK, RTC_SECS_BCD_MASK); minutes = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_min, RTC_MINS_BIN_MASK, RTC_MINS_BCD_MASK); hours = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_hour, RTC_HRS_24_BIN_MASK, RTC_HRS_24_BCD_MASK); mday = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_mday, RTC_MDAY_BIN_MASK, RTC_MDAY_BCD_MASK); /* Check the month date for validity. */ ret = ds1685_rtc_check_mday(rtc, mday); if (ret) return ret; /* * Check the three alarm bytes. * * The Linux RTC system doesn't support the "don't care" capability * of this RTC chip because rtc_valid_tm tries to validate every * field, and we only support four fields. We put the support * here anyways for the future. */ if (unlikely(seconds >= 0xc0)) seconds = 0xff; if (unlikely(minutes >= 0xc0)) minutes = 0xff; if (unlikely(hours >= 0xc0)) hours = 0xff; alrm->time.tm_mon = -1; alrm->time.tm_year = -1; alrm->time.tm_wday = -1; alrm->time.tm_yday = -1; alrm->time.tm_isdst = -1; /* Disable the alarm interrupt first. */ ds1685_rtc_begin_data_access(rtc); ctrlb = rtc->read(rtc, RTC_CTRL_B); rtc->write(rtc, RTC_CTRL_B, (ctrlb & ~(RTC_CTRL_B_AIE))); /* Read ctrlc to clear RTC_CTRL_C_AF. */ rtc->read(rtc, RTC_CTRL_C); /* * Set the data mode to use and store the time values in the