linux/drivers/rtc/rtc-pcf2127.c

// 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 <[email protected]>
 *
 * Watchdog and tamper functions
 * Author: Bruno Thomsen <[email protected]>
 *
 * PCF2131 support
 * Author: Hugo Villeneuve <[email protected]>
 *
 * 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/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
#define PCF2127_BIT_CTRL1_POR_OVRD
#define PCF2127_BIT_CTRL1_TSF1
#define PCF2127_BIT_CTRL1_STOP
/* Control register 2 */
#define PCF2127_REG_CTRL2
#define PCF2127_BIT_CTRL2_AIE
#define PCF2127_BIT_CTRL2_TSIE
#define PCF2127_BIT_CTRL2_AF
#define PCF2127_BIT_CTRL2_TSF2
#define PCF2127_BIT_CTRL2_WDTF
/* Control register 3 */
#define PCF2127_REG_CTRL3
#define PCF2127_BIT_CTRL3_BLIE
#define PCF2127_BIT_CTRL3_BIE
#define PCF2127_BIT_CTRL3_BLF
#define PCF2127_BIT_CTRL3_BF
#define PCF2127_BIT_CTRL3_BTSE
/* Time and date registers */
#define PCF2127_REG_TIME_BASE
#define PCF2127_BIT_SC_OSF
/* Alarm registers */
#define PCF2127_REG_ALARM_BASE
#define PCF2127_BIT_ALARM_AE
/* CLKOUT control register */
#define PCF2127_REG_CLKOUT
#define PCF2127_BIT_CLKOUT_OTPR
/* Watchdog registers */
#define PCF2127_REG_WD_CTL
#define PCF2127_BIT_WD_CTL_TF0
#define PCF2127_BIT_WD_CTL_TF1
#define PCF2127_BIT_WD_CTL_CD0
#define PCF2127_BIT_WD_CTL_CD1
#define PCF2127_REG_WD_VAL
/* Tamper timestamp1 registers */
#define PCF2127_REG_TS1_BASE
#define PCF2127_BIT_TS_CTRL_TSOFF
#define PCF2127_BIT_TS_CTRL_TSM
/*
 * 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
#define PCF2127_REG_RAM_WRT_CMD
#define PCF2127_REG_RAM_RD_CMD

/* Watchdog timer value constants */
#define PCF2127_WD_VAL_STOP
/* PCF2127/29 watchdog timer value constants */
#define PCF2127_WD_CLOCK_HZ_X1000
#define PCF2127_WD_MIN_HW_HEARTBEAT_MS
/* PCF2131 watchdog timer value constants */
#define PCF2131_WD_CLOCK_HZ_X1000
#define PCF2131_WD_MIN_HW_HEARTBEAT_MS

#define PCF2127_WD_DEFAULT_TIMEOUT_S

/* Mask for currently enabled interrupts */
#define PCF2127_CTRL1_IRQ_MASK
#define PCF2127_CTRL2_IRQ_MASK

#define PCF2127_MAX_TS_SUPPORTED

/* Control register 4 */
#define PCF2131_REG_CTRL4
#define PCF2131_BIT_CTRL4_TSF4
#define PCF2131_BIT_CTRL4_TSF3
#define PCF2131_BIT_CTRL4_TSF2
#define PCF2131_BIT_CTRL4_TSF1
/* Control register 5 */
#define PCF2131_REG_CTRL5
#define PCF2131_BIT_CTRL5_TSIE4
#define PCF2131_BIT_CTRL5_TSIE3
#define PCF2131_BIT_CTRL5_TSIE2
#define PCF2131_BIT_CTRL5_TSIE1
/* Software reset register */
#define PCF2131_REG_SR_RESET
#define PCF2131_SR_RESET_READ_PATTERN
#define PCF2131_SR_RESET_CPR_CMD
/* Time and date registers */
#define PCF2131_REG_TIME_BASE
/* Alarm registers */
#define PCF2131_REG_ALARM_BASE
/* CLKOUT control register */
#define PCF2131_REG_CLKOUT
/* Watchdog registers */
#define PCF2131_REG_WD_CTL
#define PCF2131_REG_WD_VAL
/* Tamper timestamp1 registers */
#define PCF2131_REG_TS1_BASE
/* Tamper timestamp2 registers */
#define PCF2131_REG_TS2_BASE
/* Tamper timestamp3 registers */
#define PCF2131_REG_TS3_BASE
/* Tamper timestamp4 registers */
#define PCF2131_REG_TS4_BASE
/* Interrupt mask registers */
#define PCF2131_REG_INT_A_MASK1
#define PCF2131_REG_INT_A_MASK2
#define PCF2131_REG_INT_B_MASK1
#define PCF2131_REG_INT_B_MASK2
#define PCF2131_BIT_INT_BLIE
#define PCF2131_BIT_INT_BIE
#define PCF2131_BIT_INT_AIE
#define PCF2131_BIT_INT_WD_CD
#define PCF2131_BIT_INT_SI
#define PCF2131_BIT_INT_MI
#define PCF2131_CTRL2_IRQ_MASK
#define PCF2131_CTRL4_IRQ_MASK

enum pcf21xx_type {};

struct pcf21xx_ts_config {};

struct pcf21xx_config {};

struct pcf2127 {};

/*
 * 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)
{}

static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
{}

static int pcf2127_rtc_ioctl(struct device *dev,
				unsigned int cmd, unsigned long arg)
{}

static int pcf2127_nvmem_read(void *priv, unsigned int offset,
			      void *val, size_t bytes)
{}

static int pcf2127_nvmem_write(void *priv, unsigned int offset,
			       void *val, size_t bytes)
{}

/* watchdog driver */

static int pcf2127_wdt_ping(struct watchdog_device *wdd)
{}

/*
 * 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.
 */
static int pcf2127_wdt_active_ping(struct watchdog_device *wdd)
{}

static int pcf2127_wdt_start(struct watchdog_device *wdd)
{}

static int pcf2127_wdt_stop(struct watchdog_device *wdd)
{}

static int pcf2127_wdt_set_timeout(struct watchdog_device *wdd,
				   unsigned int new_timeout)
{}

static const struct watchdog_info pcf2127_wdt_info =;

static const struct watchdog_ops pcf2127_watchdog_ops =;

/*
 * Compute watchdog period, t, in seconds, from the WATCHDG_TIM_VAL register
 * value, n, and the clock frequency, f1000, in Hz x 1000.
 *
 * The PCF2127/29 datasheet gives t as:
 *   t = n / f
 * The PCF2131 datasheet gives t as:
 *   t = (n - 1) / f
 * For both variants, the watchdog is triggered when the WATCHDG_TIM_VAL reaches
 * the value 1, and not zero. Consequently, the equation from the PCF2131
 * datasheet seems to be the correct one for both variants.
 */
static int pcf2127_watchdog_get_period(int n, int f1000)
{}

static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
{}

/* Alarm */
static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{}

static int pcf2127_rtc_alarm_irq_enable(struct device *dev, u32 enable)
{}

static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{}

/*
 * This function reads one timestamp function data, caller is responsible for
 * calling pcf2127_wdt_active_ping()
 */
static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts,
			       int ts_id)
{
	struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
	struct rtc_time tm;
	int ret;
	unsigned char data[7];

	ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base,
			       data, sizeof(data));
	if (ret) {
		dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
		return ret;
	}

	dev_dbg(dev,
		"%s: raw data is ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n",
		__func__, data[1], data[2], data[3], data[4], data[5], data[6]);

	tm.tm_sec = bcd2bin(data[1] & 0x7F);
	tm.tm_min = bcd2bin(data[2] & 0x7F);
	tm.tm_hour = bcd2bin(data[3] & 0x3F);
	tm.tm_mday = bcd2bin(data[4] & 0x3F);
	/* TS_MO register (month) value range: 1-12 */
	tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1;
	tm.tm_year = bcd2bin(data[6]);
	if (tm.tm_year < 70)
		tm.tm_year += 100; /* assume we are in 1970...2069 */

	ret = rtc_valid_tm(&tm);
	if (ret) {
		dev_err(dev, "Invalid timestamp. ret=%d\n", ret);
		return ret;
	}

	*ts = rtc_tm_to_time64(&tm);
	return 0;
};

static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id)
{}

static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
{}

static const struct rtc_class_ops pcf2127_rtc_ops =;

/* sysfs interface */

static ssize_t timestamp_store(struct device *dev,
			       struct device_attribute *attr,
			       const char *buf, size_t count, int ts_id)
{}

static ssize_t timestamp0_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	return timestamp_store(dev, attr, buf, count, 0);
};

static ssize_t timestamp1_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	return timestamp_store(dev, attr, buf, count, 1);
};

static ssize_t timestamp2_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	return timestamp_store(dev, attr, buf, count, 2);
};

static ssize_t timestamp3_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
	return timestamp_store(dev, attr, buf, count, 3);
};

static ssize_t timestamp_show(struct device *dev,
			      struct device_attribute *attr, char *buf,
			      int ts_id)
{}

static ssize_t timestamp0_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	return timestamp_show(dev, attr, buf, 0);
};

static ssize_t timestamp1_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	return timestamp_show(dev, attr, buf, 1);
};

static ssize_t timestamp2_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	return timestamp_show(dev, attr, buf, 2);
};

static ssize_t timestamp3_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	return timestamp_show(dev, attr, buf, 3);
};

static DEVICE_ATTR_RW(timestamp0);
static DEVICE_ATTR_RW(timestamp1);
static DEVICE_ATTR_RW(timestamp2);
static DEVICE_ATTR_RW(timestamp3);

static struct attribute *pcf2127_attrs[] =;

static struct attribute *pcf2131_attrs[] =;

static struct pcf21xx_config pcf21xx_cfg[] =;

/*
 * Enable timestamp function and corresponding interrupt(s).
 */
static int pcf2127_enable_ts(struct device *dev, int ts_id)
{}

/* Route all interrupt sources to INT A pin. */
static int pcf2127_configure_interrupt_pins(struct device *dev)
{}

static int pcf2127_probe(struct device *dev, struct regmap *regmap,
			 int alarm_irq, const struct pcf21xx_config *config)
{}

#ifdef CONFIG_OF
static const struct of_device_id pcf2127_of_match[] =;
MODULE_DEVICE_TABLE(of, pcf2127_of_match);
#endif

#if IS_ENABLED(CONFIG_I2C)

static int pcf2127_i2c_write(void *context, const void *data, size_t count)
{}

static int pcf2127_i2c_gather_write(void *context,
				const void *reg, size_t reg_size,
				const void *val, size_t val_size)
{}

static int pcf2127_i2c_read(void *context, const void *reg, size_t reg_size,
				void *val, size_t val_size)
{}

/*
 * The reason we need this custom regmap_bus instead of using regmap_init_i2c()
 * is that the STOP condition is required between set register address and
 * read register data when reading from registers.
 */
static const struct regmap_bus pcf2127_i2c_regmap =;

static struct i2c_driver pcf2127_i2c_driver;

static const struct i2c_device_id pcf2127_i2c_id[] =;
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);

static int pcf2127_i2c_probe(struct i2c_client *client)
{}

static struct i2c_driver pcf2127_i2c_driver =;

static int pcf2127_i2c_register_driver(void)
{}

static void pcf2127_i2c_unregister_driver(void)
{}

#else

static int pcf2127_i2c_register_driver(void)
{
	return 0;
}

static void pcf2127_i2c_unregister_driver(void)
{
}

#endif

#if IS_ENABLED(CONFIG_SPI_MASTER)

static struct spi_driver pcf2127_spi_driver;
static const struct spi_device_id pcf2127_spi_id[];

static int pcf2127_spi_probe(struct spi_device *spi)
{}

static const struct spi_device_id pcf2127_spi_id[] =;
MODULE_DEVICE_TABLE(spi, pcf2127_spi_id);

static struct spi_driver pcf2127_spi_driver =;

static int pcf2127_spi_register_driver(void)
{}

static void pcf2127_spi_unregister_driver(void)
{}

#else

static int pcf2127_spi_register_driver(void)
{
	return 0;
}

static void pcf2127_spi_unregister_driver(void)
{
}

#endif

static int __init pcf2127_init(void)
{}
module_init()

static void __exit pcf2127_exit(void)
{}
module_exit()

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();