// 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 <[email protected]>. * Copyright (C) 2009 Matthias Fuchs <[email protected]>. * * 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) … #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) { … } /** * 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) { … } /* ----------------------------------------------------------------------- */ /* * 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) { … } /** * 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) { … } /* ----------------------------------------------------------------------- */ /* 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* /dev/rtcX Interface functions */ /** * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off. * @dev: pointer to device structure. * @enabled: flag indicating whether to enable or disable. */ static int ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { … } /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* IRQ handler */ /** * ds1685_rtc_extended_irq - take care of extended interrupts * @rtc: pointer to the ds1685 rtc structure. * @pdev: platform device pointer. */ static void ds1685_rtc_extended_irq(struct ds1685_priv *rtc, struct platform_device *pdev) { … } /** * ds1685_rtc_irq_handler - IRQ handler. * @irq: IRQ number. * @dev_id: platform device pointer. */ static irqreturn_t ds1685_rtc_irq_handler(int irq, void *dev_id) { … } /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* ProcFS interface */ #ifdef CONFIG_PROC_FS #define NUM_REGS … #define NUM_BITS … #define NUM_SPACES … /* * Periodic Interrupt Rates. */ static const char *ds1685_rtc_pirq_rate[16] = …; /* * Square-Wave Output Frequencies. */ static const char *ds1685_rtc_sqw_freq[16] = …; /** * ds1685_rtc_proc - procfs access function. * @dev: pointer to device structure. * @seq: pointer to seq_file structure. */ static int ds1685_rtc_proc(struct device *dev, struct seq_file *seq) { … } #else #define ds1685_rtc_proc … #endif /* CONFIG_PROC_FS */ /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* RTC Class operations */ static const struct rtc_class_ops ds1685_rtc_ops = …; /* ----------------------------------------------------------------------- */ static int ds1685_nvram_read(void *priv, unsigned int pos, void *val, size_t size) { … } static int ds1685_nvram_write(void *priv, unsigned int pos, void *val, size_t size) { … } /* ----------------------------------------------------------------------- */ /* SysFS interface */ /** * ds1685_rtc_sysfs_battery_show - sysfs file for main battery status. * @dev: pointer to device structure. * @attr: pointer to device_attribute structure. * @buf: pointer to char array to hold the output. */ static ssize_t ds1685_rtc_sysfs_battery_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL); /** * ds1685_rtc_sysfs_auxbatt_show - sysfs file for aux battery status. * @dev: pointer to device structure. * @attr: pointer to device_attribute structure. * @buf: pointer to char array to hold the output. */ static ssize_t ds1685_rtc_sysfs_auxbatt_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL); /** * ds1685_rtc_sysfs_serial_show - sysfs file for silicon serial number. * @dev: pointer to device structure. * @attr: pointer to device_attribute structure. * @buf: pointer to char array to hold the output. */ static ssize_t ds1685_rtc_sysfs_serial_show(struct device *dev, struct device_attribute *attr, char *buf) { … } static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL); /* * struct ds1685_rtc_sysfs_misc_attrs - list for misc RTC features. */ static struct attribute* ds1685_rtc_sysfs_misc_attrs[] = …; /* * struct ds1685_rtc_sysfs_misc_grp - attr group for misc RTC features. */ static const struct attribute_group ds1685_rtc_sysfs_misc_grp = …; /* ----------------------------------------------------------------------- */ /* Driver Probe/Removal */ /** * ds1685_rtc_probe - initializes rtc driver. * @pdev: pointer to platform_device structure. */ static int ds1685_rtc_probe(struct platform_device *pdev) { … } /** * ds1685_rtc_remove - removes rtc driver. * @pdev: pointer to platform_device structure. */ static void ds1685_rtc_remove(struct platform_device *pdev) { … } /* * ds1685_rtc_driver - rtc driver properties. */ static struct platform_driver ds1685_rtc_driver = …; module_platform_driver(…) …; /* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */ /* Poweroff function */ /** * ds1685_rtc_poweroff - uses the RTC chip to power the system off. * @pdev: pointer to platform_device structure. */ void __noreturn ds1685_rtc_poweroff(struct platform_device *pdev) { … } EXPORT_SYMBOL_GPL(…); /* ----------------------------------------------------------------------- */ MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_ALIAS(…) …;