[v3,10/14] rtc: pcf2127: read and validate PCF2131 device signature

Message ID 20221215150214.1109074-11-hugo@hugovil.com
State New
Headers
Series rtc: pcf2127: add PCF2131 driver |

Commit Message

Hugo Villeneuve Dec. 15, 2022, 3:02 p.m. UTC
  From: Hugo Villeneuve <hvilleneuve@dimonoff.com>

Make sure the device we are probing is really the device we are
interested in.

Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
---
 drivers/rtc/rtc-pcf2127.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
  

Comments

Alexandre Belloni Jan. 20, 2023, 5:01 p.m. UTC | #1
On 15/12/2022 10:02:11-0500, Hugo Villeneuve wrote:
> From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> 
> Make sure the device we are probing is really the device we are
> interested in.
> 
> Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> ---
>  drivers/rtc/rtc-pcf2127.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
> index 241189ee4a05..e4b78b9c03f9 100644
> --- a/drivers/rtc/rtc-pcf2127.c
> +++ b/drivers/rtc/rtc-pcf2127.c
> @@ -193,11 +193,13 @@ struct pcf21xx_config {
>  	unsigned int has_nvmem:1;
>  	unsigned int has_bit_wd_ctl_cd0:1;
>  	unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */
> +	unsigned int has_reset_reg:1; /* If variant has a reset register. */
>  	u8 regs_td_base; /* Time/data base registers. */
>  	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. */
> +	u8 reg_reset;  /* Reset register if available. */
>  	unsigned int ts_count;
>  	struct pcf21xx_ts_config ts[4];
>  	struct attribute_group attribute_group;
> @@ -882,6 +884,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
>  		.has_nvmem = 1,
>  		.has_bit_wd_ctl_cd0 = 1,
>  		.has_int_a_b = 0,
> +		.has_reset_reg = 0,
>  		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
>  		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
>  		.reg_wd_ctl = PCF2127_REG_WD_CTL,
> @@ -906,6 +909,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
>  		.has_nvmem = 0,
>  		.has_bit_wd_ctl_cd0 = 0,
>  		.has_int_a_b = 0,
> +		.has_reset_reg = 0,
>  		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
>  		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
>  		.reg_wd_ctl = PCF2127_REG_WD_CTL,
> @@ -930,11 +934,13 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
>  		.has_nvmem = 0,
>  		.has_bit_wd_ctl_cd0 = 0,
>  		.has_int_a_b = 1,
> +		.has_reset_reg = 1,
>  		.regs_td_base = PCF2131_REG_TIME_DATE_BASE,
>  		.regs_alarm_base = PCF2131_REG_ALARM_BASE,
>  		.reg_wd_ctl = PCF2131_REG_WD_CTL,
>  		.reg_wd_val = PCF2131_REG_WD_VAL,
>  		.reg_clkout = PCF2131_REG_CLKOUT,
> +		.reg_reset  = PCF2131_REG_SR_RESET,
>  		.ts_count = 4,
>  		.ts[0] = {
>  			.regs_base = PCF2131_REG_TS1_BASE,
> @@ -1075,6 +1081,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
>  	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features);
>  	clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
>  
> +	/* Read device signature if available. */
> +	if (pcf2127->cfg->has_reset_reg) {
> +		ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_reset, &val);
> +		if (ret < 0) {
> +			dev_err(dev, "reading RESET register failed\n");

This is too verbose, please cut down on the number of strings you are
adding.

> +			return ret;
> +		}
> +
> +		if (val != PCF2131_SR_RESET_READ_PATTERN) {
> +			dev_err(dev, "invalid device signature: $%02X\n", (u8)val);

I'm also not convinced this is actually useful. This may have to be
updated for the next rtc the driver will support and what if this
contradicts what the device tree is claiming at this address?

> +			return -ENODEV;
> +		}
> +	}
> +
>  	if (alarm_irq > 0) {
>  		unsigned long flags;
>  
> -- 
> 2.30.2
>
  
Hugo Villeneuve Jan. 23, 2023, 5:31 p.m. UTC | #2
On Fri, 20 Jan 2023 18:01:35 +0100
Alexandre Belloni <alexandre.belloni@bootlin.com> wrote:

> On 15/12/2022 10:02:11-0500, Hugo Villeneuve wrote:
> > From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> > 
> > Make sure the device we are probing is really the device we are
> > interested in.
> > 
> > Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> > ---
> >  drivers/rtc/rtc-pcf2127.c | 20 ++++++++++++++++++++
> >  1 file changed, 20 insertions(+)
> > 
> > diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
> > index 241189ee4a05..e4b78b9c03f9 100644
> > --- a/drivers/rtc/rtc-pcf2127.c
> > +++ b/drivers/rtc/rtc-pcf2127.c
> > @@ -193,11 +193,13 @@ struct pcf21xx_config {
> >  	unsigned int has_nvmem:1;
> >  	unsigned int has_bit_wd_ctl_cd0:1;
> >  	unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */
> > +	unsigned int has_reset_reg:1; /* If variant has a reset register. */
> >  	u8 regs_td_base; /* Time/data base registers. */
> >  	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. */
> > +	u8 reg_reset;  /* Reset register if available. */
> >  	unsigned int ts_count;
> >  	struct pcf21xx_ts_config ts[4];
> >  	struct attribute_group attribute_group;
> > @@ -882,6 +884,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
> >  		.has_nvmem = 1,
> >  		.has_bit_wd_ctl_cd0 = 1,
> >  		.has_int_a_b = 0,
> > +		.has_reset_reg = 0,
> >  		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
> >  		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
> >  		.reg_wd_ctl = PCF2127_REG_WD_CTL,
> > @@ -906,6 +909,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
> >  		.has_nvmem = 0,
> >  		.has_bit_wd_ctl_cd0 = 0,
> >  		.has_int_a_b = 0,
> > +		.has_reset_reg = 0,
> >  		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
> >  		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
> >  		.reg_wd_ctl = PCF2127_REG_WD_CTL,
> > @@ -930,11 +934,13 @@ static struct pcf21xx_config pcf21xx_cfg[] = {
> >  		.has_nvmem = 0,
> >  		.has_bit_wd_ctl_cd0 = 0,
> >  		.has_int_a_b = 1,
> > +		.has_reset_reg = 1,
> >  		.regs_td_base = PCF2131_REG_TIME_DATE_BASE,
> >  		.regs_alarm_base = PCF2131_REG_ALARM_BASE,
> >  		.reg_wd_ctl = PCF2131_REG_WD_CTL,
> >  		.reg_wd_val = PCF2131_REG_WD_VAL,
> >  		.reg_clkout = PCF2131_REG_CLKOUT,
> > +		.reg_reset  = PCF2131_REG_SR_RESET,
> >  		.ts_count = 4,
> >  		.ts[0] = {
> >  			.regs_base = PCF2131_REG_TS1_BASE,
> > @@ -1075,6 +1081,20 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
> >  	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features);
> >  	clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
> >  
> > +	/* Read device signature if available. */
> > +	if (pcf2127->cfg->has_reset_reg) {
> > +		ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_reset, &val);
> > +		if (ret < 0) {
> > +			dev_err(dev, "reading RESET register failed\n");
> 
> This is too verbose, please cut down on the number of strings you are
> adding.

See comment below.

> 
> > +			return ret;
> > +		}
> > +
> > +		if (val != PCF2131_SR_RESET_READ_PATTERN) {
> > +			dev_err(dev, "invalid device signature: $%02X\n", (u8)val);
> 
> I'm also not convinced this is actually useful. This may have to be
> updated for the next rtc the driver will support and what if this
> contradicts what the device tree is claiming at this address?

I will drop that section.


> > +			return -ENODEV;
> > +		}
> > +	}
> > +
> >  	if (alarm_irq > 0) {
> >  		unsigned long flags;
> >  
> > -- 
> > 2.30.2
> > 
> 
> -- 
> Alexandre Belloni, co-owner and COO, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>
  

Patch

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 241189ee4a05..e4b78b9c03f9 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -193,11 +193,13 @@  struct pcf21xx_config {
 	unsigned int has_nvmem:1;
 	unsigned int has_bit_wd_ctl_cd0:1;
 	unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */
+	unsigned int has_reset_reg:1; /* If variant has a reset register. */
 	u8 regs_td_base; /* Time/data base registers. */
 	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. */
+	u8 reg_reset;  /* Reset register if available. */
 	unsigned int ts_count;
 	struct pcf21xx_ts_config ts[4];
 	struct attribute_group attribute_group;
@@ -882,6 +884,7 @@  static struct pcf21xx_config pcf21xx_cfg[] = {
 		.has_nvmem = 1,
 		.has_bit_wd_ctl_cd0 = 1,
 		.has_int_a_b = 0,
+		.has_reset_reg = 0,
 		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
 		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
 		.reg_wd_ctl = PCF2127_REG_WD_CTL,
@@ -906,6 +909,7 @@  static struct pcf21xx_config pcf21xx_cfg[] = {
 		.has_nvmem = 0,
 		.has_bit_wd_ctl_cd0 = 0,
 		.has_int_a_b = 0,
+		.has_reset_reg = 0,
 		.regs_td_base = PCF2127_REG_TIME_DATE_BASE,
 		.regs_alarm_base = PCF2127_REG_ALARM_BASE,
 		.reg_wd_ctl = PCF2127_REG_WD_CTL,
@@ -930,11 +934,13 @@  static struct pcf21xx_config pcf21xx_cfg[] = {
 		.has_nvmem = 0,
 		.has_bit_wd_ctl_cd0 = 0,
 		.has_int_a_b = 1,
+		.has_reset_reg = 1,
 		.regs_td_base = PCF2131_REG_TIME_DATE_BASE,
 		.regs_alarm_base = PCF2131_REG_ALARM_BASE,
 		.reg_wd_ctl = PCF2131_REG_WD_CTL,
 		.reg_wd_val = PCF2131_REG_WD_VAL,
 		.reg_clkout = PCF2131_REG_CLKOUT,
+		.reg_reset  = PCF2131_REG_SR_RESET,
 		.ts_count = 4,
 		.ts[0] = {
 			.regs_base = PCF2131_REG_TS1_BASE,
@@ -1075,6 +1081,20 @@  static int pcf2127_probe(struct device *dev, struct regmap *regmap,
 	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features);
 	clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features);
 
+	/* Read device signature if available. */
+	if (pcf2127->cfg->has_reset_reg) {
+		ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_reset, &val);
+		if (ret < 0) {
+			dev_err(dev, "reading RESET register failed\n");
+			return ret;
+		}
+
+		if (val != PCF2131_SR_RESET_READ_PATTERN) {
+			dev_err(dev, "invalid device signature: $%02X\n", (u8)val);
+			return -ENODEV;
+		}
+	}
+
 	if (alarm_irq > 0) {
 		unsigned long flags;