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 4/4] rtc: ds1302: support control with using GPIO lines
Date: Sun, 10 Apr 2016 23:59:26 +0900 [thread overview]
Message-ID: <1460300366-25248-5-git-send-email-akinobu.mita@gmail.com> (raw)
In-Reply-To: <1460300366-25248-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 | 340 ++++++++++++++++++++-
3 files changed, 351 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 a86a562..734dc1b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -636,15 +636,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
@@ -1639,6 +1630,14 @@ config RTC_DRV_XGENE
This driver can also be built as a module, if so, the module
will be called "rtc-xgene".
+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.
+
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 1647848..778f39a 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"
#define DRV_VERSION "1.0.0"
@@ -195,6 +199,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_readbyte(struct ds1302 *ds1302, u8 addr)
{
struct spi_device *spi = to_spi_device(ds1302->dev);
@@ -285,21 +299,327 @@ 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_readburst(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_readbyte(struct ds1302 *ds1302, u8 addr)
+{
+ u8 val;
+ int err;
+
+ err = ds1302_gpio_readburst(ds1302, addr, &val, 1);
+ if (err)
+ return err;
+
+ return val;
+}
+
+static int ds1302_gpio_writeburst(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 int ds1302_gpio_writebyte(struct ds1302 *ds1302, u8 addr, u8 val)
+{
+ return ds1302_gpio_writeburst(ds1302, addr, &val, 1);
+}
+
+static const struct ds1302_ops ds1302_gpio_ops = {
+ .readbyte = ds1302_gpio_readbyte,
+ .writebyte = ds1302_gpio_writebyte,
+ .readburst = ds1302_gpio_readburst,
+ .writeburst = ds1302_gpio_writeburst,
+};
+
+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_VERSION(DRV_VERSION);
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2016-04-10 14:59 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-10 14:59 [PATCH 0/4] support control with using GPIO lines Akinobu Mita
[not found] ` <1460300366-25248-1-git-send-email-akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-04-10 14:59 ` [PATCH 1/4] rtc: ds1302: fix error check in set_time Akinobu Mita
[not found] ` <1460300366-25248-2-git-send-email-akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-04-10 15:17 ` Alexandre Belloni
2016-04-10 14:59 ` [PATCH 2/4] rtc: ds1302: fix write value for day of week register Akinobu Mita
[not found] ` <1460300366-25248-3-git-send-email-akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-04-10 15:17 ` Alexandre Belloni
2016-04-10 14:59 ` [PATCH 3/4] rtc: ds1302: add register access abstraction layer Akinobu Mita
2016-04-10 14:59 ` Akinobu Mita [this message]
2016-04-10 15:12 ` [PATCH 0/4] support control with using GPIO lines Alexandre Belloni
[not found] ` <20160410151237.GD5377-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
2016-04-10 15:23 ` Sergei Ianovich
[not found] ` <1460301781.17404.171.camel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-04-10 15:38 ` Alexandre Belloni
[not found] ` <20160410153855.GG5377-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
2016-04-12 1:25 ` Mark Brown
[not found] ` <20160412012518.GQ3351-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-04-26 19:53 ` Akinobu Mita
[not found] ` <CAC5umyguFq7vBenkJYM8AWCNJ3oGBKzKAMHHMsO=+OFHtE4b0A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-04-27 13:50 ` Mark Brown
[not found] ` <20160427135012.GP3217-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2016-04-27 14:03 ` Sergei Ianovich
[not found] ` <1461765799.2957.4.camel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-04-29 5:40 ` Akinobu Mita
[not found] ` <CAC5umyhLZ7Nvakf84qS73HG=H39mjYf5Lv=BPFnqZt-rTrZvCA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-06-26 0:55 ` Alexandre Belloni
[not found] ` <20160626005534.GY5809-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
2016-06-27 10:23 ` Akinobu Mita
2016-04-11 19:46 ` Rob Herring
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=1460300366-25248-5-git-send-email-akinobu.mita@gmail.com \
--to=akinobu.mita-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
--cc=a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org \
--cc=alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=rtc-linux-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org \
--cc=ynvich-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).