From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751841AbZHJTKH (ORCPT ); Mon, 10 Aug 2009 15:10:07 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751144AbZHJTKG (ORCPT ); Mon, 10 Aug 2009 15:10:06 -0400 Received: from mx0.towertech.it ([213.215.222.73]:56545 "HELO mx0.towertech.it" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1750878AbZHJTKE (ORCPT ); Mon, 10 Aug 2009 15:10:04 -0400 X-Greylist: delayed 864 seconds by postgrey-1.27 at vger.kernel.org; Mon, 10 Aug 2009 15:10:02 EDT Date: Mon, 10 Aug 2009 20:55:35 +0200 From: Alessandro Zummo To: rtc-linux@googlegroups.com Cc: broonie@opensource.wolfsonmicro.com, Samuel Ortiz , linux-kernel@vger.kernel.org, Alessandro Zummo Subject: Re: [rtc-linux] [PATCH 4/5] RTC: Add support for RTCs on Wolfson WM831x devices Message-ID: <20090810205535.4fb160af@i1501.lan.towertech.it> In-Reply-To: <1249922635-31864-4-git-send-email-broonie@opensource.wolfsonmicro.com> References: <1249922635-31864-1-git-send-email-broonie@opensource.wolfsonmicro.com> <1249922635-31864-4-git-send-email-broonie@opensource.wolfsonmicro.com> Organization: Tower Technologies X-Mailer: Sylpheed X-This-Is-A-Real-Message: Yes Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, 10 Aug 2009 17:43:54 +0100 Mark Brown wrote: > > The WM831x series of PMICs contain RTC functionality. The hardware > provides a 32 bit counter incrementing at 1Hz together with a per > tick interrupt and an alarm value. For simplicity the driver chooses > to define the epoch for the counter as the Unix epoch - if required > platform data can be used in future to customise this. [...] HI, comments below: > Signed-off-by: Mark Brown > Cc: Alessandro Zummo > Cc: rtc-linux@googlegroups.com > --- > drivers/rtc/Kconfig | 10 + > drivers/rtc/Makefile | 1 + > drivers/rtc/rtc-wm831x.c | 538 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 549 insertions(+), 0 deletions(-) > create mode 100644 drivers/rtc/rtc-wm831x.c > > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig > index 139b783..f595113 100644 > --- a/drivers/rtc/Kconfig > +++ b/drivers/rtc/Kconfig > @@ -537,6 +537,16 @@ config RTC_DRV_V3020 > This driver can also be built as a module. If so, the module > will be called rtc-v3020. > > +config RTC_DRV_WM831X > + tristate "Wolfson Microelectronics WM831x RTC" > + depends on MFD_WM831X > + help > + If you say yes here you will get support for the RTC subsystem > + of the Wolfson Microelectronics WM831X series PMICs. > + > + This driver can also be built as a module. If so, the module > + will be called "rtc-wm831x". > + > config RTC_DRV_WM8350 > tristate "Wolfson Microelectronics WM8350 RTC" > depends on MFD_WM8350 > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile > index 2a565f8..61d5600 100644 > --- a/drivers/rtc/Makefile > +++ b/drivers/rtc/Makefile > @@ -76,6 +76,7 @@ obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o > obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o > obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o > obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o > +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_PCF50633) += rtc-pcf50633.o > diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c > new file mode 100644 > index 0000000..99e7845 > --- /dev/null > +++ b/drivers/rtc/rtc-wm831x.c > @@ -0,0 +1,538 @@ > +/* > + * Real Time Clock driver for Wolfson Microelectronics WM831x > + * > + * Copyright (C) 2009 Wolfson Microelectronics PLC. > + * > + * Author: Mark Brown > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > + > +/* > + * R16416 (0x4020) - RTC Write Counter > + */ > +#define WM831X_RTC_WR_CNT_MASK 0xFFFF /* RTC_WR_CNT - [15:0] */ > +#define WM831X_RTC_WR_CNT_SHIFT 0 /* RTC_WR_CNT - [15:0] */ > +#define WM831X_RTC_WR_CNT_WIDTH 16 /* RTC_WR_CNT - [15:0] */ > + > +/* > + * R16417 (0x4021) - RTC Time 1 > + */ > +#define WM831X_RTC_TIME_MASK 0xFFFF /* RTC_TIME - [15:0] */ > +#define WM831X_RTC_TIME_SHIFT 0 /* RTC_TIME - [15:0] */ > +#define WM831X_RTC_TIME_WIDTH 16 /* RTC_TIME - [15:0] */ > + > +/* > + * R16418 (0x4022) - RTC Time 2 > + */ > +#define WM831X_RTC_TIME_MASK 0xFFFF /* RTC_TIME - [15:0] */ > +#define WM831X_RTC_TIME_SHIFT 0 /* RTC_TIME - [15:0] */ > +#define WM831X_RTC_TIME_WIDTH 16 /* RTC_TIME - [15:0] */ > + > +/* > + * R16419 (0x4023) - RTC Alarm 1 > + */ > +#define WM831X_RTC_ALM_MASK 0xFFFF /* RTC_ALM - [15:0] */ > +#define WM831X_RTC_ALM_SHIFT 0 /* RTC_ALM - [15:0] */ > +#define WM831X_RTC_ALM_WIDTH 16 /* RTC_ALM - [15:0] */ > + > +/* > + * R16420 (0x4024) - RTC Alarm 2 > + */ > +#define WM831X_RTC_ALM_MASK 0xFFFF /* RTC_ALM - [15:0] */ > +#define WM831X_RTC_ALM_SHIFT 0 /* RTC_ALM - [15:0] */ > +#define WM831X_RTC_ALM_WIDTH 16 /* RTC_ALM - [15:0] */ > + > +/* > + * R16421 (0x4025) - RTC Control > + */ > +#define WM831X_RTC_VALID 0x8000 /* RTC_VALID */ > +#define WM831X_RTC_VALID_MASK 0x8000 /* RTC_VALID */ > +#define WM831X_RTC_VALID_SHIFT 15 /* RTC_VALID */ > +#define WM831X_RTC_VALID_WIDTH 1 /* RTC_VALID */ > +#define WM831X_RTC_SYNC_BUSY 0x4000 /* RTC_SYNC_BUSY */ > +#define WM831X_RTC_SYNC_BUSY_MASK 0x4000 /* RTC_SYNC_BUSY */ > +#define WM831X_RTC_SYNC_BUSY_SHIFT 14 /* RTC_SYNC_BUSY */ > +#define WM831X_RTC_SYNC_BUSY_WIDTH 1 /* RTC_SYNC_BUSY */ > +#define WM831X_RTC_ALM_ENA 0x0400 /* RTC_ALM_ENA */ > +#define WM831X_RTC_ALM_ENA_MASK 0x0400 /* RTC_ALM_ENA */ > +#define WM831X_RTC_ALM_ENA_SHIFT 10 /* RTC_ALM_ENA */ > +#define WM831X_RTC_ALM_ENA_WIDTH 1 /* RTC_ALM_ENA */ > +#define WM831X_RTC_PINT_FREQ_MASK 0x0070 /* RTC_PINT_FREQ - [6:4] */ > +#define WM831X_RTC_PINT_FREQ_SHIFT 4 /* RTC_PINT_FREQ - [6:4] */ > +#define WM831X_RTC_PINT_FREQ_WIDTH 3 /* RTC_PINT_FREQ - [6:4] */ > + > +/* > + * R16422 (0x4026) - RTC Trim > + */ > +#define WM831X_RTC_TRIM_MASK 0x03FF /* RTC_TRIM - [9:0] */ > +#define WM831X_RTC_TRIM_SHIFT 0 /* RTC_TRIM - [9:0] */ > +#define WM831X_RTC_TRIM_WIDTH 10 /* RTC_TRIM - [9:0] */ > + > +#define WM831X_SET_TIME_RETRIES 5 > +#define WM831X_GET_TIME_RETRIES 5 given you have your own include directory undef mfd/ you might want to move those #defines there > +struct wm831x_rtc { > + struct wm831x *wm831x; > + struct rtc_device *rtc; > + int alarm_enabled; > + int per_irq; are those tows int or unsigned int? or maybe alarm_enabled could be :1 ? > +}; > + > +/* > + * Read current time and date in RTC > + */ > +static int wm831x_rtc_readtime(struct device *dev, struct rtc_time *tm) > +{ > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + struct wm831x *wm831x = wm831x_rtc->wm831x; > + u16 time1[2], time2[2]; > + int ret; > + int count = 0; > + > + /* Has the RTC been programmed? */ > + ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); > + if (ret < 0) { > + dev_err(dev, "Failed to read RTC control: %d\n", ret); > + return ret; > + } > + if (!(ret & WM831X_RTC_VALID)) { > + dev_dbg(dev, "RTC not yet configured\n"); > + return -EINVAL; > + } > + > + /* Read twice to make sure we don't read a corrupt, partially > + * incremented, value. > + */ > + do { > + ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1, > + 2, time1); > + if (ret != 0) > + continue; > + > + ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1, > + 2, time2); > + if (ret != 0) > + continue; > + > + if (memcmp(time1, time2, sizeof(time1)) == 0) { > + u32 time = (time1[0] << 16) | time1[1]; > + > + rtc_time_to_tm(time, tm); use return rtc_valid_tm(.. > + return 0; > + } > + > + } while (++count < WM831X_GET_TIME_RETRIES); > + > + dev_err(dev, "Timed out reading current time\n"); > + > + return -EIO; > +} > + > +/* > + * Set current time and date in RTC > + */ > +static int wm831x_rtc_settime(struct device *dev, struct rtc_time *tm) isn't rtc_set_mmss more appropriate? > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + struct wm831x *wm831x = wm831x_rtc->wm831x; > + struct rtc_time new_tm; > + unsigned long time, new_time; > + int ret; > + int count = 0; > + > + ret = rtc_tm_to_time(tm, &time); > + if (ret < 0) { > + dev_err(dev, "Failed to convert time: %d\n", ret); > + return ret; > + } > + > + ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_1, > + (time >> 16) & 0xffff); > + if (ret < 0) { > + dev_err(dev, "Failed to write TIME_1: %d\n", ret); > + return ret; > + } > + > + ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_2, time & 0xffff); > + if (ret < 0) { > + dev_err(dev, "Failed to write TIME_2: %d\n", ret); > + return ret; > + } > + > + /* Wait for the update to complete - should happen first time > + * round but be conservative. > + */ > + do { > + msleep(1); > + > + ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); > + if (ret < 0) > + ret = WM831X_RTC_SYNC_BUSY; > + } while (!(ret & WM831X_RTC_SYNC_BUSY) && > + ++count < WM831X_SET_TIME_RETRIES); > + > + if (ret & WM831X_RTC_SYNC_BUSY) { > + dev_err(dev, "Timed out writing RTC update\n"); > + return -EIO; > + } > + > + /* Check that the update was accepted; security features may > + * have caused the update to be ignored. > + */ > + ret = wm831x_rtc_readtime(dev, &new_tm); > + if (ret < 0) > + return ret; > + > + ret = rtc_tm_to_time(&new_tm, &new_time); > + if (ret < 0) { > + dev_err(dev, "Failed to convert time: %d\n", ret); > + return ret; > + } > + > + /* Allow a second of change in case of tick */ > + if (new_time - time > 1) { > + dev_err(dev, "RTC update not permitted by hardware\n"); > + return -EPERM; > + } > + > + return 0; > +} > + > +/* > + * Read alarm time and date in RTC > + */ > +static int wm831x_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) > +{ > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + int ret; > + u16 data[2]; > + u32 time; > + > + ret = wm831x_bulk_read(wm831x_rtc->wm831x, WM831X_RTC_ALARM_1, > + 2, data); > + if (ret != 0) { > + dev_err(dev, "Failed to read alarm time: %d\n", ret); > + return ret; > + } > + > + time = (data[0] << 16) | data[1]; > + > + rtc_time_to_tm(time, &alrm->time); > + > + ret = wm831x_reg_read(wm831x_rtc->wm831x, WM831X_RTC_CONTROL); > + if (ret < 0) { > + dev_err(dev, "Failed to read RTC control: %d\n", ret); > + return ret; > + } > + > + if (ret & WM831X_RTC_ALM_ENA) > + alrm->enabled = 1; > + else > + alrm->enabled = 0; > + > + return 0; > +} > + > +static int wm831x_rtc_stop_alarm(struct wm831x_rtc *wm831x_rtc) > +{ > + wm831x_rtc->alarm_enabled = 0; > + > + return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, > + WM831X_RTC_ALM_ENA, 0); > +} > + > +static int wm831x_rtc_start_alarm(struct wm831x_rtc *wm831x_rtc) > +{ > + wm831x_rtc->alarm_enabled = 1; > + > + return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, > + WM831X_RTC_ALM_ENA, WM831X_RTC_ALM_ENA); > +} > + > +static int wm831x_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) > +{ > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + struct wm831x *wm831x = wm831x_rtc->wm831x; > + int ret; > + unsigned long time; > + > + ret = rtc_tm_to_time(&alrm->time, &time); > + if (ret < 0) { > + dev_err(dev, "Failed to convert time: %d\n", ret); > + return ret; > + } > + > + ret = wm831x_rtc_stop_alarm(wm831x_rtc); > + if (ret < 0) { > + dev_err(dev, "Failed to stop alarm: %d\n", ret); > + return ret; > + } > + > + ret = wm831x_reg_write(wm831x, WM831X_RTC_ALARM_1, > + (time >> 16) & 0xffff); > + if (ret < 0) { > + dev_err(dev, "Failed to write ALARM_1: %d\n", ret); > + return ret; > + } > + > + ret = wm831x_reg_write(wm831x, WM831X_RTC_ALARM_2, time & 0xffff); > + if (ret < 0) { > + dev_err(dev, "Failed to write ALARM_2: %d\n", ret); > + return ret; > + } > + > + if (alrm->enabled) { > + ret = wm831x_rtc_start_alarm(wm831x_rtc); > + if (ret < 0) { > + dev_err(dev, "Failed to start alarm: %d\n", ret); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int wm831x_rtc_alarm_irq_enable(struct device *dev, > + unsigned int enabled) > +{ > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + > + if (enabled) > + return wm831x_rtc_start_alarm(wm831x_rtc); > + else > + return wm831x_rtc_stop_alarm(wm831x_rtc); > +} > + > +static int wm831x_rtc_update_irq_enable(struct device *dev, > + unsigned int enabled) > +{ > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); > + int val; > + > + if (enabled) > + val = 1 << WM831X_RTC_PINT_FREQ_SHIFT; > + else > + val = 0; > + > + return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, > + WM831X_RTC_PINT_FREQ_MASK, val); > +} > + > +static irqreturn_t wm831x_alm_irq(int irq, void *data) > +{ > + struct wm831x_rtc *wm831x_rtc = data; > + > + rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_AF); > + > + return IRQ_HANDLED; > +} > + > +static irqreturn_t wm831x_per_irq(int irq, void *data) > +{ > + struct wm831x_rtc *wm831x_rtc = data; > + > + rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_UF); > + > + return IRQ_HANDLED; > +} > + > +static const struct rtc_class_ops wm831x_rtc_ops = { > + .read_time = wm831x_rtc_readtime, > + .set_time = wm831x_rtc_settime, > + .read_alarm = wm831x_rtc_readalarm, > + .set_alarm = wm831x_rtc_setalarm, > + .alarm_irq_enable = wm831x_rtc_alarm_irq_enable, > + .update_irq_enable = wm831x_rtc_update_irq_enable, > +}; > + > +#ifdef CONFIG_PM > +/* Turn off the alarm if it should not be a wake source. */ > +static int wm831x_rtc_suspend(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); > + int ret, enable; > + > + if (wm831x_rtc->alarm_enabled && device_may_wakeup(&pdev->dev)) > + enable = WM831X_RTC_ALM_ENA; > + else > + enable = 0; > + > + ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, > + WM831X_RTC_ALM_ENA, enable); > + if (ret != 0) > + dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret); > + > + return 0; always 0 ? (also below..) > +} > + > +/* Enable the alarm if it should be enabled (in case it was disabled to > + * prevent use as a wake source). > + */ > +static int wm831x_rtc_resume(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); > + int ret; > + > + if (wm831x_rtc->alarm_enabled) { > + ret = wm831x_rtc_start_alarm(wm831x_rtc); > + if (ret != 0) > + dev_err(&pdev->dev, > + "Failed to restart RTC alarm: %d\n", ret); > + } > + > + return 0; > +} > + > +/* Unconditionally disable the alarm */ > +static int wm831x_rtc_freeze(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(&pdev->dev); > + int ret; > + > + ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL, > + WM831X_RTC_ALM_ENA, 0); > + if (ret != 0) > + dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret); > + > + return 0; > +} > +#else > +#define wm831x_rtc_suspend NULL > +#define wm831x_rtc_resume NULL > +#define wm831x_rtc_freeze NULL > +#endif > + > +static int wm831x_rtc_probe(struct platform_device *pdev) > +{ > + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); > + struct wm831x_rtc *wm831x_rtc; > + int per_irq = platform_get_irq_byname(pdev, "PER"); > + int alm_irq = platform_get_irq_byname(pdev, "ALM"); > + int ret = 0; > + > + wm831x_rtc = kzalloc(sizeof(*wm831x_rtc), GFP_KERNEL); > + if (wm831x_rtc == NULL) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, wm831x_rtc); > + wm831x_rtc->wm831x = wm831x; > + wm831x_rtc->per_irq = per_irq; > + > + ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); > + if (ret < 0) { > + dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret); > + goto err; > + } > + if (ret & WM831X_RTC_ALM_ENA) > + wm831x_rtc->alarm_enabled = 1; > + > + device_init_wakeup(&pdev->dev, 1); > + > + wm831x_rtc->rtc = rtc_device_register("wm831x", &pdev->dev, > + &wm831x_rtc_ops, THIS_MODULE); > + if (IS_ERR(wm831x_rtc->rtc)) { > + ret = PTR_ERR(wm831x_rtc->rtc); > + dev_err(&pdev->dev, "Failed to register RTC: %d\n", ret); useless, rtc core will emit his own message. > + goto err; > + } > + > + ret = wm831x_request_irq(wm831x, per_irq, wm831x_per_irq, > + IRQF_TRIGGER_RISING, "wm831x_rtc_per", > + wm831x_rtc); > + if (ret != 0) { > + dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", > + per_irq, ret); can't the rtc work without the periodic irq? > + goto err_rtc; > + } > + > + ret = wm831x_request_irq(wm831x, alm_irq, wm831x_alm_irq, > + IRQF_TRIGGER_RISING, "wm831x_rtc_alm", > + wm831x_rtc); > + if (ret != 0) { > + dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", > + alm_irq, ret); ditto. > + goto err_per; > + } > + > + return 0; > + > +err_per: > + wm831x_free_irq(wm831x, per_irq, wm831x_rtc); > +err_rtc: > + rtc_device_unregister(wm831x_rtc->rtc); > +err: > + kfree(wm831x_rtc); > + return ret; > +} > + > +static int __devexit wm831x_rtc_remove(struct platform_device *pdev) > +{ > + struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev); > + int per_irq = platform_get_irq(pdev, 0); > + int alm_irq = platform_get_irq(pdev, 1); why not _byname() ? > + > + wm831x_free_irq(wm831x_rtc->wm831x, alm_irq, wm831x_rtc); > + wm831x_free_irq(wm831x_rtc->wm831x, per_irq, wm831x_rtc); > + rtc_device_unregister(wm831x_rtc->rtc); > + kfree(wm831x_rtc); > + > + return 0; > +} > + > +static struct dev_pm_ops wm831x_rtc_pm_ops = { > + .suspend = wm831x_rtc_suspend, > + .resume = wm831x_rtc_resume, > + > + .freeze = wm831x_rtc_freeze, > + .thaw = wm831x_rtc_resume, > + .restore = wm831x_rtc_resume, > + > + .poweroff = wm831x_rtc_suspend, > +}; > + > +static struct platform_driver wm831x_rtc_driver = { > + .probe = wm831x_rtc_probe, > + .remove = __devexit_p(wm831x_rtc_remove), > + .driver = { > + .name = "wm831x-rtc", > + .pm = &wm831x_rtc_pm_ops, > + }, > +}; > + > +static int __init wm831x_rtc_init(void) > +{ > + return platform_driver_register(&wm831x_rtc_driver); can you use platform_driver_probe() ? > +} > +module_init(wm831x_rtc_init); > + > +static void __exit wm831x_rtc_exit(void) > +{ > + platform_driver_unregister(&wm831x_rtc_driver); > +} > +module_exit(wm831x_rtc_exit); > + > +MODULE_AUTHOR("Mark Brown "); > +MODULE_DESCRIPTION("RTC driver for the WM831x series PMICs"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:wm831x-rtc"); > -- > 1.6.3.3 > > > --~--~---------~--~----~------------~-------~--~----~ > 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. > -~----------~----~----~----~------~----~------~--~--- > -- Best regards, Alessandro Zummo, Tower Technologies - Torino, Italy http://www.towertech.it