Re: [PATCH v1/1] mfd: i2c issue fix for da9052/53

2013-01-26 Thread Samuel Ortiz
Hi Ashish,

On Fri, Jan 25, 2013 at 02:03:49PM +0530, Ashish Jangam wrote:
> An issue has been reported where the PMIC either locks up or fails to
> respond following a system Reset. This could result in a second write
> in which the bus writes the current content of the write buffer to address
> of the last I2C access.
> 
> The failure case is where this unwanted write transfers incorrect data to
> a critical register.
> 
> This patch fixes this issue to by following any read or write with a dummy 
> read
> to a safe register address. A safe register address is one where the contents
> will not affect the operation of the system.
> 
> Signed-off-by: Ashish Jangam 
> ---
>  drivers/mfd/da9052-i2c.c  |   61 ++
>  include/linux/mfd/da9052/da9052.h |   66 ++--
>  include/linux/mfd/da9052/reg.h|3 ++
>  3 files changed, 126 insertions(+), 4 deletions(-)
Applied to my for-linus branch.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v1/1] mfd: i2c issue fix for da9052/53

2013-01-26 Thread Samuel Ortiz
Hi Ashish,

On Fri, Jan 25, 2013 at 02:03:49PM +0530, Ashish Jangam wrote:
 An issue has been reported where the PMIC either locks up or fails to
 respond following a system Reset. This could result in a second write
 in which the bus writes the current content of the write buffer to address
 of the last I2C access.
 
 The failure case is where this unwanted write transfers incorrect data to
 a critical register.
 
 This patch fixes this issue to by following any read or write with a dummy 
 read
 to a safe register address. A safe register address is one where the contents
 will not affect the operation of the system.
 
 Signed-off-by: Ashish Jangam ashish.jan...@kpitcummins.com
 ---
  drivers/mfd/da9052-i2c.c  |   61 ++
  include/linux/mfd/da9052/da9052.h |   66 ++--
  include/linux/mfd/da9052/reg.h|3 ++
  3 files changed, 126 insertions(+), 4 deletions(-)
Applied to my for-linus branch.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v1/1] mfd: i2c issue fix for da9052/53

2013-01-25 Thread Ashish Jangam
An issue has been reported where the PMIC either locks up or fails to
respond following a system Reset. This could result in a second write
in which the bus writes the current content of the write buffer to address
of the last I2C access.

The failure case is where this unwanted write transfers incorrect data to
a critical register.

This patch fixes this issue to by following any read or write with a dummy read
to a safe register address. A safe register address is one where the contents
will not affect the operation of the system.

Signed-off-by: Ashish Jangam 
---
 drivers/mfd/da9052-i2c.c  |   61 ++
 include/linux/mfd/da9052/da9052.h |   66 ++--
 include/linux/mfd/da9052/reg.h|3 ++
 3 files changed, 126 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index ac74a4d..885e567 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -27,6 +27,66 @@
 #include 
 #endif
 
+/* I2C safe register check */
+static inline bool i2c_safe_reg(unsigned char reg)
+{
+   switch (reg) {
+   case DA9052_STATUS_A_REG:
+   case DA9052_STATUS_B_REG:
+   case DA9052_STATUS_C_REG:
+   case DA9052_STATUS_D_REG:
+   case DA9052_ADC_RES_L_REG:
+   case DA9052_ADC_RES_H_REG:
+   case DA9052_VDD_RES_REG:
+   case DA9052_ICHG_AV_REG:
+   case DA9052_TBAT_RES_REG:
+   case DA9052_ADCIN4_RES_REG:
+   case DA9052_ADCIN5_RES_REG:
+   case DA9052_ADCIN6_RES_REG:
+   case DA9052_TJUNC_RES_REG:
+   case DA9052_TSI_X_MSB_REG:
+   case DA9052_TSI_Y_MSB_REG:
+   case DA9052_TSI_LSB_REG:
+   case DA9052_TSI_Z_MSB_REG:
+   return true;
+   default:
+   return false;
+   }
+}
+
+/*
+ * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC
+ * gets lockup up or fails to respond following a system reset.
+ * This fix is to follow any read or write with a dummy read to a safe
+ * register.
+ */
+int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
+{
+   int val;
+
+   switch (da9052->chip_id) {
+   case DA9052:
+   case DA9053_AA:
+   case DA9053_BA:
+   case DA9053_BB:
+   /* A dummy read to a safe register address. */
+   if (!i2c_safe_reg(reg))
+   return regmap_read(da9052->regmap,
+  DA9052_PARK_REGISTER,
+  );
+   break;
+   default:
+   /*
+* For other chips parking of I2C register
+* to a safe place is not required.
+*/
+   break;
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL(da9052_i2c_fix);
+
 static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
 {
int reg_val, ret;
@@ -83,6 +143,7 @@ static int da9052_i2c_probe(struct i2c_client *client,
 
da9052->dev = >dev;
da9052->chip_irq = client->irq;
+   da9052->fix_io = da9052_i2c_fix;
 
i2c_set_clientdata(client, da9052);
 
diff --git a/include/linux/mfd/da9052/da9052.h 
b/include/linux/mfd/da9052/da9052.h
index 86dd93d..786d02e 100644
--- a/include/linux/mfd/da9052/da9052.h
+++ b/include/linux/mfd/da9052/da9052.h
@@ -99,6 +99,9 @@ struct da9052 {
u8 chip_id;
 
int chip_irq;
+
+   /* SOC I/O transfer related fixes for DA9052/53 */
+   int (*fix_io) (struct da9052 *da9052, unsigned char reg);
 };
 
 /* ADC API */
@@ -113,32 +116,87 @@ static inline int da9052_reg_read(struct da9052 *da9052, 
unsigned char reg)
ret = regmap_read(da9052->regmap, reg, );
if (ret < 0)
return ret;
+
+   if (da9052->fix_io) {
+   ret = da9052->fix_io(da9052, reg);
+   if (ret < 0)
+   return ret;
+   }
+
return val;
 }
 
 static inline int da9052_reg_write(struct da9052 *da9052, unsigned char reg,
unsigned char val)
 {
-   return regmap_write(da9052->regmap, reg, val);
+   int ret;
+
+   ret = regmap_write(da9052->regmap, reg, val);
+   if (ret < 0)
+   return ret;
+
+   if (da9052->fix_io) {
+   ret = da9052->fix_io(da9052, reg);
+   if (ret < 0)
+   return ret;
+   }
+
+   return ret;
 }
 
 static inline int da9052_group_read(struct da9052 *da9052, unsigned char reg,
 unsigned reg_cnt, unsigned char *val)
 {
-   return regmap_bulk_read(da9052->regmap, reg, val, reg_cnt);
+   int ret;
+
+   ret = regmap_bulk_read(da9052->regmap, reg, val, reg_cnt);
+   if (ret < 0)
+   return ret;
+
+   if (da9052->fix_io) {
+   ret = da9052->fix_io(da9052, reg);
+   if (ret < 0)
+   return ret;
+   }
+
+   return ret;
 }
 
 static inline int 

[PATCH v1/1] mfd: i2c issue fix for da9052/53

2013-01-25 Thread Ashish Jangam
An issue has been reported where the PMIC either locks up or fails to
respond following a system Reset. This could result in a second write
in which the bus writes the current content of the write buffer to address
of the last I2C access.

The failure case is where this unwanted write transfers incorrect data to
a critical register.

This patch fixes this issue to by following any read or write with a dummy read
to a safe register address. A safe register address is one where the contents
will not affect the operation of the system.

Signed-off-by: Ashish Jangam ashish.jan...@kpitcummins.com
---
 drivers/mfd/da9052-i2c.c  |   61 ++
 include/linux/mfd/da9052/da9052.h |   66 ++--
 include/linux/mfd/da9052/reg.h|3 ++
 3 files changed, 126 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
index ac74a4d..885e567 100644
--- a/drivers/mfd/da9052-i2c.c
+++ b/drivers/mfd/da9052-i2c.c
@@ -27,6 +27,66 @@
 #include linux/of_device.h
 #endif
 
+/* I2C safe register check */
+static inline bool i2c_safe_reg(unsigned char reg)
+{
+   switch (reg) {
+   case DA9052_STATUS_A_REG:
+   case DA9052_STATUS_B_REG:
+   case DA9052_STATUS_C_REG:
+   case DA9052_STATUS_D_REG:
+   case DA9052_ADC_RES_L_REG:
+   case DA9052_ADC_RES_H_REG:
+   case DA9052_VDD_RES_REG:
+   case DA9052_ICHG_AV_REG:
+   case DA9052_TBAT_RES_REG:
+   case DA9052_ADCIN4_RES_REG:
+   case DA9052_ADCIN5_RES_REG:
+   case DA9052_ADCIN6_RES_REG:
+   case DA9052_TJUNC_RES_REG:
+   case DA9052_TSI_X_MSB_REG:
+   case DA9052_TSI_Y_MSB_REG:
+   case DA9052_TSI_LSB_REG:
+   case DA9052_TSI_Z_MSB_REG:
+   return true;
+   default:
+   return false;
+   }
+}
+
+/*
+ * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC
+ * gets lockup up or fails to respond following a system reset.
+ * This fix is to follow any read or write with a dummy read to a safe
+ * register.
+ */
+int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
+{
+   int val;
+
+   switch (da9052-chip_id) {
+   case DA9052:
+   case DA9053_AA:
+   case DA9053_BA:
+   case DA9053_BB:
+   /* A dummy read to a safe register address. */
+   if (!i2c_safe_reg(reg))
+   return regmap_read(da9052-regmap,
+  DA9052_PARK_REGISTER,
+  val);
+   break;
+   default:
+   /*
+* For other chips parking of I2C register
+* to a safe place is not required.
+*/
+   break;
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL(da9052_i2c_fix);
+
 static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
 {
int reg_val, ret;
@@ -83,6 +143,7 @@ static int da9052_i2c_probe(struct i2c_client *client,
 
da9052-dev = client-dev;
da9052-chip_irq = client-irq;
+   da9052-fix_io = da9052_i2c_fix;
 
i2c_set_clientdata(client, da9052);
 
diff --git a/include/linux/mfd/da9052/da9052.h 
b/include/linux/mfd/da9052/da9052.h
index 86dd93d..786d02e 100644
--- a/include/linux/mfd/da9052/da9052.h
+++ b/include/linux/mfd/da9052/da9052.h
@@ -99,6 +99,9 @@ struct da9052 {
u8 chip_id;
 
int chip_irq;
+
+   /* SOC I/O transfer related fixes for DA9052/53 */
+   int (*fix_io) (struct da9052 *da9052, unsigned char reg);
 };
 
 /* ADC API */
@@ -113,32 +116,87 @@ static inline int da9052_reg_read(struct da9052 *da9052, 
unsigned char reg)
ret = regmap_read(da9052-regmap, reg, val);
if (ret  0)
return ret;
+
+   if (da9052-fix_io) {
+   ret = da9052-fix_io(da9052, reg);
+   if (ret  0)
+   return ret;
+   }
+
return val;
 }
 
 static inline int da9052_reg_write(struct da9052 *da9052, unsigned char reg,
unsigned char val)
 {
-   return regmap_write(da9052-regmap, reg, val);
+   int ret;
+
+   ret = regmap_write(da9052-regmap, reg, val);
+   if (ret  0)
+   return ret;
+
+   if (da9052-fix_io) {
+   ret = da9052-fix_io(da9052, reg);
+   if (ret  0)
+   return ret;
+   }
+
+   return ret;
 }
 
 static inline int da9052_group_read(struct da9052 *da9052, unsigned char reg,
 unsigned reg_cnt, unsigned char *val)
 {
-   return regmap_bulk_read(da9052-regmap, reg, val, reg_cnt);
+   int ret;
+
+   ret = regmap_bulk_read(da9052-regmap, reg, val, reg_cnt);
+   if (ret  0)
+   return ret;
+
+   if (da9052-fix_io) {
+   ret = da9052-fix_io(da9052, reg);
+   if (ret  0)
+   return ret;
+   }
+
+