mfd: Support LP3974 RTC
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 4 Jan 2011 05:17:39 +0000 (14:17 +0900)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 14 Jan 2011 11:38:16 +0000 (12:38 +0100)
The first releases of LP3974 have a large delay in RTC registers,
which requires 2 seconds of delay after writing to a rtc register
(recommended by National Semiconductor's engineers)
before reading it.

If "rtc_delay" field of the platform data is true, the rtc driver
assumes that such delays are required. Although we have not seen
LP3974s without requiring such delays, we assume that such LP3974s
will be released soon (or they have done so already) and they are
supported by "lp3974" without setting "rtc_delay" at the platform
data.

This patch adds delays with msleep when writing values to RTC registers
if the platform data has rtc_delay set.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/max8998.c
drivers/regulator/max8998.c
drivers/rtc/rtc-max8998.c
include/linux/mfd/max8998.h

index 5ce00ad5241a0090dc704603f6db00a3ab4f2443..bbfe867326027f514b00645da907f5e31e96fabc 100644 (file)
@@ -42,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
        },
 };
 
+static struct mfd_cell lp3974_devs[] = {
+       {
+               .name = "lp3974-pmic",
+       }, {
+               .name = "lp3974-rtc",
+       },
+};
+
 int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
 {
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
@@ -146,11 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
 
        max8998_irq_init(max8998);
 
-       ret = mfd_add_devices(max8998->dev, -1,
-                             max8998_devs, ARRAY_SIZE(max8998_devs),
-                             NULL, 0);
        pm_runtime_set_active(max8998->dev);
 
+       switch (id->driver_data) {
+       case TYPE_LP3974:
+               ret = mfd_add_devices(max8998->dev, -1,
+                               lp3974_devs, ARRAY_SIZE(lp3974_devs),
+                               NULL, 0);
+               break;
+       case TYPE_MAX8998:
+               ret = mfd_add_devices(max8998->dev, -1,
+                               max8998_devs, ARRAY_SIZE(max8998_devs),
+                               NULL, 0);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
        if (ret < 0)
                goto err;
 
index 7568df6122ab64a9303f1788e151908ad5bdd094..af52ebfc4927fe832c322e643f1d43a4c2cf9321 100644 (file)
@@ -835,6 +835,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max8998_pmic_id[] = {
+       { "max8998-pmic", TYPE_MAX8998 },
+       { "lp3974-pmic", TYPE_LP3974 },
+       { }
+};
+
 static struct platform_driver max8998_pmic_driver = {
        .driver = {
                .name = "max8998-pmic",
@@ -842,6 +848,7 @@ static struct platform_driver max8998_pmic_driver = {
        },
        .probe = max8998_pmic_probe,
        .remove = __devexit_p(max8998_pmic_remove),
+       .id_table = max8998_pmic_id,
 };
 
 static int __init max8998_pmic_init(void)
index f22dee35f330e73554188b246d96eb454b31f06c..3f7bc6b9fefa94186c020503e8614304606d336b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/max8998-private.h>
+#include <linux/delay.h>
 
 #define MAX8998_RTC_SEC                        0x00
 #define MAX8998_RTC_MIN                        0x01
@@ -73,6 +74,7 @@ struct max8998_rtc_info {
        struct i2c_client       *rtc;
        struct rtc_device       *rtc_dev;
        int irq;
+       bool lp3974_bug_workaround;
 };
 
 static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
@@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct max8998_rtc_info *info = dev_get_drvdata(dev);
        u8 data[8];
+       int ret;
 
        max8998_tm_to_data(tm, data);
 
-       return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+       ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
 {
-       return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+       int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
 {
-       return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+       int ret;
+       u8 alarm0_conf = 0x77;
+
+       /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
+       if (info->lp3974_bug_workaround)
+               alarm0_conf = 0x57;
+
+       ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
+
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
+       return ret;
 }
 
 static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        if (ret < 0)
                return ret;
 
+       if (info->lp3974_bug_workaround)
+               msleep(2000);
+
        if (alrm->enabled)
-               return max8998_rtc_start_alarm(info);
+               ret = max8998_rtc_start_alarm(info);
 
-       return 0;
+       return ret;
 }
 
 static int max8998_rtc_alarm_irq_enable(struct device *dev,
@@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
 static int __devinit max8998_rtc_probe(struct platform_device *pdev)
 {
        struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+       struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
        struct max8998_rtc_info *info;
        int ret;
 
@@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
 
        ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
                        "rtc-alarm0", info);
+
        if (ret < 0)
                dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
                        info->irq, ret);
 
+       dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
+       if (pdata->rtc_delay) {
+               info->lp3974_bug_workaround = true;
+               dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
+                               " RTC updates will be extremely slow.\n");
+       }
+
        return 0;
 
 out_rtc:
@@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max8998_rtc_id[] = {
+       { "max8998-rtc", TYPE_MAX8998 },
+       { "lp3974-rtc", TYPE_LP3974 },
+       { }
+};
+
 static struct platform_driver max8998_rtc_driver = {
        .driver         = {
                .name   = "max8998-rtc",
@@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
        },
        .probe          = max8998_rtc_probe,
        .remove         = __devexit_p(max8998_rtc_remove),
+       .id_table       = max8998_rtc_id,
 };
 
 static int __init max8998_rtc_init(void)
index 686a744e63fba3293e299dd1e733bf8fcc00ac48..c22b9a417c35272691dcd2de272c45eff9ce32c1 100644 (file)
@@ -76,6 +76,9 @@ struct max8998_regulator_data {
  * @buck1_set1: BUCK1 gpio pin 1 to set output voltage
  * @buck1_set2: BUCK1 gpio pin 2 to set output voltage
  * @buck2_set3: BUCK2 gpio pin to set output voltage
+ * @wakeup: Allow to wake up from suspend
+ * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
+ * write before reading it.
  */
 struct max8998_platform_data {
        struct max8998_regulator_data   *regulators;
@@ -89,6 +92,7 @@ struct max8998_platform_data {
        int                             buck1_set2;
        int                             buck2_set3;
        bool                            wakeup;
+       bool                            rtc_delay;
 };
 
 #endif /*  __LINUX_MFD_MAX8998_H */