From: Akinobu Mita <akinobu.mita@gmail.com>
To: rtc-linux@googlegroups.com, devicetree@vger.kernel.org
Cc: Akinobu Mita <akinobu.mita@gmail.com>,
Sergey Yanovich <ynvich@gmail.com>,
Alessandro Zummo <a.zummo@towertech.it>,
Alexandre Belloni <alexandre.belloni@free-electrons.com>
Subject: [rtc-linux] [PATCH v2 2/2] rtc: ds1302: support control with using GPIO lines
Date: Mon, 27 Jun 2016 20:19:22 +0900 [thread overview]
Message-ID: <1467026362-29446-3-git-send-email-akinobu.mita@gmail.com> (raw)
In-Reply-To: <1467026362-29446-1-git-send-email-akinobu.mita@gmail.com>
This adds support control with GPIO lines connected to the DS1302
which can communicate with three wires.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Sergey Yanovich <ynvich@gmail.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
.../devicetree/bindings/rtc/maxim-ds1302.txt | 13 +
drivers/rtc/Kconfig | 17 +-
drivers/rtc/rtc-ds1302.c | 320 ++++++++++++++++++++-
3 files changed, 331 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt b/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
index ba470c5..d489753 100644
--- a/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
+++ b/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
@@ -27,6 +27,12 @@ Required SPI properties:
- spi-cs-high: DS-1302 has active high chip select line. This is
required unless inverted in hardware.
+Required properties when using GPIO lines:
+
+- gpio-ce: GPIO connected to CE pin
+- gpio-io: GPIO connected to I/O pin
+- gpio-reset: GPIO connected to SCLK pin
+
Example:
spi@901c {
@@ -44,3 +50,10 @@ spi@901c {
spi-cs-high;
};
};
+
+ rtc: ds1302 {
+ compatible = "maxim,ds1302";
+ gpio-ce = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+ gpio-io = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+ gpio-sclk = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 18639e0..618f644 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -616,15 +616,6 @@ config RTC_DRV_M41T94
This driver can also be built as a module. If so, the module
will be called rtc-m41t94.
-config RTC_DRV_DS1302
- tristate "Dallas/Maxim DS1302"
- depends on SPI
- help
- If you say yes here you get support for the Dallas DS1302 RTC chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-ds1302.
-
config RTC_DRV_DS1305
tristate "Dallas/Maxim DS1305/DS1306"
help
@@ -844,6 +835,14 @@ config RTC_DRV_DS1286
help
If you say yes here you get support for the Dallas DS1286 RTC chips.
+config RTC_DRV_DS1302
+ tristate "Dallas/Maxim DS1302"
+ help
+ If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1302.
+
config RTC_DRV_DS1511
tristate "Dallas DS1511"
depends on HAS_IOMEM
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 635288d..5a21785 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -19,6 +19,10 @@
#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#define DRV_NAME "rtc-ds1302"
@@ -197,6 +201,16 @@ static int ds1302_probe(struct ds1302 *ds1302)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id ds1302_dt_ids[] = {
+ { .compatible = "maxim,ds1302", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
+#endif
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
static int ds1302_spi_read(struct ds1302 *ds1302, u8 addr, u8 *buf, int size)
{
struct spi_device *spi = to_spi_device(ds1302->dev);
@@ -259,21 +273,307 @@ static int ds1302_spi_probe(struct spi_device *spi)
return ds1302_probe(ds1302);
}
-#ifdef CONFIG_OF
-static const struct of_device_id ds1302_dt_ids[] = {
- { .compatible = "maxim,ds1302", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
-#endif
-
-static struct spi_driver ds1302_driver = {
+static struct spi_driver ds1302_spi_driver = {
.driver.name = "rtc-ds1302",
.driver.of_match_table = of_match_ptr(ds1302_dt_ids),
.probe = ds1302_spi_probe,
};
-module_spi_driver(ds1302_driver);
+static int ds1302_spi_register_driver(void)
+{
+ return spi_register_driver(&ds1302_spi_driver);
+}
+
+static void ds1302_spi_unregister_driver(void)
+{
+ spi_unregister_driver(&ds1302_spi_driver);
+}
+
+#else
+
+static int ds1302_spi_register_driver(void)
+{
+ return 0;
+}
+
+static void ds1302_spi_unregister_driver(void)
+{
+}
+
+#endif
+
+/*
+ * ds1302 driver using three GPIO lines
+ *
+ * The information to implement this is gleaned from
+ * http://playground.arduino.cc/Main/DS1302
+ */
+struct ds1302_gpio {
+ struct gpio_desc *gpiod_ce;
+ struct gpio_desc *gpiod_io;
+ struct gpio_desc *gpiod_sclk;
+
+ struct ds1302 ds1302;
+};
+
+static struct ds1302_gpio *to_ds1302_gpio(struct ds1302 *ds1302)
+{
+ return container_of(ds1302, struct ds1302_gpio, ds1302);
+}
+
+static int ds1302_gpio_reset(struct ds1302 *ds1302)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+ int ret;
+
+ ret = gpiod_direction_output(gpio->gpiod_ce, 0);
+ if (ret)
+ return ret;
+
+ ret = gpiod_direction_output(gpio->gpiod_io, 0);
+ if (ret)
+ return ret;
+
+ return gpiod_direction_output(gpio->gpiod_sclk, 0);
+}
+
+static void ds1302_gpio_chip_enable(struct ds1302 *ds1302, int enable)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ gpiod_set_value(gpio->gpiod_ce, enable);
+ if (enable) {
+ /*
+ * tCC (CE to CLK Setup): 4us
+ */
+ udelay(4);
+ } else {
+ /*
+ * tCWH (CE Inactive Time): 4us
+ */
+ udelay(4);
+ }
+}
+
+static int ds1302_gpio_sendbits(struct ds1302 *ds1302, u8 val)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+ int i;
+
+ for (i = 0; i < 8; i++, val >>= 1) {
+ gpiod_set_value(gpio->gpiod_sclk, 0);
+ /* tCL (CLK Low Time): 1000ns */
+ udelay(1);
+
+ gpiod_set_value(gpio->gpiod_io, val & 0x1);
+ /* tDC (Data to CLK Setup): 200ns */
+ udelay(1);
+
+ gpiod_set_value(gpio->gpiod_sclk, 1);
+ /*
+ * tCH (CLK High Time): 1000ns
+ * tCDH (CLK to Data Hold): 800ns
+ */
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static unsigned int ds1302_gpio_recvbits(struct ds1302 *ds1302)
+{
+ unsigned int val;
+ int i;
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ for (i = 0, val = 0; i < 8; i++) {
+ int bit;
+
+ gpiod_set_value(gpio->gpiod_sclk, 0);
+ /*
+ * tCL (CLK Low Time): 1000ns
+ * tCDD (CLK to Data Delay): 800ns
+ */
+ udelay(1);
+
+ bit = gpiod_get_value(gpio->gpiod_io);
+ if (bit < 0)
+ return bit;
+ val |= bit << i;
+
+ gpiod_set_value(gpio->gpiod_sclk, 1);
+ /* tCH (CLK High Time): 1000ns */
+ udelay(1);
+ }
+
+ return val;
+}
+
+static int ds1302_gpio_read(struct ds1302 *ds1302, u8 addr, u8 *buf, int size)
+{
+ int i;
+ int ret;
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ ret = ds1302_gpio_reset(ds1302);
+ if (ret)
+ return ret;
+
+ ds1302_gpio_chip_enable(ds1302, true);
+
+ ds1302_gpio_sendbits(ds1302, ((addr & 0x3f) << 1) | RTC_CMD_READ);
+
+ ret = gpiod_direction_input(gpio->gpiod_io);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < size; i++) {
+ ret = ds1302_gpio_recvbits(ds1302);
+ if (ret < 0)
+ break;
+ buf[i] = ret;
+ }
+
+ ds1302_gpio_chip_enable(ds1302, false);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int ds1302_gpio_write(struct ds1302 *ds1302, u8 addr, const u8 *buf,
+ int size)
+{
+ int err;
+ int i;
+
+ err = ds1302_gpio_reset(ds1302);
+ if (err)
+ return err;
+
+ ds1302_gpio_chip_enable(ds1302, true);
+
+ ds1302_gpio_sendbits(ds1302, ((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+
+ for (i = 0; i < size; i++) {
+ err = ds1302_gpio_sendbits(ds1302, buf[i]);
+ if (err)
+ break;
+ }
+
+ ds1302_gpio_chip_enable(ds1302, false);
+
+ return err;
+}
+
+static const struct ds1302_ops ds1302_gpio_ops = {
+ .read = ds1302_gpio_read,
+ .write = ds1302_gpio_write,
+};
+
+static struct gpio_desc *ds1302_gpiod_request(struct device *dev,
+ const char *name)
+{
+ int gpio;
+ int ret;
+
+ if (!dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ gpio = of_get_named_gpio(dev->of_node, name, 0);
+ if (!gpio_is_valid(gpio))
+ return ERR_PTR(gpio);
+
+ ret = devm_gpio_request_one(dev, gpio, 0, name);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return gpio_to_desc(gpio);
+}
+
+static struct ds1302 *ds1302_gpio_init(struct device *dev)
+{
+ struct ds1302_gpio *ds1302_gpio;
+ struct gpio_desc *gpiod;
+
+ ds1302_gpio = devm_kzalloc(dev, sizeof(*ds1302_gpio), GFP_KERNEL);
+ if (!ds1302_gpio)
+ return ERR_PTR(-ENOMEM);
+
+ ds1302_gpio->ds1302.ops = &ds1302_gpio_ops;
+ ds1302_gpio->ds1302.dev = dev;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-ce");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_ce = gpiod;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-io");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_io = gpiod;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-sclk");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_sclk = gpiod;
+
+ return &ds1302_gpio->ds1302;
+}
+
+static int ds1302_gpio_probe(struct platform_device *pdev)
+{
+ struct ds1302 *ds1302;
+
+ ds1302 = ds1302_gpio_init(&pdev->dev);
+ if (IS_ERR(ds1302))
+ return PTR_ERR(ds1302);
+
+ return ds1302_probe(ds1302);
+}
+
+static struct platform_driver ds1302_gpio_driver = {
+ .probe = ds1302_gpio_probe,
+ .driver = {
+ .name = "rtc-ds1302",
+ .of_match_table = of_match_ptr(ds1302_dt_ids),
+ },
+};
+
+static int ds1302_gpio_register_driver(void)
+{
+ return platform_driver_register(&ds1302_gpio_driver);
+}
+
+static void ds1302_gpio_unregister_driver(void)
+{
+ return platform_driver_unregister(&ds1302_gpio_driver);
+}
+
+static int __init ds1302_init(void)
+{
+ int ret;
+
+ ret = ds1302_spi_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds1302 spi driver: %d\n", ret);
+ return ret;
+ }
+
+ ret = ds1302_gpio_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds1302 gpio driver: %d\n", ret);
+ ds1302_spi_unregister_driver();
+ }
+
+ return ret;
+}
+module_init(ds1302_init)
+
+static void __exit ds1302_exit(void)
+{
+ ds1302_spi_unregister_driver();
+ ds1302_gpio_unregister_driver();
+}
+module_exit(ds1302_exit)
MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
MODULE_AUTHOR("Paul Mundt, David McCullough");
--
2.7.4
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
WARNING: multiple messages have this Message-ID (diff)
From: Akinobu Mita <akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: rtc-linux-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Akinobu Mita
<akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Sergey Yanovich <ynvich-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Alessandro Zummo
<a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>,
Alexandre Belloni
<alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Subject: [PATCH v2 2/2] rtc: ds1302: support control with using GPIO lines
Date: Mon, 27 Jun 2016 20:19:22 +0900 [thread overview]
Message-ID: <1467026362-29446-3-git-send-email-akinobu.mita@gmail.com> (raw)
In-Reply-To: <1467026362-29446-1-git-send-email-akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This adds support control with GPIO lines connected to the DS1302
which can communicate with three wires.
Signed-off-by: Akinobu Mita <akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Sergey Yanovich <ynvich-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Alessandro Zummo <a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>
Cc: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
.../devicetree/bindings/rtc/maxim-ds1302.txt | 13 +
drivers/rtc/Kconfig | 17 +-
drivers/rtc/rtc-ds1302.c | 320 ++++++++++++++++++++-
3 files changed, 331 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt b/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
index ba470c5..d489753 100644
--- a/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
+++ b/Documentation/devicetree/bindings/rtc/maxim-ds1302.txt
@@ -27,6 +27,12 @@ Required SPI properties:
- spi-cs-high: DS-1302 has active high chip select line. This is
required unless inverted in hardware.
+Required properties when using GPIO lines:
+
+- gpio-ce: GPIO connected to CE pin
+- gpio-io: GPIO connected to I/O pin
+- gpio-reset: GPIO connected to SCLK pin
+
Example:
spi@901c {
@@ -44,3 +50,10 @@ spi@901c {
spi-cs-high;
};
};
+
+ rtc: ds1302 {
+ compatible = "maxim,ds1302";
+ gpio-ce = <&gpio2 6 GPIO_ACTIVE_HIGH>;
+ gpio-io = <&gpio2 7 GPIO_ACTIVE_HIGH>;
+ gpio-sclk = <&gpio2 8 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 18639e0..618f644 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -616,15 +616,6 @@ config RTC_DRV_M41T94
This driver can also be built as a module. If so, the module
will be called rtc-m41t94.
-config RTC_DRV_DS1302
- tristate "Dallas/Maxim DS1302"
- depends on SPI
- help
- If you say yes here you get support for the Dallas DS1302 RTC chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-ds1302.
-
config RTC_DRV_DS1305
tristate "Dallas/Maxim DS1305/DS1306"
help
@@ -844,6 +835,14 @@ config RTC_DRV_DS1286
help
If you say yes here you get support for the Dallas DS1286 RTC chips.
+config RTC_DRV_DS1302
+ tristate "Dallas/Maxim DS1302"
+ help
+ If you say yes here you get support for the Dallas DS1302 RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1302.
+
config RTC_DRV_DS1511
tristate "Dallas DS1511"
depends on HAS_IOMEM
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 635288d..5a21785 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -19,6 +19,10 @@
#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#define DRV_NAME "rtc-ds1302"
@@ -197,6 +201,16 @@ static int ds1302_probe(struct ds1302 *ds1302)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id ds1302_dt_ids[] = {
+ { .compatible = "maxim,ds1302", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
+#endif
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
static int ds1302_spi_read(struct ds1302 *ds1302, u8 addr, u8 *buf, int size)
{
struct spi_device *spi = to_spi_device(ds1302->dev);
@@ -259,21 +273,307 @@ static int ds1302_spi_probe(struct spi_device *spi)
return ds1302_probe(ds1302);
}
-#ifdef CONFIG_OF
-static const struct of_device_id ds1302_dt_ids[] = {
- { .compatible = "maxim,ds1302", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
-#endif
-
-static struct spi_driver ds1302_driver = {
+static struct spi_driver ds1302_spi_driver = {
.driver.name = "rtc-ds1302",
.driver.of_match_table = of_match_ptr(ds1302_dt_ids),
.probe = ds1302_spi_probe,
};
-module_spi_driver(ds1302_driver);
+static int ds1302_spi_register_driver(void)
+{
+ return spi_register_driver(&ds1302_spi_driver);
+}
+
+static void ds1302_spi_unregister_driver(void)
+{
+ spi_unregister_driver(&ds1302_spi_driver);
+}
+
+#else
+
+static int ds1302_spi_register_driver(void)
+{
+ return 0;
+}
+
+static void ds1302_spi_unregister_driver(void)
+{
+}
+
+#endif
+
+/*
+ * ds1302 driver using three GPIO lines
+ *
+ * The information to implement this is gleaned from
+ * http://playground.arduino.cc/Main/DS1302
+ */
+struct ds1302_gpio {
+ struct gpio_desc *gpiod_ce;
+ struct gpio_desc *gpiod_io;
+ struct gpio_desc *gpiod_sclk;
+
+ struct ds1302 ds1302;
+};
+
+static struct ds1302_gpio *to_ds1302_gpio(struct ds1302 *ds1302)
+{
+ return container_of(ds1302, struct ds1302_gpio, ds1302);
+}
+
+static int ds1302_gpio_reset(struct ds1302 *ds1302)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+ int ret;
+
+ ret = gpiod_direction_output(gpio->gpiod_ce, 0);
+ if (ret)
+ return ret;
+
+ ret = gpiod_direction_output(gpio->gpiod_io, 0);
+ if (ret)
+ return ret;
+
+ return gpiod_direction_output(gpio->gpiod_sclk, 0);
+}
+
+static void ds1302_gpio_chip_enable(struct ds1302 *ds1302, int enable)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ gpiod_set_value(gpio->gpiod_ce, enable);
+ if (enable) {
+ /*
+ * tCC (CE to CLK Setup): 4us
+ */
+ udelay(4);
+ } else {
+ /*
+ * tCWH (CE Inactive Time): 4us
+ */
+ udelay(4);
+ }
+}
+
+static int ds1302_gpio_sendbits(struct ds1302 *ds1302, u8 val)
+{
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+ int i;
+
+ for (i = 0; i < 8; i++, val >>= 1) {
+ gpiod_set_value(gpio->gpiod_sclk, 0);
+ /* tCL (CLK Low Time): 1000ns */
+ udelay(1);
+
+ gpiod_set_value(gpio->gpiod_io, val & 0x1);
+ /* tDC (Data to CLK Setup): 200ns */
+ udelay(1);
+
+ gpiod_set_value(gpio->gpiod_sclk, 1);
+ /*
+ * tCH (CLK High Time): 1000ns
+ * tCDH (CLK to Data Hold): 800ns
+ */
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static unsigned int ds1302_gpio_recvbits(struct ds1302 *ds1302)
+{
+ unsigned int val;
+ int i;
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ for (i = 0, val = 0; i < 8; i++) {
+ int bit;
+
+ gpiod_set_value(gpio->gpiod_sclk, 0);
+ /*
+ * tCL (CLK Low Time): 1000ns
+ * tCDD (CLK to Data Delay): 800ns
+ */
+ udelay(1);
+
+ bit = gpiod_get_value(gpio->gpiod_io);
+ if (bit < 0)
+ return bit;
+ val |= bit << i;
+
+ gpiod_set_value(gpio->gpiod_sclk, 1);
+ /* tCH (CLK High Time): 1000ns */
+ udelay(1);
+ }
+
+ return val;
+}
+
+static int ds1302_gpio_read(struct ds1302 *ds1302, u8 addr, u8 *buf, int size)
+{
+ int i;
+ int ret;
+ struct ds1302_gpio *gpio = to_ds1302_gpio(ds1302);
+
+ ret = ds1302_gpio_reset(ds1302);
+ if (ret)
+ return ret;
+
+ ds1302_gpio_chip_enable(ds1302, true);
+
+ ds1302_gpio_sendbits(ds1302, ((addr & 0x3f) << 1) | RTC_CMD_READ);
+
+ ret = gpiod_direction_input(gpio->gpiod_io);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < size; i++) {
+ ret = ds1302_gpio_recvbits(ds1302);
+ if (ret < 0)
+ break;
+ buf[i] = ret;
+ }
+
+ ds1302_gpio_chip_enable(ds1302, false);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int ds1302_gpio_write(struct ds1302 *ds1302, u8 addr, const u8 *buf,
+ int size)
+{
+ int err;
+ int i;
+
+ err = ds1302_gpio_reset(ds1302);
+ if (err)
+ return err;
+
+ ds1302_gpio_chip_enable(ds1302, true);
+
+ ds1302_gpio_sendbits(ds1302, ((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+
+ for (i = 0; i < size; i++) {
+ err = ds1302_gpio_sendbits(ds1302, buf[i]);
+ if (err)
+ break;
+ }
+
+ ds1302_gpio_chip_enable(ds1302, false);
+
+ return err;
+}
+
+static const struct ds1302_ops ds1302_gpio_ops = {
+ .read = ds1302_gpio_read,
+ .write = ds1302_gpio_write,
+};
+
+static struct gpio_desc *ds1302_gpiod_request(struct device *dev,
+ const char *name)
+{
+ int gpio;
+ int ret;
+
+ if (!dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ gpio = of_get_named_gpio(dev->of_node, name, 0);
+ if (!gpio_is_valid(gpio))
+ return ERR_PTR(gpio);
+
+ ret = devm_gpio_request_one(dev, gpio, 0, name);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return gpio_to_desc(gpio);
+}
+
+static struct ds1302 *ds1302_gpio_init(struct device *dev)
+{
+ struct ds1302_gpio *ds1302_gpio;
+ struct gpio_desc *gpiod;
+
+ ds1302_gpio = devm_kzalloc(dev, sizeof(*ds1302_gpio), GFP_KERNEL);
+ if (!ds1302_gpio)
+ return ERR_PTR(-ENOMEM);
+
+ ds1302_gpio->ds1302.ops = &ds1302_gpio_ops;
+ ds1302_gpio->ds1302.dev = dev;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-ce");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_ce = gpiod;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-io");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_io = gpiod;
+
+ gpiod = ds1302_gpiod_request(dev, "gpio-sclk");
+ if (IS_ERR(gpiod))
+ return ERR_CAST(gpiod);
+ ds1302_gpio->gpiod_sclk = gpiod;
+
+ return &ds1302_gpio->ds1302;
+}
+
+static int ds1302_gpio_probe(struct platform_device *pdev)
+{
+ struct ds1302 *ds1302;
+
+ ds1302 = ds1302_gpio_init(&pdev->dev);
+ if (IS_ERR(ds1302))
+ return PTR_ERR(ds1302);
+
+ return ds1302_probe(ds1302);
+}
+
+static struct platform_driver ds1302_gpio_driver = {
+ .probe = ds1302_gpio_probe,
+ .driver = {
+ .name = "rtc-ds1302",
+ .of_match_table = of_match_ptr(ds1302_dt_ids),
+ },
+};
+
+static int ds1302_gpio_register_driver(void)
+{
+ return platform_driver_register(&ds1302_gpio_driver);
+}
+
+static void ds1302_gpio_unregister_driver(void)
+{
+ return platform_driver_unregister(&ds1302_gpio_driver);
+}
+
+static int __init ds1302_init(void)
+{
+ int ret;
+
+ ret = ds1302_spi_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds1302 spi driver: %d\n", ret);
+ return ret;
+ }
+
+ ret = ds1302_gpio_register_driver();
+ if (ret) {
+ pr_err("Failed to register ds1302 gpio driver: %d\n", ret);
+ ds1302_spi_unregister_driver();
+ }
+
+ return ret;
+}
+module_init(ds1302_init)
+
+static void __exit ds1302_exit(void)
+{
+ ds1302_spi_unregister_driver();
+ ds1302_gpio_unregister_driver();
+}
+module_exit(ds1302_exit)
MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
MODULE_AUTHOR("Paul Mundt, David McCullough");
--
2.7.4
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
next prev parent reply other threads:[~2016-06-27 11:19 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-27 11:19 [rtc-linux] [PATCH v2 0/2] support control with using GPIO lines Akinobu Mita
2016-06-27 11:19 ` Akinobu Mita
2016-06-27 11:19 ` [rtc-linux] [PATCH v2 1/2] rtc: ds1302: add register access abstraction layer Akinobu Mita
2016-06-27 11:19 ` Akinobu Mita
2016-06-27 11:50 ` [rtc-linux] " Sergei Ianovich
2016-06-27 11:50 ` Sergei Ianovich
2016-06-27 12:44 ` [rtc-linux] " Alexandre Belloni
2016-06-27 12:44 ` Alexandre Belloni
2016-06-27 12:45 ` [rtc-linux] " Alexandre Belloni
2016-06-27 12:45 ` Alexandre Belloni
2016-06-27 15:15 ` [rtc-linux] " Sergei Ianovich
2016-06-27 15:15 ` Sergei Ianovich
2016-07-19 15:13 ` [rtc-linux] " Alexandre Belloni
2016-07-19 15:13 ` Alexandre Belloni
2016-07-27 18:47 ` [rtc-linux] " Mark Brown
2016-07-27 18:47 ` Mark Brown
2016-06-27 11:19 ` Akinobu Mita [this message]
2016-06-27 11:19 ` [PATCH v2 2/2] rtc: ds1302: support control with using GPIO lines Akinobu Mita
2016-06-28 20:57 ` [rtc-linux] " Rob Herring
2016-06-28 20:57 ` Rob Herring
2016-07-08 14:28 ` [rtc-linux] " Alexandre Belloni
2016-07-08 14:28 ` Alexandre Belloni
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1467026362-29446-3-git-send-email-akinobu.mita@gmail.com \
--to=akinobu.mita@gmail.com \
--cc=a.zummo@towertech.it \
--cc=alexandre.belloni@free-electrons.com \
--cc=devicetree@vger.kernel.org \
--cc=rtc-linux@googlegroups.com \
--cc=ynvich@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.