1440 lines · 41.0 KB · C
RawDownload
// 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 the

Lines 1–500 of 1440.