1631 lines · 41.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * An I2C and SPI driver for the NXP PCF2127/29/31 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> * * Watchdog and tamper functions * Author: Bruno Thomsen <bruno.thomsen@gmail.com> * * PCF2131 support * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com> * * based on the other drivers in this same directory. * * Datasheets: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf *             https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf */ #include <linux/i2c.h>#include <linux/spi/spi.h>#include <linux/bcd.h>#include <linux/bitfield.h>#include <linux/rtc.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/of.h>#include <linux/of_irq.h>#include <linux/of_device.h>#include <linux/regmap.h>#include <linux/watchdog.h> /* Control register 1 */#define PCF2127_REG_CTRL1		0x00#define PCF2127_BIT_CTRL1_POR_OVRD		BIT(3)#define PCF2127_BIT_CTRL1_TSF1			BIT(4)#define PCF2127_BIT_CTRL1_STOP			BIT(5)/* Control register 2 */#define PCF2127_REG_CTRL2		0x01#define PCF2127_BIT_CTRL2_AIE			BIT(1)#define PCF2127_BIT_CTRL2_TSIE			BIT(2)#define PCF2127_BIT_CTRL2_AF			BIT(4)#define PCF2127_BIT_CTRL2_TSF2			BIT(5)#define PCF2127_BIT_CTRL2_WDTF			BIT(6)#define PCF2127_BIT_CTRL2_MSF			BIT(7)/* Control register 3 */#define PCF2127_REG_CTRL3		0x02#define PCF2127_BIT_CTRL3_BLIE			BIT(0)#define PCF2127_BIT_CTRL3_BIE			BIT(1)#define PCF2127_BIT_CTRL3_BLF			BIT(2)#define PCF2127_BIT_CTRL3_BF			BIT(3)#define PCF2127_BIT_CTRL3_BTSE			BIT(4)#define PCF2127_CTRL3_PM			GENMASK(7, 5)/* Time and date registers */#define PCF2127_REG_TIME_BASE		0x03#define PCF2127_BIT_SC_OSF			BIT(7)/* Alarm registers */#define PCF2127_REG_ALARM_BASE		0x0A#define PCF2127_BIT_ALARM_AE			BIT(7)/* CLKOUT control register */#define PCF2127_REG_CLKOUT		0x0f#define PCF2127_BIT_CLKOUT_OTPR			BIT(5)/* Watchdog registers */#define PCF2127_REG_WD_CTL		0x10#define PCF2127_BIT_WD_CTL_TF0			BIT(0)#define PCF2127_BIT_WD_CTL_TF1			BIT(1)#define PCF2127_BIT_WD_CTL_CD0			BIT(6)#define PCF2127_BIT_WD_CTL_CD1			BIT(7)#define PCF2127_REG_WD_VAL		0x11/* Tamper timestamp1 registers */#define PCF2127_REG_TS1_BASE		0x12#define PCF2127_BIT_TS_CTRL_TSOFF		BIT(6)#define PCF2127_BIT_TS_CTRL_TSM			BIT(7)/* * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is * battery backed and can survive a power outage. * PCF2129/31 doesn't have this feature. */#define PCF2127_REG_RAM_ADDR_MSB	0x1A#define PCF2127_REG_RAM_WRT_CMD		0x1C#define PCF2127_REG_RAM_RD_CMD		0x1D /* Watchdog timer value constants */#define PCF2127_WD_VAL_STOP		0/* PCF2127/29 watchdog timer value constants */#define PCF2127_WD_CLOCK_HZ_X1000	1000 /* 1Hz */#define PCF2127_WD_MIN_HW_HEARTBEAT_MS	500/* PCF2131 watchdog timer value constants */#define PCF2131_WD_CLOCK_HZ_X1000	250  /* 1/4Hz */#define PCF2131_WD_MIN_HW_HEARTBEAT_MS	4000 #define PCF2127_WD_DEFAULT_TIMEOUT_S	60 /* Mask for currently enabled interrupts */#define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1)#define PCF2127_CTRL2_IRQ_MASK ( \		PCF2127_BIT_CTRL2_AF | \		PCF2127_BIT_CTRL2_WDTF | \		PCF2127_BIT_CTRL2_TSF2 | \		PCF2127_BIT_CTRL2_MSF) #define PCF2127_MAX_TS_SUPPORTED	4 /* Control register 4 */#define PCF2131_REG_CTRL4		0x03#define PCF2131_BIT_CTRL4_TSF4			BIT(4)#define PCF2131_BIT_CTRL4_TSF3			BIT(5)#define PCF2131_BIT_CTRL4_TSF2			BIT(6)#define PCF2131_BIT_CTRL4_TSF1			BIT(7)/* Control register 5 */#define PCF2131_REG_CTRL5		0x04#define PCF2131_BIT_CTRL5_TSIE4			BIT(4)#define PCF2131_BIT_CTRL5_TSIE3			BIT(5)#define PCF2131_BIT_CTRL5_TSIE2			BIT(6)#define PCF2131_BIT_CTRL5_TSIE1			BIT(7)/* Software reset register */#define PCF2131_REG_SR_RESET		0x05#define PCF2131_SR_RESET_READ_PATTERN	(BIT(2) | BIT(5))#define PCF2131_SR_RESET_CPR_CMD	(PCF2131_SR_RESET_READ_PATTERN | BIT(7))/* Time and date registers */#define PCF2131_REG_TIME_BASE		0x07/* Alarm registers */#define PCF2131_REG_ALARM_BASE		0x0E/* CLKOUT control register */#define PCF2131_REG_CLKOUT		0x13/* Watchdog registers */#define PCF2131_REG_WD_CTL		0x35#define PCF2131_REG_WD_VAL		0x36/* Tamper timestamp1 registers */#define PCF2131_REG_TS1_BASE		0x14/* Tamper timestamp2 registers */#define PCF2131_REG_TS2_BASE		0x1B/* Tamper timestamp3 registers */#define PCF2131_REG_TS3_BASE		0x22/* Tamper timestamp4 registers */#define PCF2131_REG_TS4_BASE		0x29/* Interrupt mask registers */#define PCF2131_REG_INT_A_MASK1		0x31#define PCF2131_REG_INT_A_MASK2		0x32#define PCF2131_REG_INT_B_MASK1		0x33#define PCF2131_REG_INT_B_MASK2		0x34#define PCF2131_BIT_INT_BLIE		BIT(0)#define PCF2131_BIT_INT_BIE		BIT(1)#define PCF2131_BIT_INT_AIE		BIT(2)#define PCF2131_BIT_INT_WD_CD		BIT(3)#define PCF2131_BIT_INT_SI		BIT(4)#define PCF2131_BIT_INT_MI		BIT(5)#define PCF2131_CTRL2_IRQ_MASK ( \		PCF2127_BIT_CTRL2_AF | \		PCF2127_BIT_CTRL2_WDTF)#define PCF2131_CTRL4_IRQ_MASK ( \		PCF2131_BIT_CTRL4_TSF4 | \		PCF2131_BIT_CTRL4_TSF3 | \		PCF2131_BIT_CTRL4_TSF2 | \		PCF2131_BIT_CTRL4_TSF1) enum pcf21xx_type {	PCF2127,	PCF2129,	PCF2131,	PCF21XX_LAST_ID}; struct pcf21xx_ts_config {	u8 reg_base; /* Base register to read timestamp values. */ 	/*	 * If the TS input pin is driven to GND, an interrupt can be generated	 * (supported by all variants).	 */	u8 gnd_detect_reg; /* Interrupt control register address. */	u8 gnd_detect_bit; /* Interrupt bit. */ 	/*	 * If the TS input pin is driven to an intermediate level between GND	 * and supply, an interrupt can be generated (optional feature depending	 * on variant).	 */	u8 inter_detect_reg; /* Interrupt control register address. */	u8 inter_detect_bit; /* Interrupt bit. */ 	u8 ie_reg; /* Interrupt enable control register. */	u8 ie_bit; /* Interrupt enable bit. */}; struct pcf21xx_config {	int type; /* IC variant */	int max_register;	unsigned int has_nvmem:1;	unsigned int has_bit_wd_ctl_cd0:1;	unsigned int wd_val_reg_readable:1; /* If watchdog value register can be read. */	unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */	u8 reg_time_base; /* Time/date base register. */	u8 regs_alarm_base; /* Alarm function base registers. */	u8 reg_wd_ctl; /* Watchdog control register. */	u8 reg_wd_val; /* Watchdog value register. */	u8 reg_clkout; /* Clkout register. */	int wdd_clock_hz_x1000; /* Watchdog clock in Hz multiplicated by 1000 */	int wdd_min_hw_heartbeat_ms;	unsigned int ts_count;	struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED];	struct attribute_group attribute_group;}; struct pcf2127 {	struct rtc_device *rtc;	struct watchdog_device wdd;	struct regmap *regmap;	const struct pcf21xx_config *cfg;	bool irq_enabled;	time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */	bool ts_valid[PCF2127_MAX_TS_SUPPORTED];  /* Timestamp valid indication. */}; /* * In the routines that deal directly with the pcf2127 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm){	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);	unsigned char buf[7];	int ret; 	/*	 * Avoid reading CTRL2 register as it causes WD_VAL register	 * value to reset to 0 which means watchdog is stopped.	 */	ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base,			       buf, sizeof(buf));	if (ret) {		dev_err(dev, "%s: read error\n", __func__);		return ret;	} 	/* Clock integrity is not guaranteed when OSF flag is set. */	if (buf[0] & PCF2127_BIT_SC_OSF) {		/*		 * no need clear the flag here,		 * it will be cleared once the new date is saved		 */		dev_warn(dev,			 "oscillator stop detected, date/time is not reliable\n");		return -EINVAL;	} 	dev_dbg(dev,		"%s: raw data is sec=%02x, min=%02x, hr=%02x, "		"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",		__func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); 	tm->tm_sec = bcd2bin(buf[0] & 0x7F);	tm->tm_min = bcd2bin(buf[1] & 0x7F);	tm->tm_hour = bcd2bin(buf[2] & 0x3F);	tm->tm_mday = bcd2bin(buf[3] & 0x3F);	tm->tm_wday = buf[4] & 0x07;	tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1;	tm->tm_year = bcd2bin(buf[6]);	tm->tm_year += 100; 	dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "		"mday=%d, mon=%d, year=%d, wday=%d\n",		__func__,		tm->tm_sec, tm->tm_min, tm->tm_hour,		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 	return 0;} static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm){	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);	unsigned char buf[7];	int i = 0, err; 	dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "		"mday=%d, mon=%d, year=%d, wday=%d\n",		__func__,		tm->tm_sec, tm->tm_min, tm->tm_hour,		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 	/* hours, minutes and seconds */	buf[i++] = bin2bcd(tm->tm_sec);	/* this will also clear OSF flag */	buf[i++] = bin2bcd(tm->tm_min);	buf[i++] = bin2bcd(tm->tm_hour);	buf[i++] = bin2bcd(tm->tm_mday);	buf[i++] = tm->tm_wday & 0x07; 	/* month, 1 - 12 */	buf[i++] = bin2bcd(tm->tm_mon + 1); 	/* year */	buf[i++] = bin2bcd(tm->tm_year - 100); 	/* Write access to time registers:	 * PCF2127/29: no special action required.	 * PCF2131:    requires setting the STOP and CPR bits. STOP bit needs to	 *             be cleared after time registers are updated.	 */	if (pcf2127->cfg->type == PCF2131) {		err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,					 PCF2127_BIT_CTRL1_STOP,					 PCF2127_BIT_CTRL1_STOP);		if (err) {			dev_dbg(dev, "setting STOP bit failed\n");			return err;		} 		err = regmap_write(pcf2127->regmap, PCF2131_REG_SR_RESET,				   PCF2131_SR_RESET_CPR_CMD);		if (err) {			dev_dbg(dev, "sending CPR cmd failed\n");			return err;		}	} 	/* write time register's data */	err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i);	if (err) {		dev_dbg(dev, "%s: err=%d", __func__, err);		return err;	} 	if (pcf2127->cfg->type == PCF2131) {		/* Clear STOP bit (PCF2131 only) after write is completed. */		err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,					 PCF2127_BIT_CTRL1_STOP, 0);		if (err) {			dev_dbg(dev, "clearing STOP bit failed\n");			return err;		}	} 	return 0;} static int pcf2127_param_get(struct device *dev, struct rtc_param *param){	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);	u32 value;	int ret; 	switch (param->param) {	case RTC_PARAM_BACKUP_SWITCH_MODE:		ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &value);		if (ret < 0)			return ret; 		value = FIELD_GET(PCF2127_CTRL3_PM, value); 		if (value < 0x3)			param->uvalue = RTC_BSM_LEVEL;		else if (value < 0x6)			param->uvalue = RTC_BSM_DIRECT;		else			param->uvalue = RTC_BSM_DISABLED; 		break; 	default:		return -EINVAL;	} 	return 0;} static int pcf2127_param_set(struct device *dev, struct rtc_param *param){	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);	u8 mode = 0;	u32 value;	int ret; 	switch (param->param) {	case RTC_PARAM_BACKUP_SWITCH_MODE:		ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &value);		if (ret < 0)			return ret; 		value = FIELD_GET(PCF2127_CTRL3_PM, value); 		if (value > 5)			value -= 5;		else if (value > 2)			value -= 3; 		switch (param->uvalue) {		case RTC_BSM_LEVEL:			break;		case RTC_BSM_DIRECT:			mode = 3;			break;		case RTC_BSM_DISABLED:			if (value == 0)				value = 1;			mode = 5;			break;		default:			return -EINVAL;		} 		return regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3,					  PCF2127_CTRL3_PM,					  FIELD_PREP(PCF2127_CTRL3_PM, mode + value)); 		break; 	default:		return -EINVAL;	} 	return 0;} static int pcf2127_rtc_ioctl(struct device *dev,				unsigned int cmd, unsigned long arg){	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);	int val, touser = 0;	int ret; 	switch (cmd) {	case RTC_VL_READ:		ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &val);		if (ret)			return ret; 		if (val & PCF2127_BIT_CTRL3_BLF)			touser |= RTC_VL_BACKUP_LOW; 		if (val & PCF2127_BIT_CTRL3_BF)			touser |= RTC_VL_BACKUP_SWITCH; 		return put_user(touser, (unsigned int __user *)arg); 	case RTC_VL_CLR:		return regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL3,					  PCF2127_BIT_CTRL3_BF, 0); 	default:		return -ENOIOCTLCMD;	}} static int pcf2127_nvmem_read(void *priv, unsigned int offset,			      void *val, size_t bytes){	struct pcf2127 *pcf2127 = priv;	int ret;	unsigned char offsetbuf[] = { offset >> 8, offset }; 	ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB,				offsetbuf, 2);	if (ret)		return ret; 	return regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_RD_CMD,				val, bytes);} static int pcf2127_nvmem_write(void *priv, unsigned int offset,			       void *val, size_t bytes){	struct pcf2127 *pcf2127 = priv;	int ret;	unsigned char offsetbuf[] = { offset >> 8, offset }; 	ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_ADDR_MSB,				offsetbuf, 2);	if (ret)		return ret; 	return regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_WRT_CMD,				 val, bytes);} /* watchdog driver */ static int pcf2127_wdt_ping(struct watchdog_device *wdd){	int wd_val;	struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); 	/*	 * Compute counter value of WATCHDG_TIM_VAL to obtain desired period	 * in seconds, depending on the source clock frequency.	 */	wd_val = ((wdd->timeout * pcf2127->cfg->wdd_clock_hz_x1000) / 1000) + 1; 	return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wd_val);} /* * Restart watchdog timer if feature is active. * * Note: Reading CTRL2 register causes watchdog to stop which is unfortunate, * since register also contain control/status flags for other features. * Always call this function after reading CTRL2 register. */

Lines 1–500 of 1631.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t