* [PATCH] rtc: Add MOXA ART RTC driver @ 2013-07-10 14:00 Jonas Jensen 2013-07-10 15:47 ` Mark Brown 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen 0 siblings, 2 replies; 11+ messages in thread From: Jonas Jensen @ 2013-07-10 14:00 UTC (permalink / raw) To: linux-arm-kernel Add RTC driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> --- Notes: Applies to next-20130703 drivers/rtc/Kconfig | 9 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-moxart.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 drivers/rtc/rtc-moxart.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b983813..7035955 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1233,6 +1233,15 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f..c0381fd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 0000000..cfdbedc --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,335 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * Based on code from + * Moxa Technology Co., Ltd. <www.moxa.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/gpio.h> + +#define GPIO_EM1240_HIGH 1 +#define GPIO_EM1240_LOW 0 +#define GPIO_EM1240_OUTPUT 1 +#define GPIO_EM1240_INPUT 0 + +#define GPIO_RTC_SCLK (5) +#define GPIO_RTC_DATA (6) +#define GPIO_RTC_RESET (7) + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 + +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 /* 8 usecond */ +#define GPIO_RTC_IS_OPEN 0x01 /* /dev/rtc in use */ +#define GPIO_PIO(x) (1 << x) + +struct rtc_plat_data { + struct rtc_device *rtc; +}; + +static spinlock_t rtc_lock; +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +void moxart_rtc_write_byte(u8 data) +{ + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_LOW); + gpio_set_value(GPIO_RTC_DATA, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_HIGH); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +u8 moxart_rtc_read_byte(void) +{ + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_LOW); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_HIGH); + if (gpio_get_value(GPIO_RTC_DATA)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(u8 cmd) +{ + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(GPIO_RTC_DATA, 0); + gpio_set_value(GPIO_RTC_RESET, GPIO_EM1240_HIGH); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(cmd); + gpio_direction_input(GPIO_RTC_DATA); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(); + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_LOW); + gpio_set_value(GPIO_RTC_RESET, GPIO_EM1240_LOW); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(u8 cmd, u8 data) +{ + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(GPIO_RTC_DATA, 0); + gpio_set_value(GPIO_RTC_RESET, GPIO_EM1240_HIGH); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(cmd); + moxart_rtc_write_byte(data); + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_LOW); + gpio_set_value(GPIO_RTC_RESET, GPIO_EM1240_LOW); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + spin_lock_irq(&rtc_lock); + + moxart_rtc_write_register(GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char v; + + spin_lock_irq(&rtc_lock); + + v = moxart_rtc_read_register(GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static int moxart_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, + .ioctl = moxart_rtc_ioctl, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct rtc_plat_data *pdata = NULL; + int ret = 0; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + spin_lock_init(&rtc_lock); + + gpio_request(GPIO_RTC_DATA, "rtc_data"); + gpio_request(GPIO_RTC_SCLK, "rtc_sclk"); + gpio_request(GPIO_RTC_RESET, "rtc_reset"); + + gpio_direction_output(GPIO_RTC_RESET, 0); + gpio_direction_output(GPIO_RTC_SCLK, 0); + + rtc = rtc_device_register(pdev->name, &pdev->dev, + &moxart_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + + pdata->rtc = rtc; + platform_set_drvdata(pdev, pdata); + + dev_dbg(&pdev->dev, "%s\n", __func__); + + if (ret) + goto out; + + return 0; + + out: + if (pdata->rtc) + rtc_device_unregister(pdata->rtc); + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int moxart_rtc_remove(struct platform_device *pdev) +{ + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + gpio_free(GPIO_RTC_DATA); + gpio_free(GPIO_RTC_SCLK); + gpio_free(GPIO_RTC_RESET); + + rtc_device_unregister(pdata->rtc); + devm_kfree(&pdev->dev, pdata); + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .remove = moxart_rtc_remove, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); -- 1.8.2.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] rtc: Add MOXA ART RTC driver 2013-07-10 14:00 [PATCH] rtc: Add MOXA ART RTC driver Jonas Jensen @ 2013-07-10 15:47 ` Mark Brown 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen 1 sibling, 0 replies; 11+ messages in thread From: Mark Brown @ 2013-07-10 15:47 UTC (permalink / raw) To: linux-arm-kernel On Wed, Jul 10, 2013 at 04:00:48PM +0200, Jonas Jensen wrote: > +++ b/drivers/rtc/Makefile > @@ -77,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o > obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o > obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o > obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o > +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o > obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o It'd be good to keep this sorted. > +struct rtc_plat_data { This is a bit confusing - normally platform data is data passed in by the platform as part of device registration, not runtime data. > + struct rtc_device *rtc; > +}; > + > +static spinlock_t rtc_lock; Why is this global not part of the runtime data? Not that anyone is likely to have two RTCs in the one system but still... > +u8 moxart_rtc_read_byte(void) > +{ > + int i; > + u8 data = 0; > + > + for (i = 0; i < 8; i++) { > + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_LOW); > + udelay(GPIO_RTC_DELAY_TIME); > + gpio_set_value(GPIO_RTC_SCLK, GPIO_EM1240_HIGH); > + if (gpio_get_value(GPIO_RTC_DATA)) > + data |= (1 << i); > + udelay(GPIO_RTC_DELAY_TIME); This looks wrong, although I expect it's probably fine - you're reading the value with no delay after setting the GPIO high. I assume the hardware actually strobes the data out on the the high to low transition but in that case I'd expect the get to be before the raise. Either that or some delay after the raise just to make sure. It's also very odd seeing the constants for _LOW and _HIGH, these should just be booleans. > +static int moxart_rtc_ioctl(struct device *dev, unsigned int cmd, > + unsigned long arg) > +{ > + switch (cmd) { > + default: > + return -ENOIOCTLCMD; > + } > + > + return 0; > +} Why not just remove this function? > + out: > + if (pdata->rtc) > + rtc_device_unregister(pdata->rtc); > + devm_kfree(&pdev->dev, pdata); devm_kfree() isn't needed, the main point of devm_ is to avoid having to explicitly free things. > + gpio_free(GPIO_RTC_DATA); > + gpio_free(GPIO_RTC_SCLK); > + gpio_free(GPIO_RTC_RESET); Use devm_gpio_request(). -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130710/be4d14ac/attachment.sig> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2] rtc: Add MOXA ART RTC driver 2013-07-10 14:00 [PATCH] rtc: Add MOXA ART RTC driver Jonas Jensen 2013-07-10 15:47 ` Mark Brown @ 2013-07-11 13:51 ` Jonas Jensen 2013-07-11 16:51 ` Mark Brown ` (2 more replies) 1 sibling, 3 replies; 11+ messages in thread From: Jonas Jensen @ 2013-07-11 13:51 UTC (permalink / raw) To: linux-arm-kernel Add RTC driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> --- Notes: Thanks for the review Mark, what you said should be fixed in v2. Applies to next-20130711 Changes since v1: 1. remove defines GPIO_EM1240_HIGH and GPIO_EM1240_LOW 2. rename struct "rtc_plat_data" "moxart_rtc" 3. move rtc_lock to struct moxart_rtc 4. add delay after setting GPIO high 5. remove moxart_rtc_ioctl 6. use devm_gpio_request instead of gpio_request 7. remove explicit devm_kfree 8. change Makefile list order drivers/rtc/Kconfig | 9 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-moxart.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 326 insertions(+) create mode 100644 drivers/rtc/rtc-moxart.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9e3498b..9654aa3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1249,6 +1249,15 @@ config RTC_DRV_SIRFSOC Say "yes" here to support the real time clock on SiRF SOC chips. This driver can also be built as a module called rtc-sirfsoc. +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3b4488..2dff3d2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 0000000..dd8615e --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,316 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * Based on code from + * Moxa Technology Co., Ltd. <www.moxa.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/gpio.h> + +#define GPIO_EM1240_OUTPUT 1 +#define GPIO_EM1240_INPUT 0 + +#define GPIO_RTC_SCLK (5) +#define GPIO_RTC_DATA (6) +#define GPIO_RTC_RESET (7) + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 + +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 /* 8 usecond */ +#define GPIO_RTC_IS_OPEN 0x01 /* /dev/rtc in use */ +#define GPIO_PIO(x) (1 << x) + +struct moxart_rtc { + struct rtc_device *rtc; + spinlock_t rtc_lock; +}; + +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +void moxart_rtc_write_byte(u8 data) +{ + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(GPIO_RTC_SCLK, 0); + gpio_set_value(GPIO_RTC_DATA, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(GPIO_RTC_SCLK, 1); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +u8 moxart_rtc_read_byte(void) +{ + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(GPIO_RTC_SCLK, 0); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(GPIO_RTC_SCLK, 1); + udelay(GPIO_RTC_DELAY_TIME); + if (gpio_get_value(GPIO_RTC_DATA)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(u8 cmd) +{ + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(GPIO_RTC_DATA, 0); + gpio_set_value(GPIO_RTC_RESET, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(cmd); + gpio_direction_input(GPIO_RTC_DATA); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(); + gpio_set_value(GPIO_RTC_SCLK, 0); + gpio_set_value(GPIO_RTC_RESET, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(u8 cmd, u8 data) +{ + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(GPIO_RTC_DATA, 0); + gpio_set_value(GPIO_RTC_RESET, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(cmd); + moxart_rtc_write_byte(data); + gpio_set_value(GPIO_RTC_SCLK, 0); + gpio_set_value(GPIO_RTC_RESET, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&moxart_rtc->rtc_lock); + + moxart_rtc_write_register(GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned char v; + + spin_lock_irq(&moxart_rtc->rtc_lock); + + v = moxart_rtc_read_register(GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc; + int ret = 0; + + moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); + if (!moxart_rtc) { + dev_err(&pdev->dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + + devm_gpio_request(&pdev->dev, GPIO_RTC_DATA, "rtc_data"); + devm_gpio_request(&pdev->dev, GPIO_RTC_SCLK, "rtc_sclk"); + devm_gpio_request(&pdev->dev, GPIO_RTC_RESET, "rtc_reset"); + + gpio_direction_output(GPIO_RTC_RESET, 0); + gpio_direction_output(GPIO_RTC_SCLK, 0); + + moxart_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &moxart_rtc_ops, THIS_MODULE); + if (IS_ERR(moxart_rtc->rtc)) { + ret = PTR_ERR(moxart_rtc->rtc); + goto out; + } + + dev_dbg(&pdev->dev, "%s\n", __func__); + + if (ret) + goto out; + + return 0; + + out: + if (moxart_rtc->rtc) + rtc_device_unregister(moxart_rtc->rtc); + return ret; +} + +static int moxart_rtc_remove(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(moxart_rtc->rtc); + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .remove = moxart_rtc_remove, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); -- 1.8.2.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2] rtc: Add MOXA ART RTC driver 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen @ 2013-07-11 16:51 ` Mark Brown 2013-07-14 19:58 ` Arnd Bergmann 2013-07-16 12:41 ` [PATCH v3] " Jonas Jensen 2 siblings, 0 replies; 11+ messages in thread From: Mark Brown @ 2013-07-11 16:51 UTC (permalink / raw) To: linux-arm-kernel On Thu, Jul 11, 2013 at 03:51:51PM +0200, Jonas Jensen wrote: > Add RTC driver for MOXA ART SoCs. Looks good now. A couple more minor nits. > +void moxart_rtc_write_byte(u8 data) > +{ > +u8 moxart_rtc_read_byte(void) > +{ These should be static. > + gpio_direction_output(GPIO_RTC_DATA, 0); > + gpio_set_value(GPIO_RTC_RESET, 1); I guess I'd expect the GPIOs to be configured by platform data in case of board changes (it's a bit odd that a SoC RTC is being done with bitbanging, I guess it's on an external chip?). > + devm_gpio_request(&pdev->dev, GPIO_RTC_DATA, "rtc_data"); > + devm_gpio_request(&pdev->dev, GPIO_RTC_SCLK, "rtc_sclk"); > + devm_gpio_request(&pdev->dev, GPIO_RTC_RESET, "rtc_reset"); Should check the errors from these. > + gpio_direction_output(GPIO_RTC_RESET, 0); > + gpio_direction_output(GPIO_RTC_SCLK, 0); devm_gpio_request_one()? Though it doesn't make much difference and you do have a nice block of devm_gpio_request() above not all of which have a direction assigned immediately. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130711/7019f737/attachment.sig> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2] rtc: Add MOXA ART RTC driver 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen 2013-07-11 16:51 ` Mark Brown @ 2013-07-14 19:58 ` Arnd Bergmann 2013-07-16 12:41 ` [PATCH v3] " Jonas Jensen 2 siblings, 0 replies; 11+ messages in thread From: Arnd Bergmann @ 2013-07-14 19:58 UTC (permalink / raw) To: linux-arm-kernel On Thursday 11 July 2013, Jonas Jensen wrote: > Add RTC driver for MOXA ART SoCs. > + > +#define GPIO_EM1240_OUTPUT 1 > +#define GPIO_EM1240_INPUT 0 > + > +#define GPIO_RTC_SCLK (5) > +#define GPIO_RTC_DATA (6) > +#define GPIO_RTC_RESET (7) Since this is a DT-only platform, you should not really have hardcoded GPIO numbers. > + devm_gpio_request(&pdev->dev, GPIO_RTC_DATA, "rtc_data"); > + devm_gpio_request(&pdev->dev, GPIO_RTC_SCLK, "rtc_sclk"); > + devm_gpio_request(&pdev->dev, GPIO_RTC_RESET, "rtc_reset"); Instead, you should use of_get_named_gpio() here, and add a binding document that describes the names. Arnd ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3] rtc: Add MOXA ART RTC driver 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen 2013-07-11 16:51 ` Mark Brown 2013-07-14 19:58 ` Arnd Bergmann @ 2013-07-16 12:41 ` Jonas Jensen 2013-07-16 13:13 ` Mark Brown 2013-07-17 9:14 ` [PATCH v4] " Jonas Jensen 2 siblings, 2 replies; 11+ messages in thread From: Jonas Jensen @ 2013-07-16 12:41 UTC (permalink / raw) To: linux-arm-kernel Add RTC driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> --- Notes: Thanks for the replies. This should fix the remaining issues mentioned by Mark and Arnd. Changes since v2: 1. don't use hardcoded GPIO numbers, use of_get_named_gpio 2. make two functions static, moxart_rtc_write_byte and moxart_rtc_read_byte 3. use devm_gpio_request_one where appropriate 4. add gpio_is_valid check to all of_get_named_gpio 5. check devm_gpio_request return value 6. use devm_rtc_device_register instead of rtc_device_register 7. remove label "out" from moxart_rtc_probe 8. remove moxart_rtc_remove function Applies to next-20130716 drivers/rtc/Kconfig | 9 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-moxart.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 drivers/rtc/rtc-moxart.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9e3498b..9654aa3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1249,6 +1249,15 @@ config RTC_DRV_SIRFSOC Say "yes" here to support the real time clock on SiRF SOC chips. This driver can also be built as a module called rtc-sirfsoc. +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3b4488..2dff3d2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 0000000..c29dee0 --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,330 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * Based on code from + * Moxa Technology Co., Ltd. <www.moxa.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 + +struct moxart_rtc { + struct rtc_device *rtc; + spinlock_t rtc_lock; + int gpio_data, gpio_sclk, gpio_reset; +}; + +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +static void moxart_rtc_write_byte(struct device *dev, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +static u8 moxart_rtc_read_byte(struct device *dev) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + if (gpio_get_value(moxart_rtc->gpio_data)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + gpio_direction_input(moxart_rtc->gpio_data); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(dev); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + moxart_rtc_write_byte(dev, data); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&moxart_rtc->rtc_lock); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned char v; + + spin_lock_irq(&moxart_rtc->rtc_lock); + + v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc; + int ret = 0; + + moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); + if (!moxart_rtc) { + dev_err(&pdev->dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-data", 0); + if (!gpio_is_valid(moxart_rtc->gpio_data)) { + dev_err(&pdev->dev, "invalid gpio (data): %d\n", + moxart_rtc->gpio_data); + return moxart_rtc->gpio_data; + } + + moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-sclk", 0); + if (!gpio_is_valid(moxart_rtc->gpio_sclk)) { + dev_err(&pdev->dev, "invalid gpio (sclk): %d\n", + moxart_rtc->gpio_sclk); + return moxart_rtc->gpio_sclk; + } + + moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-reset", 0); + if (!gpio_is_valid(moxart_rtc->gpio_reset)) { + dev_err(&pdev->dev, "invalid gpio (reset): %d\n", + moxart_rtc->gpio_reset); + return moxart_rtc->gpio_reset; + } + + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + + ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_data gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, + GPIOF_DIR_OUT, "rtc_sclk"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, + GPIOF_DIR_OUT, "rtc_reset"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); + return ret; + } + + moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &moxart_rtc_ops, + THIS_MODULE); + if (IS_ERR(moxart_rtc->rtc)) { + dev_err(&pdev->dev, "devm_rtc_device_register failed\n"); + return PTR_ERR(moxart_rtc->rtc); + } + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); -- 1.8.2.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3] rtc: Add MOXA ART RTC driver 2013-07-16 12:41 ` [PATCH v3] " Jonas Jensen @ 2013-07-16 13:13 ` Mark Brown 2013-07-16 14:04 ` Jonas Jensen 2013-07-17 9:14 ` [PATCH v4] " Jonas Jensen 1 sibling, 1 reply; 11+ messages in thread From: Mark Brown @ 2013-07-16 13:13 UTC (permalink / raw) To: linux-arm-kernel On Tue, Jul 16, 2013 at 02:41:25PM +0200, Jonas Jensen wrote: > 1. don't use hardcoded GPIO numbers, use of_get_named_gpio Since you're now using OF you should also be including a binding document. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130716/e65a6be3/attachment-0001.sig> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3] rtc: Add MOXA ART RTC driver 2013-07-16 13:13 ` Mark Brown @ 2013-07-16 14:04 ` Jonas Jensen 2013-07-16 15:57 ` Mark Brown 0 siblings, 1 reply; 11+ messages in thread From: Jonas Jensen @ 2013-07-16 14:04 UTC (permalink / raw) To: linux-arm-kernel On 16 July 2013 15:13, Mark Brown <broonie@kernel.org> wrote: > Since you're now using OF you should also be including a binding > document. The binding document already exist in set of patches adding MOXA ART SoC support ( I intend to mail out v4 once I know how to proceed ): "[PATCH v3 2/4] ARM: mach-moxart: add MOXA ART device tree files" - http://lists.infradead.org/pipermail/linux-arm-kernel/2013-July/181757.html Can it remain as a part of that set? Or should it be moved here to a new v4 patch? Changes are available in my public git repository, see Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt: http://code.google.com/p/linux-next-20130703-moxart/source/detail?r=55b2a92724f36ecc852208bb1f8e1b7bd7c7904b Best regards, Jonas ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3] rtc: Add MOXA ART RTC driver 2013-07-16 14:04 ` Jonas Jensen @ 2013-07-16 15:57 ` Mark Brown 0 siblings, 0 replies; 11+ messages in thread From: Mark Brown @ 2013-07-16 15:57 UTC (permalink / raw) To: linux-arm-kernel On Tue, Jul 16, 2013 at 04:04:07PM +0200, Jonas Jensen wrote: > On 16 July 2013 15:13, Mark Brown <broonie@kernel.org> wrote: > > Since you're now using OF you should also be including a binding > > document. > The binding document already exist in set of patches adding MOXA ART > SoC support ( I intend to mail out v4 once I know how to proceed ): If that's the case then you need to point people at the binding document when posting the driver but... > Or should it be moved here to a new v4 patch? ...it's more normal to push the binding along with the driver. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130716/7e5b010a/attachment.sig> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v4] rtc: Add MOXA ART RTC driver 2013-07-16 12:41 ` [PATCH v3] " Jonas Jensen 2013-07-16 13:13 ` Mark Brown @ 2013-07-17 9:14 ` Jonas Jensen 2013-07-17 10:09 ` Mark Brown 1 sibling, 1 reply; 11+ messages in thread From: Jonas Jensen @ 2013-07-17 9:14 UTC (permalink / raw) To: linux-arm-kernel Add RTC driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> --- Notes: Changes since v3: 1. add devicetree bindings document Applies to next-20130716 .../devicetree/bindings/rtc/moxa,moxart-rtc.txt | 17 ++ drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-moxart.c | 330 +++++++++++++++++++++ 4 files changed, 357 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt create mode 100644 drivers/rtc/rtc-moxart.c diff --git a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt new file mode 100644 index 0000000..c9d3ac1 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt @@ -0,0 +1,17 @@ +MOXA ART real-time clock + +Required properties: + +- compatible : Should be "moxa,moxart-rtc" +- gpio-rtc-sclk : RTC sclk gpio, with zero flags +- gpio-rtc-data : RTC data gpio, with zero flags +- gpio-rtc-reset : RTC reset gpio, with zero flags + +Example: + + rtc: rtc { + compatible = "moxa,moxart-rtc"; + gpio-rtc-sclk = <&gpio 5 0>; + gpio-rtc-data = <&gpio 6 0>; + gpio-rtc-reset = <&gpio 7 0>; + }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9e3498b..9654aa3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1249,6 +1249,15 @@ config RTC_DRV_SIRFSOC Say "yes" here to support the real time clock on SiRF SOC chips. This driver can also be built as a module called rtc-sirfsoc. +config RTC_DRV_MOXART + tristate "MOXA ART RTC" + help + If you say yes here you get support for the MOXA ART + RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-moxart + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3b4488..2dff3d2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -130,3 +130,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o +obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c new file mode 100644 index 0000000..c29dee0 --- /dev/null +++ b/drivers/rtc/rtc-moxart.c @@ -0,0 +1,330 @@ +/* + * MOXA ART RTC driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * Based on code from + * Moxa Technology Co., Ltd. <www.moxa.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#define GPIO_RTC_RESERVED 0x0C +#define GPIO_RTC_DATA_SET 0x10 +#define GPIO_RTC_DATA_CLEAR 0x14 +#define GPIO_RTC_PIN_PULL_ENABLE 0x18 +#define GPIO_RTC_PIN_PULL_TYPE 0x1C +#define GPIO_RTC_INT_ENABLE 0x20 +#define GPIO_RTC_INT_RAW_STATE 0x24 +#define GPIO_RTC_INT_MASKED_STATE 0x28 +#define GPIO_RTC_INT_MASK 0x2C +#define GPIO_RTC_INT_CLEAR 0x30 +#define GPIO_RTC_INT_TRIGGER 0x34 +#define GPIO_RTC_INT_BOTH 0x38 +#define GPIO_RTC_INT_RISE_NEG 0x3C +#define GPIO_RTC_BOUNCE_ENABLE 0x40 +#define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 +#define GPIO_RTC_PROTECT_W 0x8E +#define GPIO_RTC_PROTECT_R 0x8F +#define GPIO_RTC_YEAR_W 0x8C +#define GPIO_RTC_YEAR_R 0x8D +#define GPIO_RTC_DAY_W 0x8A +#define GPIO_RTC_DAY_R 0x8B +#define GPIO_RTC_MONTH_W 0x88 +#define GPIO_RTC_MONTH_R 0x89 +#define GPIO_RTC_DATE_W 0x86 +#define GPIO_RTC_DATE_R 0x87 +#define GPIO_RTC_HOURS_W 0x84 +#define GPIO_RTC_HOURS_R 0x85 +#define GPIO_RTC_MINUTES_W 0x82 +#define GPIO_RTC_MINUTES_R 0x83 +#define GPIO_RTC_SECONDS_W 0x80 +#define GPIO_RTC_SECONDS_R 0x81 +#define GPIO_RTC_DELAY_TIME 8 + +struct moxart_rtc { + struct rtc_device *rtc; + spinlock_t rtc_lock; + int gpio_data, gpio_sclk, gpio_reset; +}; + +static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + +static void moxart_rtc_write_byte(struct device *dev, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < 8; i++, data >>= 1) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + } +} + +static u8 moxart_rtc_read_byte(struct device *dev) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + int i; + u8 data = 0; + + for (i = 0; i < 8; i++) { + gpio_set_value(moxart_rtc->gpio_sclk, 0); + udelay(GPIO_RTC_DELAY_TIME); + gpio_set_value(moxart_rtc->gpio_sclk, 1); + udelay(GPIO_RTC_DELAY_TIME); + if (gpio_get_value(moxart_rtc->gpio_data)) + data |= (1 << i); + udelay(GPIO_RTC_DELAY_TIME); + } + return data; +} + +static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + u8 data; + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + gpio_direction_input(moxart_rtc->gpio_data); + udelay(GPIO_RTC_DELAY_TIME); + data = moxart_rtc_read_byte(dev); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); + + return data; +} + +static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned long flags; + + local_irq_save(flags); + + gpio_direction_output(moxart_rtc->gpio_data, 0); + gpio_set_value(moxart_rtc->gpio_reset, 1); + udelay(GPIO_RTC_DELAY_TIME); + moxart_rtc_write_byte(dev, cmd); + moxart_rtc_write_byte(dev, data); + gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpio_set_value(moxart_rtc->gpio_reset, 0); + udelay(GPIO_RTC_DELAY_TIME); + + local_irq_restore(flags); +} + +static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + + spin_lock_irq(&moxart_rtc->rtc_lock); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0); + moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, + (((tm->tm_year - 100) / 10) << 4) | + ((tm->tm_year - 100) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, + (((tm->tm_mon + 1) / 10) << 4) | + ((tm->tm_mon + 1) % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, + ((tm->tm_mday / 10) << 4) | + (tm->tm_mday % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, + ((tm->tm_hour / 10) << 4) | + (tm->tm_hour % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, + ((tm->tm_min / 10) << 4) | + (tm->tm_min % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, + ((tm->tm_sec / 10) << 4) | + (tm->tm_sec % 10)); + + moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80); + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" + "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); + unsigned char v; + + spin_lock_irq(&moxart_rtc->rtc_lock); + + v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); + tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); + tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); + if (v & 0x80) { /* 12-hour mode */ + tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + if (v & 0x20) { /* PM mode */ + tm->tm_hour += 12; + if (tm->tm_hour >= 24) + tm->tm_hour = 0; + } + } else { /* 24-hour mode */ + tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + } + + v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); + tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); + + v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); + tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); + tm->tm_mon--; + + v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); + tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); + tm->tm_year += 100; + if (tm->tm_year <= 69) + tm->tm_year += 100; + + v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); + tm->tm_wday = (v & 0x0f) - 1; + tm->tm_yday = day_of_year[tm->tm_mon]; + tm->tm_yday += (tm->tm_mday - 1); + if (tm->tm_mon >= 2) { + if (!(tm->tm_year % 4) && (tm->tm_year % 100)) + tm->tm_yday++; + } + + tm->tm_isdst = 0; + + spin_unlock_irq(&moxart_rtc->rtc_lock); + + return 0; +} + +static const struct rtc_class_ops moxart_rtc_ops = { + .read_time = moxart_rtc_read_time, + .set_time = moxart_rtc_set_time, +}; + +static int moxart_rtc_probe(struct platform_device *pdev) +{ + struct moxart_rtc *moxart_rtc; + int ret = 0; + + moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); + if (!moxart_rtc) { + dev_err(&pdev->dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-data", 0); + if (!gpio_is_valid(moxart_rtc->gpio_data)) { + dev_err(&pdev->dev, "invalid gpio (data): %d\n", + moxart_rtc->gpio_data); + return moxart_rtc->gpio_data; + } + + moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-sclk", 0); + if (!gpio_is_valid(moxart_rtc->gpio_sclk)) { + dev_err(&pdev->dev, "invalid gpio (sclk): %d\n", + moxart_rtc->gpio_sclk); + return moxart_rtc->gpio_sclk; + } + + moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node, + "gpio-rtc-reset", 0); + if (!gpio_is_valid(moxart_rtc->gpio_reset)) { + dev_err(&pdev->dev, "invalid gpio (reset): %d\n", + moxart_rtc->gpio_reset); + return moxart_rtc->gpio_reset; + } + + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + + ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_data gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, + GPIOF_DIR_OUT, "rtc_sclk"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); + return ret; + } + + ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, + GPIOF_DIR_OUT, "rtc_reset"); + if (ret) { + dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); + return ret; + } + + moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &moxart_rtc_ops, + THIS_MODULE); + if (IS_ERR(moxart_rtc->rtc)) { + dev_err(&pdev->dev, "devm_rtc_device_register failed\n"); + return PTR_ERR(moxart_rtc->rtc); + } + + return 0; +} + +static const struct of_device_id moxart_rtc_match[] = { + { .compatible = "moxa,moxart-rtc" }, + { }, +}; + +static struct platform_driver moxart_rtc_driver = { + .probe = moxart_rtc_probe, + .driver = { + .name = "moxart-rtc", + .owner = THIS_MODULE, + .of_match_table = moxart_rtc_match, + }, +}; +module_platform_driver(moxart_rtc_driver); + +MODULE_DESCRIPTION("MOXART RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); -- 1.8.2.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v4] rtc: Add MOXA ART RTC driver 2013-07-17 9:14 ` [PATCH v4] " Jonas Jensen @ 2013-07-17 10:09 ` Mark Brown 0 siblings, 0 replies; 11+ messages in thread From: Mark Brown @ 2013-07-17 10:09 UTC (permalink / raw) To: linux-arm-kernel On Wed, Jul 17, 2013 at 11:14:04AM +0200, Jonas Jensen wrote: > Add RTC driver for MOXA ART SoCs. > > Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> Reviewed-by: Mark Brown <broonie@linaro.org> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130717/cabf25e8/attachment.sig> ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2013-07-17 10:09 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-07-10 14:00 [PATCH] rtc: Add MOXA ART RTC driver Jonas Jensen 2013-07-10 15:47 ` Mark Brown 2013-07-11 13:51 ` [PATCH v2] " Jonas Jensen 2013-07-11 16:51 ` Mark Brown 2013-07-14 19:58 ` Arnd Bergmann 2013-07-16 12:41 ` [PATCH v3] " Jonas Jensen 2013-07-16 13:13 ` Mark Brown 2013-07-16 14:04 ` Jonas Jensen 2013-07-16 15:57 ` Mark Brown 2013-07-17 9:14 ` [PATCH v4] " Jonas Jensen 2013-07-17 10:09 ` Mark Brown
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).