Patchwork [0/2] rtc: tps6586x: add RTC driver for TI TPS6586x

login
register
mail settings
Submitter Varun Wadekar
Date Jan. 25, 2011, 4:53 a.m.
Message ID <4D3E5731.4000809@nvidia.com>
Download mbox | patch
Permalink /patch/80314/
State New
Headers show

Comments

Varun Wadekar - Jan. 25, 2011, 4:53 a.m.
----
    rtc: tps6586x: add RTC driver for TI TPS6586x

    Signed-off-by: Gary King <gking@nvidia.com>

+MODULE_AUTHOR("NVIDIA Corporation");
+MODULE_LICENSE("GPL");

nvpublic
Olof Johansson - Jan. 25, 2011, 6:19 a.m.
Hi,


On Mon, Jan 24, 2011 at 8:53 PM, Varun Wadekar <vwadekar@nvidia.com> wrote:
> ----
>    rtc: tps6586x: add RTC driver for TI TPS6586x
>
>    Signed-off-by: Gary King <gking@nvidia.com>

Your patch seems to be line wrapped. There seems to be whitespace
damage overall in it.

Please don't put dashes in the changelog, git will strip what's below.

You also numbered the patches 0/2, 1/2 and 2/2 -- 0/<x> is normally
used just for an overall description of the following patches when a
series is posted. Since the two follow-on patches are incremental,
please squash them into this one before posting -- no need to keep
them separate since it's the original submission.

Also, you should add your own Signed-off-by if you're posting it.

>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 48ca713..241c7f7 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -286,6 +286,13 @@ config RTC_DRV_DM355EVM
>     help
>       Supports the RTC firmware in the MSP430 on the DM355 EVM.
>
> +config RTC_DRV_TPS6586X
> +    tristate "TI TPS6586X RTC"
> +    depends on I2C
> +    select MFD_TPS6586X

Shouldn't this be a depend instead of a select? That's how some of the
other MFD RTCs seem to do it.

> +    help
> +      This driver supports TPS6586X RTC
> +
>  config RTC_DRV_TWL92330
>     boolean "TI TWL92330/Menelaus"
>     depends on MENELAUS



-Olof

Patch

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 48ca713..241c7f7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -286,6 +286,13 @@  config RTC_DRV_DM355EVM
     help
       Supports the RTC firmware in the MSP430 on the DM355 EVM.

+config RTC_DRV_TPS6586X
+    tristate "TI TPS6586X RTC"
+    depends on I2C
+    select MFD_TPS6586X
+    help
+      This driver supports TPS6586X RTC
+
 config RTC_DRV_TWL92330
     boolean "TI TWL92330/Menelaus"
     depends on MENELAUS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0f207b3..acd8426 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -91,6 +91,7 @@  obj-$(CONFIG_RTC_DRV_STK17TA8)    += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_STMP)    += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
 obj-$(CONFIG_RTC_DRV_TEST)    += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TPS6586X)    += rtc-tps6586x.o
 obj-$(CONFIG_RTC_DRV_TWL4030)    += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TX4939)    += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
new file mode 100644
index 0000000..f898f40
--- /dev/null
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -0,0 +1,203 @@ 
+/*
+ * drivers/rtc/rtc-tps6586x.c
+ *
+ * RTC driver for TI TPS6586x
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps6586x.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#define TPS_EPOCH    2009
+
+#define RTC_CTRL    0xc0
+#define RTC_ENABLE    (1 << 5)    /* enables tick updates */
+#define RTC_HIRES    (1 << 4)    /* 1Khz or 32Khz updates */
+#define RTC_ALARM1_HI    0xc1
+#define RTC_COUNT4    0xc6
+
+struct tps6586x_rtc {
+    unsigned long     epoch_start;
+    struct rtc_device *rtc;
+};
+
+static inline struct device *to_tps6586x_dev(struct device *dev)
+{
+    return dev->parent;
+}
+
+static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+    struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+    struct device *tps_dev = to_tps6586x_dev(dev);
+    unsigned long long ticks = 0;
+    unsigned long seconds;
+    u8 buff[5];
+    int err;
+    int i;
+
+    err = tps6586x_reads(tps_dev, RTC_COUNT4, sizeof(buff), buff);
+    if (err < 0) {
+        dev_err(dev, "failed to read counter\n");
+        return err;
+    }
+
+    for (i = 0; i < sizeof(buff); i++) {
+        ticks <<= 8;
+        ticks |= buff[i];
+    }
+
+    seconds = ticks >> 10;
+
+    seconds += rtc->epoch_start;
+    rtc_time_to_tm(seconds, tm);
+    return rtc_valid_tm(tm);
+}
+
+static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+    struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+    struct device *tps_dev = to_tps6586x_dev(dev);
+    unsigned long long ticks;
+    unsigned long seconds;
+    u8 buff[5];
+    int err;
+
+    rtc_tm_to_time(tm, &seconds);
+
+    if (WARN_ON(seconds < rtc->epoch_start)) {
+        dev_err(dev, "requested time unsupported\n");
+        return -EINVAL;
+    }
+
+    seconds -= rtc->epoch_start;
+
+    ticks = seconds << 10;
+    buff[0] = (ticks >> 32) & 0xff;
+    buff[1] = (ticks >> 24) & 0xff;
+    buff[2] = (ticks >> 16) & 0xff;
+    buff[3] = (ticks >> 8) & 0xff;
+    buff[4] = ticks & 0xff;
+
+    dev_info(dev, "setting time to %lu seconds (%llu ticks)\n",
+         seconds, ticks);
+
+
+    err = tps6586x_clr_bits(tps_dev, RTC_CTRL, RTC_ENABLE);
+    if (err < 0) {
+        dev_err(dev, "failed to clear RTC_ENABLE\n");
+        return err;
+    }
+
+    err = tps6586x_writes(tps_dev, RTC_COUNT4, sizeof(buff), buff);
+    if (err < 0) {
+        dev_err(dev, "failed to program new time\n");
+        return err;
+    }
+
+    err = tps6586x_set_bits(tps_dev, RTC_CTRL, RTC_ENABLE);
+    if (err < 0) {
+        dev_err(dev, "failed to set RTC_ENABLE\n");
+        return err;
+    }
+
+    return 0;
+}
+
+static const struct rtc_class_ops tps6586x_rtc_ops = {
+    .read_time    = tps6586x_rtc_read_time,
+    .set_time    = tps6586x_rtc_set_time,
+};
+
+static int __devinit tps6586x_rtc_probe(struct platform_device *pdev)
+{
+    struct device *tps_dev = to_tps6586x_dev(&pdev->dev);
+    struct tps6586x_rtc *rtc;
+    int err;
+
+    rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+
+    if (!rtc)
+        return -ENOMEM;
+
+    rtc->epoch_start = mktime(TPS_EPOCH, 1, 1, 0, 0, 0);
+    rtc->rtc = rtc_device_register("tps6586x-rtc", &pdev->dev,
+                       &tps6586x_rtc_ops, THIS_MODULE);
+
+    if (IS_ERR(rtc->rtc)) {
+        err = PTR_ERR(rtc->rtc);
+        goto fail;
+    }
+
+    /* disable high-res mode, enable tick counting */
+    err = tps6586x_update(tps_dev, RTC_CTRL,
+                  (RTC_ENABLE | RTC_HIRES), RTC_ENABLE);
+    if (err < 0) {
+        dev_err(&pdev->dev, "unable to start counter\n");
+        goto fail;
+    }
+
+    dev_set_drvdata(&pdev->dev, rtc);
+    return 0;
+
+fail:
+    if (!IS_ERR_OR_NULL(rtc->rtc))
+        rtc_device_unregister(rtc->rtc);
+    kfree(rtc);
+    return err;
+}
+
+static int __devexit tps6586x_rtc_remove(struct platform_device *pdev)
+{
+    struct tps6586x_rtc *rtc = dev_get_drvdata(&pdev->dev);
+
+    rtc_device_unregister(rtc->rtc);
+    kfree(rtc);
+    return 0;
+}
+
+static struct platform_driver tps6586x_rtc_driver = {
+    .driver    = {
+        .name    = "tps6586x-rtc",
+        .owner    = THIS_MODULE,
+    },
+    .probe    = tps6586x_rtc_probe,
+    .remove    = __devexit_p(tps6586x_rtc_remove),
+};
+
+static int __init tps6586x_rtc_init(void)
+{
+    return platform_driver_register(&tps6586x_rtc_driver);
+}
+module_init(tps6586x_rtc_init);
+
+static void __exit tps6586x_rtc_exit(void)
+{
+    platform_driver_unregister(&tps6586x_rtc_driver);
+}
+module_exit(tps6586x_rtc_exit);
+
+MODULE_DESCRIPTION("TI TPS6586x RTC driver");