rtc: pcf2127: add support for multiple TS functions
This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com> Link: https://lore.kernel.org/r/20230622145800.2442116-11-hugo@hugovil.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
fc16599e01
commit
420cc9e850
1 changed files with 203 additions and 69 deletions
|
@ -59,8 +59,8 @@
|
||||||
#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
|
#define PCF2127_BIT_WD_CTL_CD0 BIT(6)
|
||||||
#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
|
#define PCF2127_BIT_WD_CTL_CD1 BIT(7)
|
||||||
#define PCF2127_REG_WD_VAL 0x11
|
#define PCF2127_REG_WD_VAL 0x11
|
||||||
/* Tamper timestamp registers */
|
/* Tamper timestamp1 registers */
|
||||||
#define PCF2127_REG_TS_CTRL 0x12
|
#define PCF2127_REG_TS1_BASE 0x12
|
||||||
#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6)
|
#define PCF2127_BIT_TS_CTRL_TSOFF BIT(6)
|
||||||
#define PCF2127_BIT_TS_CTRL_TSM BIT(7)
|
#define PCF2127_BIT_TS_CTRL_TSM BIT(7)
|
||||||
/*
|
/*
|
||||||
|
@ -86,12 +86,36 @@
|
||||||
PCF2127_BIT_CTRL2_WDTF | \
|
PCF2127_BIT_CTRL2_WDTF | \
|
||||||
PCF2127_BIT_CTRL2_TSF2)
|
PCF2127_BIT_CTRL2_TSF2)
|
||||||
|
|
||||||
|
#define PCF2127_MAX_TS_SUPPORTED 1
|
||||||
|
|
||||||
enum pcf21xx_type {
|
enum pcf21xx_type {
|
||||||
PCF2127,
|
PCF2127,
|
||||||
PCF2129,
|
PCF2129,
|
||||||
PCF21XX_LAST_ID
|
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 {
|
struct pcf21xx_config {
|
||||||
int type; /* IC variant */
|
int type; /* IC variant */
|
||||||
int max_register;
|
int max_register;
|
||||||
|
@ -102,6 +126,9 @@ struct pcf21xx_config {
|
||||||
u8 reg_wd_ctl; /* Watchdog control register. */
|
u8 reg_wd_ctl; /* Watchdog control register. */
|
||||||
u8 reg_wd_val; /* Watchdog value register. */
|
u8 reg_wd_val; /* Watchdog value register. */
|
||||||
u8 reg_clkout; /* Clkout register. */
|
u8 reg_clkout; /* Clkout register. */
|
||||||
|
unsigned int ts_count;
|
||||||
|
struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED];
|
||||||
|
struct attribute_group attribute_group;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pcf2127 {
|
struct pcf2127 {
|
||||||
|
@ -109,9 +136,9 @@ struct pcf2127 {
|
||||||
struct watchdog_device wdd;
|
struct watchdog_device wdd;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
const struct pcf21xx_config *cfg;
|
const struct pcf21xx_config *cfg;
|
||||||
time64_t ts;
|
|
||||||
bool ts_valid;
|
|
||||||
bool irq_enabled;
|
bool irq_enabled;
|
||||||
|
time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */
|
||||||
|
bool ts_valid[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp valid indication. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -441,18 +468,19 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function reads ctrl2 register, caller is responsible for calling
|
* This function reads one timestamp function data, caller is responsible for
|
||||||
* pcf2127_wdt_active_ping()
|
* calling pcf2127_wdt_active_ping()
|
||||||
*/
|
*/
|
||||||
static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
|
static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts,
|
||||||
|
int ts_id)
|
||||||
{
|
{
|
||||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
||||||
struct rtc_time tm;
|
struct rtc_time tm;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned char data[7];
|
unsigned char data[7];
|
||||||
|
|
||||||
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_TS_CTRL, data,
|
ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base,
|
||||||
sizeof(data));
|
data, sizeof(data));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
|
dev_err(dev, "%s: read error ret=%d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -482,18 +510,21 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts)
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pcf2127_rtc_ts_snapshot(struct device *dev)
|
static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id)
|
||||||
{
|
{
|
||||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Let userspace read the first timestamp */
|
if (ts_id >= pcf2127->cfg->ts_count)
|
||||||
if (pcf2127->ts_valid)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts);
|
/* Let userspace read the first timestamp */
|
||||||
|
if (pcf2127->ts_valid[ts_id])
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
pcf2127->ts_valid = true;
|
pcf2127->ts_valid[ts_id] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
|
static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
|
||||||
|
@ -514,7 +545,7 @@ static irqreturn_t pcf2127_rtc_irq(int irq, void *dev)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
|
if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2)
|
||||||
pcf2127_rtc_ts_snapshot(dev);
|
pcf2127_rtc_ts_snapshot(dev, 0);
|
||||||
|
|
||||||
if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
|
if (ctrl1 & PCF2127_CTRL1_IRQ_MASK)
|
||||||
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
|
regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1,
|
||||||
|
@ -543,29 +574,42 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
|
||||||
|
|
||||||
/* sysfs interface */
|
/* sysfs interface */
|
||||||
|
|
||||||
static ssize_t timestamp0_store(struct device *dev,
|
static ssize_t timestamp_store(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count, int ts_id)
|
||||||
{
|
{
|
||||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (ts_id >= pcf2127->cfg->ts_count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (pcf2127->irq_enabled) {
|
if (pcf2127->irq_enabled) {
|
||||||
pcf2127->ts_valid = false;
|
pcf2127->ts_valid[ts_id] = false;
|
||||||
} else {
|
} else {
|
||||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1,
|
/* Always clear GND interrupt bit. */
|
||||||
PCF2127_BIT_CTRL1_TSF1, 0);
|
ret = regmap_update_bits(pcf2127->regmap,
|
||||||
|
pcf2127->cfg->ts[ts_id].gnd_detect_reg,
|
||||||
|
pcf2127->cfg->ts[ts_id].gnd_detect_bit,
|
||||||
|
0);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret);
|
dev_err(dev, "%s: update TS gnd detect ret=%d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
|
if (pcf2127->cfg->ts[ts_id].inter_detect_bit) {
|
||||||
PCF2127_BIT_CTRL2_TSF2, 0);
|
/* Clear intermediate level interrupt bit if supported. */
|
||||||
|
ret = regmap_update_bits(pcf2127->regmap,
|
||||||
|
pcf2127->cfg->ts[ts_id].inter_detect_reg,
|
||||||
|
pcf2127->cfg->ts[ts_id].inter_detect_bit,
|
||||||
|
0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret);
|
dev_err(dev, "%s: update TS intermediate level detect ret=%d\n",
|
||||||
|
__func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
|
ret = pcf2127_wdt_active_ping(&pcf2127->wdd);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -573,34 +617,63 @@ static ssize_t timestamp0_store(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 timestamp0_show(struct device *dev,
|
static ssize_t timestamp_show(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf,
|
||||||
|
int ts_id)
|
||||||
{
|
{
|
||||||
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent);
|
||||||
unsigned int ctrl1, ctrl2;
|
|
||||||
int ret;
|
int ret;
|
||||||
time64_t ts;
|
time64_t ts;
|
||||||
|
|
||||||
|
if (ts_id >= pcf2127->cfg->ts_count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (pcf2127->irq_enabled) {
|
if (pcf2127->irq_enabled) {
|
||||||
if (!pcf2127->ts_valid)
|
if (!pcf2127->ts_valid[ts_id])
|
||||||
return 0;
|
return 0;
|
||||||
ts = pcf2127->ts;
|
ts = pcf2127->ts[ts_id];
|
||||||
} else {
|
} else {
|
||||||
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1);
|
u8 valid_low = 0;
|
||||||
|
u8 valid_inter = 0;
|
||||||
|
unsigned int ctrl;
|
||||||
|
|
||||||
|
/* Check if TS input pin is driven to GND, supported by all
|
||||||
|
* variants.
|
||||||
|
*/
|
||||||
|
ret = regmap_read(pcf2127->regmap,
|
||||||
|
pcf2127->cfg->ts[ts_id].gnd_detect_reg,
|
||||||
|
&ctrl);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2);
|
valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit;
|
||||||
|
|
||||||
|
if (pcf2127->cfg->ts[ts_id].inter_detect_bit) {
|
||||||
|
/* Check if TS input pin is driven to intermediate level
|
||||||
|
* between GND and supply, if supported by variant.
|
||||||
|
*/
|
||||||
|
ret = regmap_read(pcf2127->regmap,
|
||||||
|
pcf2127->cfg->ts[ts_id].inter_detect_reg,
|
||||||
|
&ctrl);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) &&
|
valid_inter = ctrl & pcf2127->cfg->ts[ts_id].inter_detect_bit;
|
||||||
!(ctrl2 & PCF2127_BIT_CTRL2_TSF2))
|
}
|
||||||
|
|
||||||
|
if (!valid_low && !valid_inter)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = pcf2127_rtc_ts_read(dev->parent, &ts);
|
ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -609,6 +682,12 @@ static ssize_t timestamp0_show(struct device *dev,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return sprintf(buf, "%llu\n", (unsigned long long)ts);
|
return sprintf(buf, "%llu\n", (unsigned long long)ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t timestamp0_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
return timestamp_show(dev, attr, buf, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEVICE_ATTR_RW(timestamp0);
|
static DEVICE_ATTR_RW(timestamp0);
|
||||||
|
@ -618,10 +697,6 @@ static struct attribute *pcf2127_attrs[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group pcf2127_attr_group = {
|
|
||||||
.attrs = pcf2127_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct pcf21xx_config pcf21xx_cfg[] = {
|
static struct pcf21xx_config pcf21xx_cfg[] = {
|
||||||
[PCF2127] = {
|
[PCF2127] = {
|
||||||
.type = PCF2127,
|
.type = PCF2127,
|
||||||
|
@ -633,6 +708,19 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
|
||||||
.reg_wd_ctl = PCF2127_REG_WD_CTL,
|
.reg_wd_ctl = PCF2127_REG_WD_CTL,
|
||||||
.reg_wd_val = PCF2127_REG_WD_VAL,
|
.reg_wd_val = PCF2127_REG_WD_VAL,
|
||||||
.reg_clkout = PCF2127_REG_CLKOUT,
|
.reg_clkout = PCF2127_REG_CLKOUT,
|
||||||
|
.ts_count = 1,
|
||||||
|
.ts[0] = {
|
||||||
|
.reg_base = PCF2127_REG_TS1_BASE,
|
||||||
|
.gnd_detect_reg = PCF2127_REG_CTRL1,
|
||||||
|
.gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1,
|
||||||
|
.inter_detect_reg = PCF2127_REG_CTRL2,
|
||||||
|
.inter_detect_bit = PCF2127_BIT_CTRL2_TSF2,
|
||||||
|
.ie_reg = PCF2127_REG_CTRL2,
|
||||||
|
.ie_bit = PCF2127_BIT_CTRL2_TSIE,
|
||||||
|
},
|
||||||
|
.attribute_group = {
|
||||||
|
.attrs = pcf2127_attrs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[PCF2129] = {
|
[PCF2129] = {
|
||||||
.type = PCF2129,
|
.type = PCF2129,
|
||||||
|
@ -644,9 +732,74 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
|
||||||
.reg_wd_ctl = PCF2127_REG_WD_CTL,
|
.reg_wd_ctl = PCF2127_REG_WD_CTL,
|
||||||
.reg_wd_val = PCF2127_REG_WD_VAL,
|
.reg_wd_val = PCF2127_REG_WD_VAL,
|
||||||
.reg_clkout = PCF2127_REG_CLKOUT,
|
.reg_clkout = PCF2127_REG_CLKOUT,
|
||||||
|
.ts_count = 1,
|
||||||
|
.ts[0] = {
|
||||||
|
.reg_base = PCF2127_REG_TS1_BASE,
|
||||||
|
.gnd_detect_reg = PCF2127_REG_CTRL1,
|
||||||
|
.gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1,
|
||||||
|
.inter_detect_reg = PCF2127_REG_CTRL2,
|
||||||
|
.inter_detect_bit = PCF2127_BIT_CTRL2_TSF2,
|
||||||
|
.ie_reg = PCF2127_REG_CTRL2,
|
||||||
|
.ie_bit = PCF2127_BIT_CTRL2_TSIE,
|
||||||
|
},
|
||||||
|
.attribute_group = {
|
||||||
|
.attrs = pcf2127_attrs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable timestamp function and corresponding interrupt(s).
|
||||||
|
*/
|
||||||
|
static int pcf2127_enable_ts(struct device *dev, int ts_id)
|
||||||
|
{
|
||||||
|
struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (ts_id >= pcf2127->cfg->ts_count) {
|
||||||
|
dev_err(dev, "%s: invalid tamper detection ID (%d)\n",
|
||||||
|
__func__, ts_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable timestamp function. */
|
||||||
|
ret = regmap_update_bits(pcf2127->regmap,
|
||||||
|
pcf2127->cfg->ts[ts_id].reg_base,
|
||||||
|
PCF2127_BIT_TS_CTRL_TSOFF |
|
||||||
|
PCF2127_BIT_TS_CTRL_TSM,
|
||||||
|
PCF2127_BIT_TS_CTRL_TSM);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "%s: tamper detection config (ts%d_ctrl) failed\n",
|
||||||
|
__func__, ts_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TS input pin driven to GND detection is supported by all variants.
|
||||||
|
* Make sure that interrupt bit is defined.
|
||||||
|
*/
|
||||||
|
if (pcf2127->cfg->ts[ts_id].gnd_detect_bit == 0) {
|
||||||
|
dev_err(dev, "%s: tamper detection to GND configuration invalid\n",
|
||||||
|
__func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable interrupt generation when TSF timestamp flag is set.
|
||||||
|
* Interrupt signals are open-drain outputs and can be left floating if
|
||||||
|
* unused.
|
||||||
|
*/
|
||||||
|
ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->ts[ts_id].ie_reg,
|
||||||
|
pcf2127->cfg->ts[ts_id].ie_bit,
|
||||||
|
pcf2127->cfg->ts[ts_id].ie_bit);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "%s: tamper detection TSIE%d config failed\n",
|
||||||
|
__func__, ts_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
||||||
int alarm_irq, const char *name, const struct pcf21xx_config *config)
|
int alarm_irq, const char *name, const struct pcf21xx_config *config)
|
||||||
{
|
{
|
||||||
|
@ -777,34 +930,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable timestamp function and store timestamp of first trigger
|
* Enable timestamp functions 1 to 4.
|
||||||
* event until TSF1 and TSF2 interrupt flags are cleared.
|
|
||||||
*/
|
*/
|
||||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL,
|
for (int i = 0; i < pcf2127->cfg->ts_count; i++) {
|
||||||
PCF2127_BIT_TS_CTRL_TSOFF |
|
ret = pcf2127_enable_ts(dev, i);
|
||||||
PCF2127_BIT_TS_CTRL_TSM,
|
if (ret)
|
||||||
PCF2127_BIT_TS_CTRL_TSM);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n",
|
|
||||||
__func__);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group);
|
||||||
* Enable interrupt generation when TSF1 or TSF2 timestamp flags
|
|
||||||
* are set. Interrupt signal is an open-drain output and can be
|
|
||||||
* left floating if unused.
|
|
||||||
*/
|
|
||||||
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2,
|
|
||||||
PCF2127_BIT_CTRL2_TSIE,
|
|
||||||
PCF2127_BIT_CTRL2_TSIE);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "%s: tamper detection config (ctrl2) failed\n",
|
|
||||||
__func__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: tamper sysfs registering failed\n",
|
dev_err(dev, "%s: tamper sysfs registering failed\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
|
Loading…
Add table
Reference in a new issue