Merge branch 'akpm' (incoming from Andrew)
Merge misc patches from Andrew Morton: - Florian has vanished so I appear to have become fbdev maintainer again :( - Joel and Mark are distracted to welcome to the new OCFS2 maintainer - The backlight queue - Small core kernel changes - lib/ updates - The rtc queue - Various random bits * akpm: (164 commits) rtc: rtc-davinci: use devm_*() functions rtc: rtc-max8997: use devm_request_threaded_irq() rtc: rtc-max8907: use devm_request_threaded_irq() rtc: rtc-da9052: use devm_request_threaded_irq() rtc: rtc-wm831x: use devm_request_threaded_irq() rtc: rtc-tps80031: use devm_request_threaded_irq() rtc: rtc-lp8788: use devm_request_threaded_irq() rtc: rtc-coh901331: use devm_clk_get() rtc: rtc-vt8500: use devm_*() functions rtc: rtc-tps6586x: use devm_request_threaded_irq() rtc: rtc-imxdi: use devm_clk_get() rtc: rtc-cmos: use dev_warn()/dev_dbg() instead of printk()/pr_debug() rtc: rtc-pcf8583: use dev_warn() instead of printk() rtc: rtc-sun4v: use pr_warn() instead of printk() rtc: rtc-vr41xx: use dev_info() instead of printk() rtc: rtc-rs5c313: use pr_err() instead of printk() rtc: rtc-at91rm9200: use dev_dbg()/dev_err() instead of printk()/pr_debug() rtc: rtc-rs5c372: use dev_dbg()/dev_warn() instead of printk()/pr_debug() rtc: rtc-ds2404: use dev_err() instead of printk() rtc: rtc-efi: use dev_err()/dev_warn()/pr_err() instead of printk() ...
This commit is contained in:
@@ -204,6 +204,12 @@ config RTC_DRV_DS3232
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-ds3232.
|
||||
|
||||
config RTC_DRV_LP8788
|
||||
tristate "TI LP8788 RTC driver"
|
||||
depends on MFD_LP8788
|
||||
help
|
||||
Say Y to enable support for the LP8788 RTC/ALARM driver.
|
||||
|
||||
config RTC_DRV_MAX6900
|
||||
tristate "Maxim MAX6900"
|
||||
help
|
||||
@@ -243,6 +249,26 @@ config RTC_DRV_MAX8998
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max8998.
|
||||
|
||||
config RTC_DRV_MAX8997
|
||||
tristate "Maxim MAX8997"
|
||||
depends on MFD_MAX8997
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
RTC of Maxim MAX8997 PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max8997.
|
||||
|
||||
config RTC_DRV_MAX77686
|
||||
tristate "Maxim MAX77686"
|
||||
depends on MFD_MAX77686
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
RTC of Maxim MAX77686 PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max77686.
|
||||
|
||||
config RTC_DRV_RS5C372
|
||||
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
|
||||
help
|
||||
@@ -380,6 +406,14 @@ config RTC_DRV_TPS65910
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-tps65910.
|
||||
|
||||
config RTC_DRV_TPS80031
|
||||
tristate "TI TPS80031/TPS80032 RTC driver"
|
||||
depends on MFD_TPS80031
|
||||
help
|
||||
TI Power Managment IC TPS80031 supports RTC functionality
|
||||
along with alarm. This driver supports the RTC driver for
|
||||
the TPS80031 RTC module.
|
||||
|
||||
config RTC_DRV_RC5T583
|
||||
tristate "RICOH 5T583 RTC driver"
|
||||
depends on MFD_RC5T583
|
||||
@@ -537,6 +571,14 @@ config RTC_DRV_PCF2123
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-pcf2123.
|
||||
|
||||
config RTC_DRV_RX4581
|
||||
tristate "Epson RX-4581"
|
||||
help
|
||||
If you say yes here you will get support for the Epson RX-4581.
|
||||
|
||||
This driver can also be built as a module. If so the module
|
||||
will be called rtc-rx4581.
|
||||
|
||||
endif # SPI_MASTER
|
||||
|
||||
comment "Platform RTC drivers"
|
||||
|
@@ -58,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
|
||||
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
|
||||
obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
|
||||
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
|
||||
obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
|
||||
@@ -71,7 +72,9 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
|
||||
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_MPC5121) += rtc-mpc5121.o
|
||||
@@ -97,6 +100,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
||||
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
|
||||
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
|
||||
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
|
||||
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
|
||||
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
|
||||
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
|
||||
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
|
||||
@@ -115,6 +119,7 @@ obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
|
||||
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
|
||||
obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.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
|
||||
|
@@ -11,6 +11,8 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/kdev_t.h>
|
||||
@@ -261,7 +263,7 @@ static int __init rtc_init(void)
|
||||
{
|
||||
rtc_class = class_create(THIS_MODULE, "rtc");
|
||||
if (IS_ERR(rtc_class)) {
|
||||
printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
|
||||
pr_err("couldn't create class\n");
|
||||
return PTR_ERR(rtc_class);
|
||||
}
|
||||
rtc_class->suspend = rtc_suspend;
|
||||
|
@@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
|
||||
tm->tm_year = tm->tm_year - 1900;
|
||||
|
||||
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
@@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned long cr;
|
||||
|
||||
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
@@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
|
||||
? 1 : 0;
|
||||
|
||||
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
@@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
|
||||
}
|
||||
|
||||
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec);
|
||||
|
||||
@@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
pr_debug("%s(): cmd=%08x\n", __func__, enabled);
|
||||
dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled);
|
||||
|
||||
if (enabled) {
|
||||
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
|
||||
@@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
|
||||
|
||||
rtc_update_irq(rtc, 1, events);
|
||||
|
||||
pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
|
||||
dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
|
||||
events >> 8, events & 0x000000FF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
||||
IRQF_SHARED,
|
||||
"at91_rtc", pdev);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
|
||||
irq);
|
||||
dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
||||
}
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
printk(KERN_INFO "AT91 Real Time Clock driver.\n");
|
||||
dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
rtc_cmos_int_handler = hpet_rtc_interrupt;
|
||||
err = hpet_register_irq_handler(cmos_interrupt);
|
||||
if (err != 0) {
|
||||
printk(KERN_WARNING "hpet_register_irq_handler "
|
||||
dev_warn(dev, "hpet_register_irq_handler "
|
||||
" failed in rtc_init().");
|
||||
goto cleanup1;
|
||||
}
|
||||
@@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
pr_info("%s: %s%s, %zd bytes nvram%s\n",
|
||||
dev_name(&cmos_rtc.rtc->dev),
|
||||
dev_info(dev, "%s%s, %zd bytes nvram%s\n",
|
||||
!is_valid_irq(rtc_irq) ? "no alarms" :
|
||||
cmos_rtc.mon_alrm ? "alarms up to one year" :
|
||||
cmos_rtc.day_alrm ? "alarms up to one month" :
|
||||
@@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev)
|
||||
enable_irq_wake(cmos->irq);
|
||||
}
|
||||
|
||||
pr_debug("%s: suspend%s, ctrl %02x\n",
|
||||
dev_name(&cmos_rtc.rtc->dev),
|
||||
dev_dbg(dev, "suspend%s, ctrl %02x\n",
|
||||
(tmp & RTC_AIE) ? ", alarm may wake" : "",
|
||||
tmp);
|
||||
|
||||
@@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev)
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
}
|
||||
|
||||
pr_debug("%s: resume, ctrl %02x\n",
|
||||
dev_name(&cmos_rtc.rtc->dev),
|
||||
tmp);
|
||||
dev_dbg(dev, "resume, ctrl %02x\n", tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1098,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev)
|
||||
}
|
||||
#else
|
||||
static inline void cmos_of_init(struct platform_device *pdev) {}
|
||||
#define of_cmos_match NULL
|
||||
#endif
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
@@ -1140,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = {
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &cmos_pm_ops,
|
||||
#endif
|
||||
.of_match_table = of_cmos_match,
|
||||
.of_match_table = of_match_ptr(of_cmos_match),
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev)
|
||||
if (rtap) {
|
||||
rtc_device_unregister(rtap->rtc);
|
||||
clk_unprepare(rtap->clk);
|
||||
clk_put(rtap->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
@@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
|
||||
"RTC COH 901 331 Alarm", rtap))
|
||||
return -EIO;
|
||||
|
||||
rtap->clk = clk_get(&pdev->dev, NULL);
|
||||
rtap->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(rtap->clk)) {
|
||||
ret = PTR_ERR(rtap->clk);
|
||||
dev_err(&pdev->dev, "could not get clock\n");
|
||||
@@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
|
||||
ret = clk_prepare_enable(rtap->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "could not enable clock\n");
|
||||
goto out_no_clk_prepenable;
|
||||
return ret;
|
||||
}
|
||||
clk_disable(rtap->clk);
|
||||
|
||||
@@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev)
|
||||
out_no_rtc:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
clk_unprepare(rtap->clk);
|
||||
out_no_clk_prepenable:
|
||||
clk_put(rtap->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
|
||||
rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
rtc->irq = platform_get_irq_byname(pdev, "ALM");
|
||||
ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"ALM", rtc);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
da9052_rtc_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"ALM", rtc);
|
||||
if (ret != 0) {
|
||||
rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
|
||||
return ret;
|
||||
@@ -250,16 +251,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
|
||||
&da9052_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
goto err_free_irq;
|
||||
}
|
||||
if (IS_ERR(rtc->rtc))
|
||||
return PTR_ERR(rtc->rtc);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(rtc->irq, rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da9052_rtc_remove(struct platform_device *pdev)
|
||||
@@ -267,7 +262,6 @@ static int da9052_rtc_remove(struct platform_device *pdev)
|
||||
struct da9052_rtc *rtc = pdev->dev.platform_data;
|
||||
|
||||
rtc_device_unregister(rtc->rtc);
|
||||
free_irq(rtc->irq, rtc);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
|
@@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
|
||||
davinci_rtc->pbase = res->start;
|
||||
davinci_rtc->base_size = resource_size(res);
|
||||
|
||||
mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size,
|
||||
pdev->name);
|
||||
mem = devm_request_mem_region(dev, davinci_rtc->pbase,
|
||||
davinci_rtc->base_size, pdev->name);
|
||||
if (!mem) {
|
||||
dev_err(dev, "RTC registers at %08x are not free\n",
|
||||
davinci_rtc->pbase);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size);
|
||||
davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase,
|
||||
davinci_rtc->base_size);
|
||||
if (!davinci_rtc->base) {
|
||||
dev_err(dev, "unable to ioremap MEM resource\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail2;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, davinci_rtc);
|
||||
@@ -529,7 +529,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
|
||||
ret = PTR_ERR(davinci_rtc->rtc);
|
||||
dev_err(dev, "unable to register RTC device, err %d\n",
|
||||
ret);
|
||||
goto fail3;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
|
||||
@@ -539,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
|
||||
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
|
||||
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
|
||||
|
||||
ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
|
||||
ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt,
|
||||
0, "davinci_rtc", davinci_rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to register davinci RTC interrupt\n");
|
||||
goto fail4;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
@@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
fail4:
|
||||
rtc_device_unregister(davinci_rtc->rtc);
|
||||
fail3:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
iounmap(davinci_rtc->base);
|
||||
fail2:
|
||||
release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
|
||||
rtc_device_unregister(davinci_rtc->rtc);
|
||||
fail1:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev)
|
||||
|
||||
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
|
||||
|
||||
free_irq(davinci_rtc->irq, davinci_rtc);
|
||||
|
||||
rtc_device_unregister(davinci_rtc->rtc);
|
||||
|
||||
iounmap(davinci_rtc->base);
|
||||
release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
|
@@ -11,6 +11,8 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/sched.h>
|
||||
@@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
|
||||
return;
|
||||
|
||||
if (rtc->id >= RTC_DEV_MAX) {
|
||||
pr_debug("%s: too many RTC devices\n", rtc->name);
|
||||
dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc)
|
||||
void rtc_dev_add_device(struct rtc_device *rtc)
|
||||
{
|
||||
if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
|
||||
printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
|
||||
dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
|
||||
rtc->name, MAJOR(rtc_devt), rtc->id);
|
||||
else
|
||||
pr_debug("%s: dev (%d:%d)\n", rtc->name,
|
||||
dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
|
||||
MAJOR(rtc_devt), rtc->id);
|
||||
}
|
||||
|
||||
@@ -499,8 +501,7 @@ void __init rtc_dev_init(void)
|
||||
|
||||
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
|
||||
if (err < 0)
|
||||
printk(KERN_ERR "%s: failed to allocate char dev region\n",
|
||||
__FILE__);
|
||||
pr_err("failed to allocate char dev region\n");
|
||||
}
|
||||
|
||||
void __exit rtc_dev_exit(void)
|
||||
|
@@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi)
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
|
||||
"read", ds1305->ctrl[0],
|
||||
ds1305->ctrl[1], ds1305->ctrl[2]);
|
||||
dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
|
||||
|
||||
/* Sanity check register values ... partially compensating for the
|
||||
* fact that SPI has no device handshake. A pullup on MISO would
|
||||
@@ -723,9 +721,7 @@ static int ds1305_probe(struct spi_device *spi)
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
|
||||
"write", ds1305->ctrl[0],
|
||||
ds1305->ctrl[1], ds1305->ctrl[2]);
|
||||
dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
|
||||
}
|
||||
|
||||
/* see if non-Linux software set up AM/PM mode */
|
||||
|
@@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"read",
|
||||
ds1307->regs[0], ds1307->regs[1],
|
||||
ds1307->regs[2], ds1307->regs[3],
|
||||
ds1307->regs[4], ds1307->regs[5],
|
||||
ds1307->regs[6]);
|
||||
dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
|
||||
|
||||
t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
|
||||
t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
|
||||
@@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"write", buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6]);
|
||||
dev_dbg(dev, "%s: %7ph\n", "write", buf);
|
||||
|
||||
result = ds1307->write_block_data(ds1307->client,
|
||||
ds1307->offset, 7, buf);
|
||||
|
@@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
|
||||
for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
|
||||
err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
|
||||
if (err) {
|
||||
printk(KERN_ERR "error mapping gpio %s: %d\n",
|
||||
dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
|
||||
ds2404_gpio[i].name, err);
|
||||
goto err_request;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset,
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (out[i] != ds2404_read_byte(dev)) {
|
||||
printk(KERN_ERR "read invalid data\n");
|
||||
dev_err(dev, "read invalid data\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static __init int ds2404_init(void)
|
||||
{
|
||||
return platform_driver_register(&rtc_device_driver);
|
||||
}
|
||||
|
||||
static __exit void ds2404_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rtc_device_driver);
|
||||
}
|
||||
|
||||
module_init(ds2404_init);
|
||||
module_exit(ds2404_exit);
|
||||
module_platform_driver(rtc_device_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DS2404 RTC");
|
||||
MODULE_AUTHOR("Sven Schnelle");
|
||||
|
@@ -13,6 +13,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
@@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft)
|
||||
int ndays = 0;
|
||||
|
||||
if (eft->year < 1998) {
|
||||
printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
|
||||
pr_err("EFI year < 1998, invalid date\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
|
||||
eft->day = wtime->tm_mday;
|
||||
eft->hour = wtime->tm_hour;
|
||||
eft->minute = wtime->tm_min;
|
||||
eft->second = wtime->tm_sec;
|
||||
eft->second = wtime->tm_sec;
|
||||
eft->nanosecond = 0;
|
||||
eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
|
||||
eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
|
||||
@@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
*/
|
||||
status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
|
||||
|
||||
printk(KERN_WARNING "write status is %d\n", (int)status);
|
||||
dev_warn(dev, "write status is %d\n", (int)status);
|
||||
|
||||
return status == EFI_SUCCESS ? 0 : -EINVAL;
|
||||
}
|
||||
@@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
/* should never happen */
|
||||
printk(KERN_ERR "efitime: can't read time\n");
|
||||
dev_err(dev, "can't read time\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
|
||||
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"read",
|
||||
fm3130->regs[0], fm3130->regs[1],
|
||||
fm3130->regs[2], fm3130->regs[3],
|
||||
fm3130->regs[4], fm3130->regs[5],
|
||||
fm3130->regs[6], fm3130->regs[7],
|
||||
fm3130->regs[8], fm3130->regs[9],
|
||||
fm3130->regs[0xa], fm3130->regs[0xb],
|
||||
fm3130->regs[0xc], fm3130->regs[0xd],
|
||||
fm3130->regs[0xe]);
|
||||
dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs);
|
||||
|
||||
t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
|
||||
t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
|
||||
@@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t)
|
||||
tmp = t->tm_year - 100;
|
||||
buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"write", buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7],
|
||||
buf[8], buf[9], buf[0xa], buf[0xb],
|
||||
buf[0xc], buf[0xd], buf[0xe]);
|
||||
dev_dbg(dev, "%s: %15ph\n", "write", buf);
|
||||
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
|
||||
|
||||
@@ -517,18 +502,8 @@ bad_alarm:
|
||||
bad_clock:
|
||||
|
||||
if (!fm3130->data_valid || !fm3130->alarm_valid)
|
||||
dev_dbg(&client->dev,
|
||||
"%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"bogus registers",
|
||||
fm3130->regs[0], fm3130->regs[1],
|
||||
fm3130->regs[2], fm3130->regs[3],
|
||||
fm3130->regs[4], fm3130->regs[5],
|
||||
fm3130->regs[6], fm3130->regs[7],
|
||||
fm3130->regs[8], fm3130->regs[9],
|
||||
fm3130->regs[0xa], fm3130->regs[0xb],
|
||||
fm3130->regs[0xc], fm3130->regs[0xd],
|
||||
fm3130->regs[0xe]);
|
||||
dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers",
|
||||
fm3130->regs);
|
||||
|
||||
/* We won't bail out here because we just got invalid data.
|
||||
Time setting from u-boot doesn't work anyway */
|
||||
|
@@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&imxdi->write_mutex);
|
||||
|
||||
imxdi->clk = clk_get(&pdev->dev, NULL);
|
||||
imxdi->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(imxdi->clk))
|
||||
return PTR_ERR(imxdi->clk);
|
||||
clk_prepare_enable(imxdi->clk);
|
||||
@@ -475,7 +475,6 @@ static int dryice_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
err:
|
||||
clk_disable_unprepare(imxdi->clk);
|
||||
clk_put(imxdi->clk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -492,7 +491,6 @@ static int dryice_rtc_remove(struct platform_device *pdev)
|
||||
rtc_device_unregister(imxdi->rtc);
|
||||
|
||||
clk_disable_unprepare(imxdi->clk);
|
||||
clk_put(imxdi->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
buf[ISL12022_REG_SC + i]);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
338
drivers/rtc/rtc-lp8788.c
Normal file
338
drivers/rtc/rtc-lp8788.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* TI LP8788 MFD - rtc driver
|
||||
*
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mfd/lp8788.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* register address */
|
||||
#define LP8788_INTEN_3 0x05
|
||||
#define LP8788_RTC_UNLOCK 0x64
|
||||
#define LP8788_RTC_SEC 0x70
|
||||
#define LP8788_ALM1_SEC 0x77
|
||||
#define LP8788_ALM1_EN 0x7D
|
||||
#define LP8788_ALM2_SEC 0x7E
|
||||
#define LP8788_ALM2_EN 0x84
|
||||
|
||||
/* mask/shift bits */
|
||||
#define LP8788_INT_RTC_ALM1_M BIT(1) /* Addr 05h */
|
||||
#define LP8788_INT_RTC_ALM1_S 1
|
||||
#define LP8788_INT_RTC_ALM2_M BIT(2) /* Addr 05h */
|
||||
#define LP8788_INT_RTC_ALM2_S 2
|
||||
#define LP8788_ALM_EN_M BIT(7) /* Addr 7Dh or 84h */
|
||||
#define LP8788_ALM_EN_S 7
|
||||
|
||||
#define DEFAULT_ALARM_SEL LP8788_ALARM_1
|
||||
#define LP8788_MONTH_OFFSET 1
|
||||
#define LP8788_BASE_YEAR 2000
|
||||
#define MAX_WDAY_BITS 7
|
||||
#define LP8788_WDAY_SET 1
|
||||
#define RTC_UNLOCK 0x1
|
||||
#define RTC_LATCH 0x2
|
||||
#define ALARM_IRQ_FLAG (RTC_IRQF | RTC_AF)
|
||||
|
||||
enum lp8788_time {
|
||||
LPTIME_SEC,
|
||||
LPTIME_MIN,
|
||||
LPTIME_HOUR,
|
||||
LPTIME_MDAY,
|
||||
LPTIME_MON,
|
||||
LPTIME_YEAR,
|
||||
LPTIME_WDAY,
|
||||
LPTIME_MAX,
|
||||
};
|
||||
|
||||
struct lp8788_rtc {
|
||||
struct lp8788 *lp;
|
||||
struct rtc_device *rdev;
|
||||
enum lp8788_alarm_sel alarm;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = {
|
||||
LP8788_ALM1_SEC,
|
||||
LP8788_ALM2_SEC,
|
||||
};
|
||||
|
||||
static const u8 addr_alarm_en[LP8788_ALARM_MAX] = {
|
||||
LP8788_ALM1_EN,
|
||||
LP8788_ALM2_EN,
|
||||
};
|
||||
|
||||
static const u8 mask_alarm_en[LP8788_ALARM_MAX] = {
|
||||
LP8788_INT_RTC_ALM1_M,
|
||||
LP8788_INT_RTC_ALM2_M,
|
||||
};
|
||||
|
||||
static const u8 shift_alarm_en[LP8788_ALARM_MAX] = {
|
||||
LP8788_INT_RTC_ALM1_S,
|
||||
LP8788_INT_RTC_ALM2_S,
|
||||
};
|
||||
|
||||
static int _to_tm_wday(u8 lp8788_wday)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (lp8788_wday == 0)
|
||||
return 0;
|
||||
|
||||
/* lookup defined weekday from read register value */
|
||||
for (i = 0; i < MAX_WDAY_BITS; i++) {
|
||||
if ((lp8788_wday >> i) == LP8788_WDAY_SET)
|
||||
break;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static inline int _to_lp8788_wday(int tm_wday)
|
||||
{
|
||||
return LP8788_WDAY_SET << (tm_wday - 1);
|
||||
}
|
||||
|
||||
static void lp8788_rtc_unlock(struct lp8788 *lp)
|
||||
{
|
||||
lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK);
|
||||
lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH);
|
||||
}
|
||||
|
||||
static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct lp8788_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
u8 data[LPTIME_MAX];
|
||||
int ret;
|
||||
|
||||
lp8788_rtc_unlock(lp);
|
||||
|
||||
ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data, LPTIME_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tm->tm_sec = data[LPTIME_SEC];
|
||||
tm->tm_min = data[LPTIME_MIN];
|
||||
tm->tm_hour = data[LPTIME_HOUR];
|
||||
tm->tm_mday = data[LPTIME_MDAY];
|
||||
tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
|
||||
tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
|
||||
tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct lp8788_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
u8 data[LPTIME_MAX - 1];
|
||||
int ret, i, year;
|
||||
|
||||
year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
|
||||
if (year < 0) {
|
||||
dev_err(lp->dev, "invalid year: %d\n", year);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* because rtc weekday is a readonly register, do not update */
|
||||
data[LPTIME_SEC] = tm->tm_sec;
|
||||
data[LPTIME_MIN] = tm->tm_min;
|
||||
data[LPTIME_HOUR] = tm->tm_hour;
|
||||
data[LPTIME_MDAY] = tm->tm_mday;
|
||||
data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET;
|
||||
data[LPTIME_YEAR] = year;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++) {
|
||||
ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct lp8788_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
struct rtc_time *tm = &alarm->time;
|
||||
u8 addr, data[LPTIME_MAX];
|
||||
int ret;
|
||||
|
||||
addr = addr_alarm_sec[rtc->alarm];
|
||||
ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tm->tm_sec = data[LPTIME_SEC];
|
||||
tm->tm_min = data[LPTIME_MIN];
|
||||
tm->tm_hour = data[LPTIME_HOUR];
|
||||
tm->tm_mday = data[LPTIME_MDAY];
|
||||
tm->tm_mon = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
|
||||
tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
|
||||
tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
|
||||
alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct lp8788_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
struct rtc_time *tm = &alarm->time;
|
||||
u8 addr, data[LPTIME_MAX];
|
||||
int ret, i, year;
|
||||
|
||||
year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
|
||||
if (year < 0) {
|
||||
dev_err(lp->dev, "invalid year: %d\n", year);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data[LPTIME_SEC] = tm->tm_sec;
|
||||
data[LPTIME_MIN] = tm->tm_min;
|
||||
data[LPTIME_HOUR] = tm->tm_hour;
|
||||
data[LPTIME_MDAY] = tm->tm_mday;
|
||||
data[LPTIME_MON] = tm->tm_mon + LP8788_MONTH_OFFSET;
|
||||
data[LPTIME_YEAR] = year;
|
||||
data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++) {
|
||||
addr = addr_alarm_sec[rtc->alarm] + i;
|
||||
ret = lp8788_write_byte(lp, addr, data[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarm->enabled = 1;
|
||||
addr = addr_alarm_en[rtc->alarm];
|
||||
|
||||
return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M,
|
||||
alarm->enabled << LP8788_ALM_EN_S);
|
||||
}
|
||||
|
||||
static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
struct lp8788_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
u8 mask, shift;
|
||||
|
||||
if (!rtc->irq)
|
||||
return -EIO;
|
||||
|
||||
mask = mask_alarm_en[rtc->alarm];
|
||||
shift = shift_alarm_en[rtc->alarm];
|
||||
|
||||
return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops lp8788_rtc_ops = {
|
||||
.read_time = lp8788_rtc_read_time,
|
||||
.set_time = lp8788_rtc_set_time,
|
||||
.read_alarm = lp8788_read_alarm,
|
||||
.set_alarm = lp8788_set_alarm,
|
||||
.alarm_irq_enable = lp8788_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr)
|
||||
{
|
||||
struct lp8788_rtc *rtc = ptr;
|
||||
|
||||
rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lp8788_alarm_irq_register(struct platform_device *pdev,
|
||||
struct lp8788_rtc *rtc)
|
||||
{
|
||||
struct resource *r;
|
||||
struct lp8788 *lp = rtc->lp;
|
||||
struct irq_domain *irqdm = lp->irqdm;
|
||||
int irq;
|
||||
|
||||
rtc->irq = 0;
|
||||
|
||||
/* even the alarm IRQ number is not specified, rtc time should work */
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ);
|
||||
if (!r)
|
||||
return 0;
|
||||
|
||||
if (rtc->alarm == LP8788_ALARM_1)
|
||||
irq = r->start;
|
||||
else
|
||||
irq = r->end;
|
||||
|
||||
rtc->irq = irq_create_mapping(irqdm, irq);
|
||||
|
||||
return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
lp8788_alarm_irq_handler,
|
||||
0, LP8788_ALM_IRQ, rtc);
|
||||
}
|
||||
|
||||
static int lp8788_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
|
||||
struct lp8788_rtc *rtc;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->lp = lp;
|
||||
rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL;
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
device_init_wakeup(dev, 1);
|
||||
|
||||
rtc->rdev = rtc_device_register("lp8788_rtc", dev,
|
||||
&lp8788_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rdev)) {
|
||||
dev_err(dev, "can not register rtc device\n");
|
||||
return PTR_ERR(rtc->rdev);
|
||||
}
|
||||
|
||||
if (lp8788_alarm_irq_register(pdev, rtc))
|
||||
dev_warn(lp->dev, "no rtc irq handler\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lp8788_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(rtc->rdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver lp8788_rtc_driver = {
|
||||
.probe = lp8788_rtc_probe,
|
||||
.remove = lp8788_rtc_remove,
|
||||
.driver = {
|
||||
.name = LP8788_DEV_RTC,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lp8788_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver");
|
||||
MODULE_AUTHOR("Milo Kim");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:lp8788-rtc");
|
641
drivers/rtc/rtc-max77686.c
Normal file
641
drivers/rtc/rtc-max77686.c
Normal file
@@ -0,0 +1,641 @@
|
||||
/*
|
||||
* RTC driver for Maxim MAX77686
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics Co.Ltd
|
||||
*
|
||||
* based on rtc-max8997.c
|
||||
*
|
||||
* 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 <linux/slab.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max77686-private.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* RTC Control Register */
|
||||
#define BCD_EN_SHIFT 0
|
||||
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
|
||||
#define MODEL24_SHIFT 1
|
||||
#define MODEL24_MASK (1 << MODEL24_SHIFT)
|
||||
/* RTC Update Register1 */
|
||||
#define RTC_UDR_SHIFT 0
|
||||
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
|
||||
#define RTC_RBUDR_SHIFT 4
|
||||
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
|
||||
/* WTSR and SMPL Register */
|
||||
#define WTSRT_SHIFT 0
|
||||
#define SMPLT_SHIFT 2
|
||||
#define WTSR_EN_SHIFT 6
|
||||
#define SMPL_EN_SHIFT 7
|
||||
#define WTSRT_MASK (3 << WTSRT_SHIFT)
|
||||
#define SMPLT_MASK (3 << SMPLT_SHIFT)
|
||||
#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT)
|
||||
#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT)
|
||||
/* RTC Hour register */
|
||||
#define HOUR_PM_SHIFT 6
|
||||
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
|
||||
/* RTC Alarm Enable */
|
||||
#define ALARM_ENABLE_SHIFT 7
|
||||
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
|
||||
|
||||
#define MAX77686_RTC_UPDATE_DELAY 16
|
||||
#undef MAX77686_RTC_WTSR_SMPL
|
||||
|
||||
enum {
|
||||
RTC_SEC = 0,
|
||||
RTC_MIN,
|
||||
RTC_HOUR,
|
||||
RTC_WEEKDAY,
|
||||
RTC_MONTH,
|
||||
RTC_YEAR,
|
||||
RTC_DATE,
|
||||
RTC_NR_TIME
|
||||
};
|
||||
|
||||
struct max77686_rtc_info {
|
||||
struct device *dev;
|
||||
struct max77686_dev *max77686;
|
||||
struct i2c_client *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct mutex lock;
|
||||
|
||||
struct regmap *regmap;
|
||||
|
||||
int virq;
|
||||
int rtc_24hr_mode;
|
||||
};
|
||||
|
||||
enum MAX77686_RTC_OP {
|
||||
MAX77686_RTC_WRITE,
|
||||
MAX77686_RTC_READ,
|
||||
};
|
||||
|
||||
static inline int max77686_rtc_calculate_wday(u8 shifted)
|
||||
{
|
||||
int counter = -1;
|
||||
while (shifted) {
|
||||
shifted >>= 1;
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
||||
int rtc_24hr_mode)
|
||||
{
|
||||
tm->tm_sec = data[RTC_SEC] & 0x7f;
|
||||
tm->tm_min = data[RTC_MIN] & 0x7f;
|
||||
if (rtc_24hr_mode)
|
||||
tm->tm_hour = data[RTC_HOUR] & 0x1f;
|
||||
else {
|
||||
tm->tm_hour = data[RTC_HOUR] & 0x0f;
|
||||
if (data[RTC_HOUR] & HOUR_PM_MASK)
|
||||
tm->tm_hour += 12;
|
||||
}
|
||||
|
||||
tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f);
|
||||
tm->tm_mday = data[RTC_DATE] & 0x1f;
|
||||
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
|
||||
tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
|
||||
tm->tm_yday = 0;
|
||||
tm->tm_isdst = 0;
|
||||
}
|
||||
|
||||
static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
|
||||
{
|
||||
data[RTC_SEC] = tm->tm_sec;
|
||||
data[RTC_MIN] = tm->tm_min;
|
||||
data[RTC_HOUR] = tm->tm_hour;
|
||||
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
|
||||
data[RTC_DATE] = tm->tm_mday;
|
||||
data[RTC_MONTH] = tm->tm_mon + 1;
|
||||
data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
|
||||
|
||||
if (tm->tm_year < 100) {
|
||||
pr_warn("%s: MAX77686 RTC cannot handle the year %d."
|
||||
"Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77686_rtc_update(struct max77686_rtc_info *info,
|
||||
enum MAX77686_RTC_OP op)
|
||||
{
|
||||
int ret;
|
||||
unsigned int data;
|
||||
|
||||
if (op == MAX77686_RTC_WRITE)
|
||||
data = 1 << RTC_UDR_SHIFT;
|
||||
else
|
||||
data = 1 << RTC_RBUDR_SHIFT;
|
||||
|
||||
ret = regmap_update_bits(info->max77686->rtc_regmap,
|
||||
MAX77686_RTC_UPDATE0, data, data);
|
||||
if (ret < 0)
|
||||
dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
|
||||
__func__, ret, data);
|
||||
else {
|
||||
/* Minimum 16ms delay required before RTC update. */
|
||||
msleep(MAX77686_RTC_UPDATE_DELAY);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = regmap_bulk_read(info->max77686->rtc_regmap,
|
||||
MAX77686_RTC_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
|
||||
|
||||
ret = rtc_valid_tm(tm);
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
ret = max77686_rtc_tm_to_data(tm, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = regmap_bulk_write(info->max77686->rtc_regmap,
|
||||
MAX77686_RTC_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
unsigned int val;
|
||||
int i, ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = regmap_bulk_read(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
|
||||
__func__, __LINE__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
|
||||
|
||||
alrm->enabled = 0;
|
||||
for (i = 0; i < RTC_NR_TIME; i++) {
|
||||
if (data[i] & ALARM_ENABLE_MASK) {
|
||||
alrm->enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
alrm->pending = 0;
|
||||
ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
|
||||
__func__, __LINE__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val & (1 << 4)) /* RTCA1 */
|
||||
alrm->pending = 1;
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
|
||||
{
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret, i;
|
||||
struct rtc_time tm;
|
||||
|
||||
if (!mutex_is_locked(&info->lock))
|
||||
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = regmap_bulk_read(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
|
||||
|
||||
for (i = 0; i < RTC_NR_TIME; i++)
|
||||
data[i] &= ~ALARM_ENABLE_MASK;
|
||||
|
||||
ret = regmap_bulk_write(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
|
||||
{
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
struct rtc_time tm;
|
||||
|
||||
if (!mutex_is_locked(&info->lock))
|
||||
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_READ);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = regmap_bulk_read(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
|
||||
|
||||
data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
|
||||
if (data[RTC_MONTH] & 0xf)
|
||||
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
if (data[RTC_YEAR] & 0x7f)
|
||||
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
if (data[RTC_DATE] & 0x1f)
|
||||
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
|
||||
ret = regmap_bulk_write(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
ret = max77686_rtc_tm_to_data(&alrm->time, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max77686_rtc_stop_alarm(info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = regmap_bulk_write(info->max77686->rtc_regmap,
|
||||
MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (alrm->enabled)
|
||||
ret = max77686_rtc_start_alarm(info);
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct max77686_rtc_info *info = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
if (enabled)
|
||||
ret = max77686_rtc_start_alarm(info);
|
||||
else
|
||||
ret = max77686_rtc_stop_alarm(info);
|
||||
mutex_unlock(&info->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
|
||||
{
|
||||
struct max77686_rtc_info *info = data;
|
||||
|
||||
dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
|
||||
|
||||
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops max77686_rtc_ops = {
|
||||
.read_time = max77686_rtc_read_time,
|
||||
.set_time = max77686_rtc_set_time,
|
||||
.read_alarm = max77686_rtc_read_alarm,
|
||||
.set_alarm = max77686_rtc_set_alarm,
|
||||
.alarm_irq_enable = max77686_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
||||
static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val, mask;
|
||||
|
||||
if (enable)
|
||||
val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
|
||||
else
|
||||
val = 0;
|
||||
|
||||
mask = WTSR_EN_MASK | WTSRT_MASK;
|
||||
|
||||
dev_info(info->dev, "%s: %s WTSR\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
ret = regmap_update_bits(info->max77686->rtc_regmap,
|
||||
MAX77686_WTSR_SMPL_CNTL, mask, val);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
|
||||
__func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
}
|
||||
|
||||
static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val, mask;
|
||||
|
||||
if (enable)
|
||||
val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
|
||||
else
|
||||
val = 0;
|
||||
|
||||
mask = SMPL_EN_MASK | SMPLT_MASK;
|
||||
|
||||
dev_info(info->dev, "%s: %s SMPL\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
ret = regmap_update_bits(info->max77686->rtc_regmap,
|
||||
MAX77686_WTSR_SMPL_CNTL, mask, val);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
|
||||
__func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
|
||||
val = 0;
|
||||
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
|
||||
pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
|
||||
}
|
||||
#endif /* MAX77686_RTC_WTSR_SMPL */
|
||||
|
||||
static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
|
||||
{
|
||||
u8 data[2];
|
||||
int ret;
|
||||
|
||||
/* Set RTC control register : Binary mode, 24hour mdoe */
|
||||
data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||
data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||
|
||||
info->rtc_24hr_mode = 1;
|
||||
|
||||
ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regmap_config max77686_rtc_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int max77686_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max77686_rtc_info *info;
|
||||
int ret, virq;
|
||||
|
||||
dev_info(&pdev->dev, "%s\n", __func__);
|
||||
|
||||
info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&info->lock);
|
||||
info->dev = &pdev->dev;
|
||||
info->max77686 = max77686;
|
||||
info->rtc = max77686->rtc;
|
||||
info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc,
|
||||
&max77686_rtc_regmap_config);
|
||||
if (IS_ERR(info->max77686->rtc_regmap)) {
|
||||
ret = PTR_ERR(info->max77686->rtc_regmap);
|
||||
dev_err(info->max77686->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = max77686_rtc_init_reg(info);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
|
||||
goto err_rtc;
|
||||
}
|
||||
|
||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
||||
max77686_rtc_enable_wtsr(info, true);
|
||||
max77686_rtc_enable_smpl(info, true);
|
||||
#endif
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev,
|
||||
&max77686_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(info->rtc_dev)) {
|
||||
dev_info(&pdev->dev, "%s: fail\n", __func__);
|
||||
|
||||
ret = PTR_ERR(info->rtc_dev);
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
if (ret == 0)
|
||||
ret = -EINVAL;
|
||||
goto err_rtc;
|
||||
}
|
||||
virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1);
|
||||
if (!virq)
|
||||
goto err_rtc;
|
||||
info->virq = virq;
|
||||
|
||||
ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0,
|
||||
"rtc-alarm0", info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
info->virq, ret);
|
||||
goto err_rtc;
|
||||
}
|
||||
|
||||
goto out;
|
||||
err_rtc:
|
||||
kfree(info);
|
||||
return ret;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max77686_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max77686_rtc_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
if (info) {
|
||||
free_irq(info->virq, info);
|
||||
rtc_device_unregister(info->rtc_dev);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max77686_rtc_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef MAX77686_RTC_WTSR_SMPL
|
||||
struct max77686_rtc_info *info = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
u8 val = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
max77686_rtc_enable_wtsr(info, false);
|
||||
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
|
||||
pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);
|
||||
if (val & WTSR_EN_MASK)
|
||||
pr_emerg("%s: fail to disable WTSR\n", __func__);
|
||||
else {
|
||||
pr_info("%s: success to disable WTSR\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable SMPL when power off */
|
||||
max77686_rtc_enable_smpl(info, false);
|
||||
#endif /* MAX77686_RTC_WTSR_SMPL */
|
||||
}
|
||||
|
||||
static const struct platform_device_id rtc_id[] = {
|
||||
{ "max77686-rtc", 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver max77686_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "max77686-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max77686_rtc_probe,
|
||||
.remove = max77686_rtc_remove,
|
||||
.shutdown = max77686_rtc_shutdown,
|
||||
.id_table = rtc_id,
|
||||
};
|
||||
|
||||
static int __init max77686_rtc_init(void)
|
||||
{
|
||||
return platform_driver_register(&max77686_rtc_driver);
|
||||
}
|
||||
module_init(max77686_rtc_init);
|
||||
|
||||
static void __exit max77686_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&max77686_rtc_driver);
|
||||
}
|
||||
module_exit(max77686_rtc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Maxim MAX77686 RTC driver");
|
||||
MODULE_AUTHOR("<woong.byun@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
@@ -205,8 +205,9 @@ static int max8907_rtc_probe(struct platform_device *pdev)
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler,
|
||||
IRQF_ONESHOT, "max8907-alarm0", rtc);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
max8907_irq_handler,
|
||||
IRQF_ONESHOT, "max8907-alarm0", rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
|
||||
rtc->irq, ret);
|
||||
@@ -224,7 +225,6 @@ static int max8907_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8907_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(rtc->irq, rtc);
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
|
||||
return 0;
|
||||
|
552
drivers/rtc/rtc-max8997.c
Normal file
552
drivers/rtc/rtc-max8997.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* RTC driver for Maxim MAX8997
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co.Ltd
|
||||
*
|
||||
* based on rtc-max8998.c
|
||||
*
|
||||
* 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 <linux/slab.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max8997-private.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
/* Module parameter for WTSR function control */
|
||||
static int wtsr_en = 1;
|
||||
module_param(wtsr_en, int, 0444);
|
||||
MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)");
|
||||
/* Module parameter for SMPL function control */
|
||||
static int smpl_en = 1;
|
||||
module_param(smpl_en, int, 0444);
|
||||
MODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)");
|
||||
|
||||
/* RTC Control Register */
|
||||
#define BCD_EN_SHIFT 0
|
||||
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
|
||||
#define MODEL24_SHIFT 1
|
||||
#define MODEL24_MASK (1 << MODEL24_SHIFT)
|
||||
/* RTC Update Register1 */
|
||||
#define RTC_UDR_SHIFT 0
|
||||
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
|
||||
/* WTSR and SMPL Register */
|
||||
#define WTSRT_SHIFT 0
|
||||
#define SMPLT_SHIFT 2
|
||||
#define WTSR_EN_SHIFT 6
|
||||
#define SMPL_EN_SHIFT 7
|
||||
#define WTSRT_MASK (3 << WTSRT_SHIFT)
|
||||
#define SMPLT_MASK (3 << SMPLT_SHIFT)
|
||||
#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT)
|
||||
#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT)
|
||||
/* RTC Hour register */
|
||||
#define HOUR_PM_SHIFT 6
|
||||
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
|
||||
/* RTC Alarm Enable */
|
||||
#define ALARM_ENABLE_SHIFT 7
|
||||
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
|
||||
|
||||
enum {
|
||||
RTC_SEC = 0,
|
||||
RTC_MIN,
|
||||
RTC_HOUR,
|
||||
RTC_WEEKDAY,
|
||||
RTC_MONTH,
|
||||
RTC_YEAR,
|
||||
RTC_DATE,
|
||||
RTC_NR_TIME
|
||||
};
|
||||
|
||||
struct max8997_rtc_info {
|
||||
struct device *dev;
|
||||
struct max8997_dev *max8997;
|
||||
struct i2c_client *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct mutex lock;
|
||||
int virq;
|
||||
int rtc_24hr_mode;
|
||||
};
|
||||
|
||||
static void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
|
||||
int rtc_24hr_mode)
|
||||
{
|
||||
tm->tm_sec = data[RTC_SEC] & 0x7f;
|
||||
tm->tm_min = data[RTC_MIN] & 0x7f;
|
||||
if (rtc_24hr_mode)
|
||||
tm->tm_hour = data[RTC_HOUR] & 0x1f;
|
||||
else {
|
||||
tm->tm_hour = data[RTC_HOUR] & 0x0f;
|
||||
if (data[RTC_HOUR] & HOUR_PM_MASK)
|
||||
tm->tm_hour += 12;
|
||||
}
|
||||
|
||||
tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1;
|
||||
tm->tm_mday = data[RTC_DATE] & 0x1f;
|
||||
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
|
||||
tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
|
||||
tm->tm_yday = 0;
|
||||
tm->tm_isdst = 0;
|
||||
}
|
||||
|
||||
static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
|
||||
{
|
||||
data[RTC_SEC] = tm->tm_sec;
|
||||
data[RTC_MIN] = tm->tm_min;
|
||||
data[RTC_HOUR] = tm->tm_hour;
|
||||
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
|
||||
data[RTC_DATE] = tm->tm_mday;
|
||||
data[RTC_MONTH] = tm->tm_mon + 1;
|
||||
data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
|
||||
|
||||
if (tm->tm_year < 100) {
|
||||
pr_warn("%s: MAX8997 RTC cannot handle the year %d."
|
||||
"Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1,
|
||||
RTC_UDR_MASK);
|
||||
if (ret < 0)
|
||||
dev_err(info->dev, "%s: fail to write update reg(%d)\n",
|
||||
__func__, ret);
|
||||
else {
|
||||
/* Minimum 16ms delay required before RTC update.
|
||||
* Otherwise, we may read and update based on out-of-date
|
||||
* value */
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct max8997_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
|
||||
mutex_unlock(&info->lock);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct max8997_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
ret = max8997_rtc_tm_to_data(tm, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max8997_rtc_set_update_reg(info);
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct max8997_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
u8 val;
|
||||
int i, ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
|
||||
__func__, __LINE__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
|
||||
|
||||
alrm->enabled = 0;
|
||||
for (i = 0; i < RTC_NR_TIME; i++) {
|
||||
if (data[i] & ALARM_ENABLE_MASK) {
|
||||
alrm->enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
alrm->pending = 0;
|
||||
ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
|
||||
__func__, __LINE__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val & (1 << 4)) /* RTCA1 */
|
||||
alrm->pending = 1;
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info)
|
||||
{
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret, i;
|
||||
|
||||
if (!mutex_is_locked(&info->lock))
|
||||
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
|
||||
|
||||
ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < RTC_NR_TIME; i++)
|
||||
data[i] &= ~ALARM_ENABLE_MASK;
|
||||
|
||||
ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max8997_rtc_set_update_reg(info);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_start_alarm(struct max8997_rtc_info *info)
|
||||
{
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
if (!mutex_is_locked(&info->lock))
|
||||
dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
|
||||
|
||||
ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
|
||||
if (data[RTC_MONTH] & 0xf)
|
||||
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
if (data[RTC_YEAR] & 0x7f)
|
||||
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
if (data[RTC_DATE] & 0x1f)
|
||||
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
|
||||
|
||||
ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max8997_rtc_set_update_reg(info);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
static int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct max8997_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[RTC_NR_TIME];
|
||||
int ret;
|
||||
|
||||
ret = max8997_rtc_tm_to_data(&alrm->time, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__,
|
||||
data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE],
|
||||
data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]);
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
ret = max8997_rtc_stop_alarm(info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
|
||||
data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = max8997_rtc_set_update_reg(info);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (alrm->enabled)
|
||||
ret = max8997_rtc_start_alarm(info);
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct max8997_rtc_info *info = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
if (enabled)
|
||||
ret = max8997_rtc_start_alarm(info);
|
||||
else
|
||||
ret = max8997_rtc_stop_alarm(info);
|
||||
mutex_unlock(&info->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t max8997_rtc_alarm_irq(int irq, void *data)
|
||||
{
|
||||
struct max8997_rtc_info *info = data;
|
||||
|
||||
dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
|
||||
|
||||
rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops max8997_rtc_ops = {
|
||||
.read_time = max8997_rtc_read_time,
|
||||
.set_time = max8997_rtc_set_time,
|
||||
.read_alarm = max8997_rtc_read_alarm,
|
||||
.set_alarm = max8997_rtc_set_alarm,
|
||||
.alarm_irq_enable = max8997_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable)
|
||||
{
|
||||
int ret;
|
||||
u8 val, mask;
|
||||
|
||||
if (!wtsr_en)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
|
||||
else
|
||||
val = 0;
|
||||
|
||||
mask = WTSR_EN_MASK | WTSRT_MASK;
|
||||
|
||||
dev_info(info->dev, "%s: %s WTSR\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
|
||||
__func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
max8997_rtc_set_update_reg(info);
|
||||
}
|
||||
|
||||
static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable)
|
||||
{
|
||||
int ret;
|
||||
u8 val, mask;
|
||||
|
||||
if (!smpl_en)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
|
||||
else
|
||||
val = 0;
|
||||
|
||||
mask = SMPL_EN_MASK | SMPLT_MASK;
|
||||
|
||||
dev_info(info->dev, "%s: %s SMPL\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
|
||||
__func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
max8997_rtc_set_update_reg(info);
|
||||
|
||||
val = 0;
|
||||
max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val);
|
||||
pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
|
||||
}
|
||||
|
||||
static int max8997_rtc_init_reg(struct max8997_rtc_info *info)
|
||||
{
|
||||
u8 data[2];
|
||||
int ret;
|
||||
|
||||
/* Set RTC control register : Binary mode, 24hour mdoe */
|
||||
data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||
data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
|
||||
|
||||
info->rtc_24hr_mode = 1;
|
||||
|
||||
ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data);
|
||||
if (ret < 0) {
|
||||
dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max8997_rtc_set_update_reg(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8997_rtc_info *info;
|
||||
int ret, virq;
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&info->lock);
|
||||
info->dev = &pdev->dev;
|
||||
info->max8997 = max8997;
|
||||
info->rtc = max8997->rtc;
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = max8997_rtc_init_reg(info);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
max8997_rtc_enable_wtsr(info, true);
|
||||
max8997_rtc_enable_smpl(info, true);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev,
|
||||
&max8997_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(info->rtc_dev)) {
|
||||
ret = PTR_ERR(info->rtc_dev);
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1);
|
||||
if (!virq) {
|
||||
dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n");
|
||||
goto err_out;
|
||||
}
|
||||
info->virq = virq;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
|
||||
max8997_rtc_alarm_irq, 0,
|
||||
"rtc-alarm0", info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
info->virq, ret);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_out:
|
||||
rtc_device_unregister(info->rtc_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8997_rtc_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
if (info)
|
||||
rtc_device_unregister(info->rtc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max8997_rtc_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct max8997_rtc_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
max8997_rtc_enable_wtsr(info, false);
|
||||
max8997_rtc_enable_smpl(info, false);
|
||||
}
|
||||
|
||||
static const struct platform_device_id rtc_id[] = {
|
||||
{ "max8997-rtc", 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver max8997_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "max8997-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max8997_rtc_probe,
|
||||
.remove = max8997_rtc_remove,
|
||||
.shutdown = max8997_rtc_shutdown,
|
||||
.id_table = rtc_id,
|
||||
};
|
||||
|
||||
module_platform_driver(max8997_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Maxim MAX8997 RTC driver");
|
||||
MODULE_AUTHOR("<ms925.kim@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/io.h>
|
||||
@@ -403,17 +404,19 @@ static int mpc5121_rtc_remove(struct platform_device *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id mpc5121_rtc_match[] = {
|
||||
{ .compatible = "fsl,mpc5121-rtc", },
|
||||
{ .compatible = "fsl,mpc5200-rtc", },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver mpc5121_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "mpc5121-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = mpc5121_rtc_match,
|
||||
.of_match_table = of_match_ptr(mpc5121_rtc_match),
|
||||
},
|
||||
.probe = mpc5121_rtc_probe,
|
||||
.remove = mpc5121_rtc_remove,
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */
|
||||
#define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */
|
||||
#define REG_CONTROL3_PM_MASK 0xe0
|
||||
#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */
|
||||
|
||||
#define REG_SECONDS 0x03
|
||||
#define REG_SECONDS_OS (1 << 7)
|
||||
@@ -250,9 +251,39 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
return pcf8523_start_rtc(client);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_DEV
|
||||
static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 value;
|
||||
int ret = 0, err;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_VL_READ:
|
||||
err = pcf8523_read(client, REG_CONTROL3, &value);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (value & REG_CONTROL3_BLF)
|
||||
ret = 1;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &ret, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define pcf8523_rtc_ioctl NULL
|
||||
#endif
|
||||
|
||||
static const struct rtc_class_ops pcf8523_rtc_ops = {
|
||||
.read_time = pcf8523_rtc_read_time,
|
||||
.set_time = pcf8523_rtc_set_time,
|
||||
.ioctl = pcf8523_rtc_ioctl,
|
||||
};
|
||||
|
||||
static int pcf8523_probe(struct i2c_client *client,
|
||||
|
@@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
__func__, err, data[0], data[1]);
|
||||
return -EIO;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
|
||||
unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
|
||||
|
||||
printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
|
||||
ctrl, new_ctrl);
|
||||
dev_warn(dev, "resetting control %02x -> %02x\n",
|
||||
ctrl, new_ctrl);
|
||||
|
||||
if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
|
||||
return err;
|
||||
|
@@ -384,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
goto out_no_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&adev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
out_no_irq:
|
||||
|
@@ -62,6 +62,10 @@
|
||||
#define RYxR_MONTH_S 5
|
||||
#define RYxR_MONTH_MASK (0xf << RYxR_MONTH_S)
|
||||
#define RYxR_DAY_MASK 0x1f
|
||||
#define RDxR_WOM_S 20
|
||||
#define RDxR_WOM_MASK (0x7 << RDxR_WOM_S)
|
||||
#define RDxR_DOW_S 17
|
||||
#define RDxR_DOW_MASK (0x7 << RDxR_DOW_S)
|
||||
#define RDxR_HOUR_S 12
|
||||
#define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S)
|
||||
#define RDxR_MIN_S 6
|
||||
@@ -91,6 +95,7 @@ struct pxa_rtc {
|
||||
spinlock_t lock; /* Protects this structure */
|
||||
};
|
||||
|
||||
|
||||
static u32 ryxr_calc(struct rtc_time *tm)
|
||||
{
|
||||
return ((tm->tm_year + 1900) << RYxR_YEAR_S)
|
||||
@@ -100,7 +105,10 @@ static u32 ryxr_calc(struct rtc_time *tm)
|
||||
|
||||
static u32 rdxr_calc(struct rtc_time *tm)
|
||||
{
|
||||
return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S)
|
||||
return ((((tm->tm_mday + 6) / 7) << RDxR_WOM_S) & RDxR_WOM_MASK)
|
||||
| (((tm->tm_wday + 1) << RDxR_DOW_S) & RDxR_DOW_MASK)
|
||||
| (tm->tm_hour << RDxR_HOUR_S)
|
||||
| (tm->tm_min << RDxR_MIN_S)
|
||||
| tm->tm_sec;
|
||||
}
|
||||
|
||||
@@ -109,6 +117,7 @@ static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm)
|
||||
tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900;
|
||||
tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
|
||||
tm->tm_mday = (rycr & RYxR_DAY_MASK);
|
||||
tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
|
||||
tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S;
|
||||
tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
|
||||
tm->tm_sec = rdcr & RDxR_SEC_MASK;
|
||||
@@ -300,8 +309,6 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops pxa_rtc_ops = {
|
||||
.open = pxa_rtc_open,
|
||||
.release = pxa_rtc_release,
|
||||
.read_time = pxa_rtc_read_time,
|
||||
.set_time = pxa_rtc_set_time,
|
||||
.read_alarm = pxa_rtc_read_alarm,
|
||||
@@ -341,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "No alarm IRQ resource defined\n");
|
||||
goto err_ress;
|
||||
}
|
||||
|
||||
pxa_rtc_open(dev);
|
||||
ret = -ENOMEM;
|
||||
pxa_rtc->base = ioremap(pxa_rtc->ress->start,
|
||||
resource_size(pxa_rtc->ress));
|
||||
@@ -387,6 +394,9 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
|
||||
|
||||
struct device *dev = &pdev->dev;
|
||||
pxa_rtc_release(dev);
|
||||
|
||||
rtc_device_unregister(pxa_rtc->rtc);
|
||||
|
||||
spin_lock_irq(&pxa_rtc->lock);
|
||||
@@ -444,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = {
|
||||
|
||||
static int __init pxa_rtc_init(void)
|
||||
{
|
||||
if (cpu_is_pxa27x() || cpu_is_pxa3xx())
|
||||
return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
|
||||
|
||||
return -ENODEV;
|
||||
return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
|
||||
}
|
||||
|
||||
static void __exit pxa_rtc_exit(void)
|
||||
|
@@ -39,6 +39,8 @@
|
||||
* 1.13 Nobuhiro Iwamatsu: Updata driver.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/rtc.h>
|
||||
@@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void)
|
||||
tm.tm_year = 2000 - 1900;
|
||||
|
||||
rs5c313_rtc_set_time(NULL, &tm);
|
||||
printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
|
||||
"1 Jan 2000\n");
|
||||
pr_err("invalid value, resetting to 1 Jan 2000\n");
|
||||
}
|
||||
RS5C313_CEDISABLE;
|
||||
ndelay(700); /* CE:L */
|
||||
|
@@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
buf &= ~RS5C_CTRL1_AALE;
|
||||
|
||||
if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
|
||||
printk(KERN_WARNING "%s: can't update alarm\n",
|
||||
rs5c->rtc->name);
|
||||
dev_warn(dev, "can't update alarm\n");
|
||||
status = -EIO;
|
||||
} else
|
||||
rs5c->regs[RS5C_REG_CTRL1] = buf;
|
||||
@@ -381,7 +380,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
addr = RS5C_ADDR(RS5C_REG_CTRL1);
|
||||
buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
|
||||
if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
|
||||
pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
|
||||
dev_dbg(dev, "can't disable alarm\n");
|
||||
return -EIO;
|
||||
}
|
||||
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
|
||||
@@ -395,7 +394,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
for (i = 0; i < sizeof(buf); i++) {
|
||||
addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
|
||||
if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
|
||||
pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
|
||||
dev_dbg(dev, "can't set alarm time\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
@@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
addr = RS5C_ADDR(RS5C_REG_CTRL1);
|
||||
buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
|
||||
if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
|
||||
printk(KERN_WARNING "%s: can't enable alarm\n",
|
||||
rs5c->rtc->name);
|
||||
dev_warn(dev, "can't enable alarm\n");
|
||||
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
|
||||
}
|
||||
|
||||
|
314
drivers/rtc/rtc-rx4581.c
Normal file
314
drivers/rtc/rtc-rx4581.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/* drivers/rtc/rtc-rx4581.c
|
||||
*
|
||||
* written by Torben Hohn <torbenh@linutronix.de>
|
||||
*
|
||||
* Based on:
|
||||
* drivers/rtc/rtc-max6902.c
|
||||
*
|
||||
* Copyright (C) 2006 8D Technologies inc.
|
||||
* Copyright (C) 2004 Compulab Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Driver for MAX6902 spi RTC
|
||||
*
|
||||
* and based on:
|
||||
* drivers/rtc/rtc-rx8581.c
|
||||
*
|
||||
* An I2C driver for the Epson RX8581 RTC
|
||||
*
|
||||
* Author: Martyn Welch <martyn.welch@ge.com>
|
||||
* Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC)
|
||||
* Copyright 2005-06 Tower Technologies
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define RX4581_REG_SC 0x00 /* Second in BCD */
|
||||
#define RX4581_REG_MN 0x01 /* Minute in BCD */
|
||||
#define RX4581_REG_HR 0x02 /* Hour in BCD */
|
||||
#define RX4581_REG_DW 0x03 /* Day of Week */
|
||||
#define RX4581_REG_DM 0x04 /* Day of Month in BCD */
|
||||
#define RX4581_REG_MO 0x05 /* Month in BCD */
|
||||
#define RX4581_REG_YR 0x06 /* Year in BCD */
|
||||
#define RX4581_REG_RAM 0x07 /* RAM */
|
||||
#define RX4581_REG_AMN 0x08 /* Alarm Min in BCD*/
|
||||
#define RX4581_REG_AHR 0x09 /* Alarm Hour in BCD */
|
||||
#define RX4581_REG_ADM 0x0A
|
||||
#define RX4581_REG_ADW 0x0A
|
||||
#define RX4581_REG_TMR0 0x0B
|
||||
#define RX4581_REG_TMR1 0x0C
|
||||
#define RX4581_REG_EXT 0x0D /* Extension Register */
|
||||
#define RX4581_REG_FLAG 0x0E /* Flag Register */
|
||||
#define RX4581_REG_CTRL 0x0F /* Control Register */
|
||||
|
||||
|
||||
/* Flag Register bit definitions */
|
||||
#define RX4581_FLAG_UF 0x20 /* Update */
|
||||
#define RX4581_FLAG_TF 0x10 /* Timer */
|
||||
#define RX4581_FLAG_AF 0x08 /* Alarm */
|
||||
#define RX4581_FLAG_VLF 0x02 /* Voltage Low */
|
||||
|
||||
/* Control Register bit definitions */
|
||||
#define RX4581_CTRL_UIE 0x20 /* Update Interrupt Enable */
|
||||
#define RX4581_CTRL_TIE 0x10 /* Timer Interrupt Enable */
|
||||
#define RX4581_CTRL_AIE 0x08 /* Alarm Interrupt Enable */
|
||||
#define RX4581_CTRL_STOP 0x02 /* STOP bit */
|
||||
#define RX4581_CTRL_RESET 0x01 /* RESET bit */
|
||||
|
||||
static int rx4581_set_reg(struct device *dev, unsigned char address,
|
||||
unsigned char data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[2];
|
||||
|
||||
/* high nibble must be '0' to write */
|
||||
buf[0] = address & 0x0f;
|
||||
buf[1] = data;
|
||||
|
||||
return spi_write_then_read(spi, buf, 2, NULL, 0);
|
||||
}
|
||||
|
||||
static int rx4581_get_reg(struct device *dev, unsigned char address,
|
||||
unsigned char *data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
/* Set MSB to indicate read */
|
||||
*data = address | 0x80;
|
||||
|
||||
return spi_write_then_read(spi, data, 1, data, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the routines that deal directly with the rx8581 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
*/
|
||||
static int rx4581_get_datetime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char date[7];
|
||||
unsigned char data;
|
||||
int err;
|
||||
|
||||
/* First we ensure that the "update flag" is not set, we read the
|
||||
* time and date then re-read the "update flag". If the update flag
|
||||
* has been set, we know that the time has changed during the read so
|
||||
* we repeat the whole process again.
|
||||
*/
|
||||
err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to read device flags\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
do {
|
||||
/* If update flag set, clear it */
|
||||
if (data & RX4581_FLAG_UF) {
|
||||
err = rx4581_set_reg(dev,
|
||||
RX4581_REG_FLAG, (data & ~RX4581_FLAG_UF));
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to write device "
|
||||
"flags\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now read time and date */
|
||||
date[0] = 0x80;
|
||||
err = spi_write_then_read(spi, date, 1, date, 7);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to read date\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Check flag register */
|
||||
err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to read device flags\n");
|
||||
return -EIO;
|
||||
}
|
||||
} while (data & RX4581_FLAG_UF);
|
||||
|
||||
if (data & RX4581_FLAG_VLF)
|
||||
dev_info(dev,
|
||||
"low voltage detected, date/time is not reliable.\n");
|
||||
|
||||
dev_dbg(dev,
|
||||
"%s: raw data is sec=%02x, min=%02x, hr=%02x, "
|
||||
"wday=%02x, mday=%02x, mon=%02x, year=%02x\n",
|
||||
__func__,
|
||||
date[0], date[1], date[2], date[3], date[4], date[5], date[6]);
|
||||
|
||||
tm->tm_sec = bcd2bin(date[RX4581_REG_SC] & 0x7F);
|
||||
tm->tm_min = bcd2bin(date[RX4581_REG_MN] & 0x7F);
|
||||
tm->tm_hour = bcd2bin(date[RX4581_REG_HR] & 0x3F); /* rtc hr 0-23 */
|
||||
tm->tm_wday = ilog2(date[RX4581_REG_DW] & 0x7F);
|
||||
tm->tm_mday = bcd2bin(date[RX4581_REG_DM] & 0x3F);
|
||||
tm->tm_mon = bcd2bin(date[RX4581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(date[RX4581_REG_YR]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
|
||||
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
err = rtc_valid_tm(tm);
|
||||
if (err < 0)
|
||||
dev_err(dev, "retrieved date/time is not valid.\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rx4581_set_datetime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int err;
|
||||
unsigned char buf[8], data;
|
||||
|
||||
dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
buf[0] = 0x00;
|
||||
/* hours, minutes and seconds */
|
||||
buf[RX4581_REG_SC+1] = bin2bcd(tm->tm_sec);
|
||||
buf[RX4581_REG_MN+1] = bin2bcd(tm->tm_min);
|
||||
buf[RX4581_REG_HR+1] = bin2bcd(tm->tm_hour);
|
||||
|
||||
buf[RX4581_REG_DM+1] = bin2bcd(tm->tm_mday);
|
||||
|
||||
/* month, 1 - 12 */
|
||||
buf[RX4581_REG_MO+1] = bin2bcd(tm->tm_mon + 1);
|
||||
|
||||
/* year and century */
|
||||
buf[RX4581_REG_YR+1] = bin2bcd(tm->tm_year % 100);
|
||||
buf[RX4581_REG_DW+1] = (0x1 << tm->tm_wday);
|
||||
|
||||
/* Stop the clock */
|
||||
err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to read control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = rx4581_set_reg(dev, RX4581_REG_CTRL,
|
||||
(data | RX4581_CTRL_STOP));
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to write control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* write register's data */
|
||||
err = spi_write_then_read(spi, buf, 8, NULL, 0);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to write to date registers\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* get VLF and clear it */
|
||||
err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to read flag register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = rx4581_set_reg(dev, RX4581_REG_FLAG,
|
||||
(data & ~(RX4581_FLAG_VLF)));
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to write flag register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Restart the clock */
|
||||
err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data);
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to read control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = rx4581_set_reg(dev, RX4581_REG_CTRL,
|
||||
(data & ~(RX4581_CTRL_STOP)));
|
||||
if (err != 0) {
|
||||
dev_err(dev, "Unable to write control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rx4581_rtc_ops = {
|
||||
.read_time = rx4581_get_datetime,
|
||||
.set_time = rx4581_set_datetime,
|
||||
};
|
||||
|
||||
static int rx4581_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
unsigned char tmp;
|
||||
int res;
|
||||
|
||||
res = rx4581_get_reg(&spi->dev, RX4581_REG_SC, &tmp);
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
rtc = rtc_device_register("rx4581",
|
||||
&spi->dev, &rx4581_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
dev_set_drvdata(&spi->dev, rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx4581_remove(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
|
||||
|
||||
rtc_device_unregister(rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id rx4581_id[] = {
|
||||
{ "rx4581", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, rx4581_id);
|
||||
|
||||
static struct spi_driver rx4581_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-rx4581",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rx4581_probe,
|
||||
.remove = rx4581_remove,
|
||||
.id_table = rx4581_id,
|
||||
};
|
||||
|
||||
module_spi_driver(rx4581_driver);
|
||||
|
||||
MODULE_DESCRIPTION("rx4581 spi RTC driver");
|
||||
MODULE_AUTHOR("Torben Hohn");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("spi:rtc-rx4581");
|
@@ -115,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
pr_debug("%s: aie=%d\n", __func__, enabled);
|
||||
dev_dbg(dev, "%s: aie=%d\n", __func__, enabled);
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
|
||||
@@ -203,7 +203,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||
|
||||
rtc_tm->tm_year += 100;
|
||||
|
||||
pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
|
||||
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
|
||||
|
||||
@@ -218,7 +218,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
void __iomem *base = s3c_rtc_base;
|
||||
int year = tm->tm_year - 100;
|
||||
|
||||
pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
@@ -259,7 +259,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
|
||||
|
||||
pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
alm_en,
|
||||
1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
|
||||
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
|
||||
@@ -310,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
unsigned int alrm_en;
|
||||
|
||||
clk_enable(rtc_clk);
|
||||
pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
|
||||
alrm->enabled,
|
||||
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
@@ -333,7 +333,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
|
||||
}
|
||||
|
||||
pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
|
||||
dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
|
||||
|
||||
writeb(alrm_en, base + S3C2410_RTCALM);
|
||||
|
||||
@@ -459,7 +459,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
int tmp;
|
||||
|
||||
pr_debug("%s: probe=%p\n", __func__, pdev);
|
||||
dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev);
|
||||
|
||||
/* find the IRQs */
|
||||
|
||||
@@ -475,7 +475,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
return s3c_rtc_alarmno;
|
||||
}
|
||||
|
||||
pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
|
||||
dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
|
||||
s3c_rtc_tickno, s3c_rtc_alarmno);
|
||||
|
||||
/* get the memory region */
|
||||
@@ -504,7 +504,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
s3c_rtc_enable(pdev, 1);
|
||||
|
||||
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
|
||||
dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
|
||||
readw(s3c_rtc_base + S3C2410_RTCCON));
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
@@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev)
|
||||
struct rtc_device *rtc = info->rtc;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
goto fail_clk;
|
||||
ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
|
||||
@@ -130,7 +127,6 @@ static int sa1100_rtc_open(struct device *dev)
|
||||
free_irq(info->irq_1hz, dev);
|
||||
fail_ui:
|
||||
clk_disable_unprepare(info->clk);
|
||||
fail_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev)
|
||||
|
||||
free_irq(info->irq_alarm, dev);
|
||||
free_irq(info->irq_1hz, dev);
|
||||
clk_disable_unprepare(info->clk);
|
||||
}
|
||||
|
||||
static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
@@ -253,6 +248,9 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&info->lock);
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret)
|
||||
goto err_enable_clk;
|
||||
/*
|
||||
* According to the manual we should be able to let RTTR be zero
|
||||
* and then a default diviser for a 32.768KHz clock is used.
|
||||
@@ -305,6 +303,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
err_dev:
|
||||
clk_disable_unprepare(info->clk);
|
||||
err_enable_clk:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
clk_put(info->clk);
|
||||
err_clk:
|
||||
@@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
|
||||
|
||||
if (info) {
|
||||
rtc_device_unregister(info->rtc);
|
||||
clk_disable_unprepare(info->clk);
|
||||
clk_put(info->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(info);
|
||||
@@ -349,12 +350,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id sa1100_rtc_dt_ids[] = {
|
||||
{ .compatible = "mrvl,sa1100-rtc", },
|
||||
{ .compatible = "mrvl,mmp-rtc", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver sa1100_rtc_driver = {
|
||||
.probe = sa1100_rtc_probe,
|
||||
@@ -364,7 +367,7 @@ static struct platform_driver sa1100_rtc_driver = {
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &sa1100_rtc_pm_ops,
|
||||
#endif
|
||||
.of_match_table = sa1100_rtc_dt_ids,
|
||||
.of_match_table = of_match_ptr(sa1100_rtc_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -338,7 +338,7 @@ static struct platform_driver snvs_rtc_driver = {
|
||||
.name = "snvs_rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snvs_rtc_pm_ops,
|
||||
.of_match_table = snvs_dt_ids,
|
||||
.of_match_table = of_match_ptr(snvs_dt_ids),
|
||||
},
|
||||
.probe = snvs_rtc_probe,
|
||||
.remove = snvs_rtc_remove,
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <mach/common.h>
|
||||
|
||||
@@ -280,7 +281,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {
|
||||
.driver = {
|
||||
.name = "stmp3xxx-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = rtc_dt_ids,
|
||||
.of_match_table = of_match_ptr(rtc_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -3,6 +3,8 @@
|
||||
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -26,10 +28,10 @@ retry:
|
||||
udelay(100);
|
||||
goto retry;
|
||||
}
|
||||
printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
|
||||
pr_warn("tod_get() timed out.\n");
|
||||
return 0;
|
||||
}
|
||||
printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
|
||||
pr_warn("tod_get() not supported.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -53,10 +55,10 @@ retry:
|
||||
udelay(100);
|
||||
goto retry;
|
||||
}
|
||||
printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
|
||||
pr_warn("tod_set() timed out.\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
|
||||
pr_warn("tod_set() not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
@@ -282,7 +282,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq,
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
tps6586x_rtc_irq,
|
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME,
|
||||
dev_name(&pdev->dev), rtc);
|
||||
if (ret < 0) {
|
||||
@@ -311,7 +312,6 @@ static int tps6586x_rtc_remove(struct platform_device *pdev)
|
||||
tps6586x_update(tps_dev, RTC_CTRL, 0,
|
||||
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
|
||||
rtc_device_unregister(rtc->rtc);
|
||||
free_irq(rtc->irq, rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -22,13 +22,13 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/tps65910.h>
|
||||
|
||||
struct tps65910_rtc {
|
||||
struct rtc_device *rtc;
|
||||
/* To store the list of enabled interrupts */
|
||||
u32 irqstat;
|
||||
int irq;
|
||||
};
|
||||
|
||||
/* Total number of RTC registers needed to set time*/
|
||||
@@ -267,13 +267,14 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
|
||||
tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
|
||||
dev_name(&pdev->dev), &pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "IRQ is not free.\n");
|
||||
return ret;
|
||||
}
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
tps_rtc->irq = irq;
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
|
||||
tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
|
||||
&tps65910_rtc_ops, THIS_MODULE);
|
||||
@@ -304,49 +305,36 @@ static int tps65910_rtc_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int tps65910_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct tps65910 *tps = dev_get_drvdata(dev->parent);
|
||||
u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM;
|
||||
int ret;
|
||||
struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
|
||||
|
||||
/* Store current list of enabled interrupts*/
|
||||
ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS,
|
||||
&tps->rtc->irqstat);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable RTC ALARM interrupt only */
|
||||
return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm);
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(tps_rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps65910_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct tps65910 *tps = dev_get_drvdata(dev->parent);
|
||||
struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
|
||||
|
||||
/* Restore list of enabled interrupts before suspend */
|
||||
return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS,
|
||||
tps->rtc->irqstat);
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(tps_rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops tps65910_rtc_pm_ops = {
|
||||
.suspend = tps65910_rtc_suspend,
|
||||
.resume = tps65910_rtc_resume,
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&tps65910_rtc_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver tps65910_rtc_driver = {
|
||||
.probe = tps65910_rtc_probe,
|
||||
.remove = tps65910_rtc_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tps65910-rtc",
|
||||
.pm = DEV_PM_OPS,
|
||||
.pm = &tps65910_rtc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
349
drivers/rtc/rtc-tps80031.c
Normal file
349
drivers/rtc/rtc-tps80031.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver
|
||||
*
|
||||
* RTC driver for TI TPS80031/TPS80032 Fully Integrated
|
||||
* Power Management with Power Path and Battery Charger
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA Corporation.
|
||||
*
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
|
||||
* whether express or implied; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/tps80031.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define ENABLE_ALARM_INT 0x08
|
||||
#define ALARM_INT_STATUS 0x40
|
||||
|
||||
/**
|
||||
* Setting bit to 1 in STOP_RTC will run the RTC and
|
||||
* setting this bit to 0 will freeze RTC.
|
||||
*/
|
||||
#define STOP_RTC 0x1
|
||||
|
||||
/* Power on reset Values of RTC registers */
|
||||
#define TPS80031_RTC_POR_YEAR 0
|
||||
#define TPS80031_RTC_POR_MONTH 1
|
||||
#define TPS80031_RTC_POR_DAY 1
|
||||
|
||||
/* Numbers of registers for time and alarms */
|
||||
#define TPS80031_RTC_TIME_NUM_REGS 7
|
||||
#define TPS80031_RTC_ALARM_NUM_REGS 6
|
||||
|
||||
/**
|
||||
* PMU RTC have only 2 nibbles to store year information, so using an
|
||||
* offset of 100 to set the base year as 2000 for our driver.
|
||||
*/
|
||||
#define RTC_YEAR_OFFSET 100
|
||||
|
||||
struct tps80031_rtc {
|
||||
struct rtc_device *rtc;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 buff[TPS80031_RTC_TIME_NUM_REGS];
|
||||
int ret;
|
||||
|
||||
ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(buff[0]);
|
||||
tm->tm_min = bcd2bin(buff[1]);
|
||||
tm->tm_hour = bcd2bin(buff[2]);
|
||||
tm->tm_mday = bcd2bin(buff[3]);
|
||||
tm->tm_mon = bcd2bin(buff[4]) - 1;
|
||||
tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
|
||||
tm->tm_wday = bcd2bin(buff[6]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 buff[7];
|
||||
int ret;
|
||||
|
||||
buff[0] = bin2bcd(tm->tm_sec);
|
||||
buff[1] = bin2bcd(tm->tm_min);
|
||||
buff[2] = bin2bcd(tm->tm_hour);
|
||||
buff[3] = bin2bcd(tm->tm_mday);
|
||||
buff[4] = bin2bcd(tm->tm_mon + 1);
|
||||
buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET);
|
||||
buff[6] = bin2bcd(tm->tm_wday);
|
||||
|
||||
/* Stop RTC while updating the RTC time registers */
|
||||
ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_SECONDS_REG,
|
||||
TPS80031_RTC_TIME_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0)
|
||||
dev_err(dev->parent, "Start RTC failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (enable)
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
|
||||
else
|
||||
ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
u8 buff[TPS80031_RTC_ALARM_NUM_REGS];
|
||||
int ret;
|
||||
|
||||
buff[0] = bin2bcd(alrm->time.tm_sec);
|
||||
buff[1] = bin2bcd(alrm->time.tm_min);
|
||||
buff[2] = bin2bcd(alrm->time.tm_hour);
|
||||
buff[3] = bin2bcd(alrm->time.tm_mday);
|
||||
buff[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET);
|
||||
ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_ALARM_SECONDS_REG,
|
||||
TPS80031_RTC_ALARM_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
}
|
||||
|
||||
static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
u8 buff[6];
|
||||
int ret;
|
||||
|
||||
ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_ALARM_SECONDS_REG,
|
||||
TPS80031_RTC_ALARM_NUM_REGS, buff);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->parent,
|
||||
"reading RTC_ALARM failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
alrm->time.tm_sec = bcd2bin(buff[0]);
|
||||
alrm->time.tm_min = bcd2bin(buff[1]);
|
||||
alrm->time.tm_hour = bcd2bin(buff[2]);
|
||||
alrm->time.tm_mday = bcd2bin(buff[3]);
|
||||
alrm->time.tm_mon = bcd2bin(buff[4]) - 1;
|
||||
alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc)
|
||||
{
|
||||
int ret;
|
||||
u8 buf;
|
||||
|
||||
/**
|
||||
* As per datasheet, A dummy read of this RTC_STATUS_REG register
|
||||
* is necessary before each I2C read in order to update the status
|
||||
* register value.
|
||||
*/
|
||||
ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_STATUS_REG, &buf);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear Alarm status bits.*/
|
||||
ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "clear Alarm INT failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t tps80031_rtc_irq(int irq, void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clear_alarm_int_status(dev, rtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops tps80031_rtc_ops = {
|
||||
.read_time = tps80031_rtc_read_time,
|
||||
.set_time = tps80031_rtc_set_time,
|
||||
.set_alarm = tps80031_rtc_set_alarm,
|
||||
.read_alarm = tps80031_rtc_read_alarm,
|
||||
.alarm_irq_enable = tps80031_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int tps80031_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps80031_rtc *rtc;
|
||||
struct rtc_time tm;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* Start RTC */
|
||||
ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1,
|
||||
TPS80031_RTC_CTRL_REG, STOP_RTC);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If RTC have POR values, set time 01:01:2000 */
|
||||
tps80031_rtc_read_time(&pdev->dev, &tm);
|
||||
if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) &&
|
||||
(tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) &&
|
||||
(tm.tm_mday == TPS80031_RTC_POR_DAY)) {
|
||||
tm.tm_year = 2000;
|
||||
tm.tm_mday = 1;
|
||||
tm.tm_mon = 1;
|
||||
ret = tps80031_rtc_set_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"RTC set time failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear alarm intretupt status if it is there */
|
||||
ret = clear_alarm_int_status(&pdev->dev, rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
|
||||
&tps80031_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
tps80031_rtc_irq,
|
||||
IRQF_ONESHOT | IRQF_EARLY_RESUME,
|
||||
dev_name(&pdev->dev), rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",
|
||||
rtc->irq, ret);
|
||||
rtc_device_unregister(rtc->rtc);
|
||||
return ret;
|
||||
}
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps80031_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(rtc->rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tps80031_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(rtc->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps80031_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct tps80031_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(rtc->irq);
|
||||
return 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops tps80031_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver tps80031_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "tps80031-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &tps80031_pm_ops,
|
||||
},
|
||||
.probe = tps80031_rtc_probe,
|
||||
.remove = tps80031_rtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(tps80031_rtc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:tps80031-rtc");
|
||||
MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver");
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -27,6 +27,7 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/i2c/twl.h>
|
||||
|
||||
@@ -588,11 +589,14 @@ static int twl_rtc_resume(struct platform_device *pdev)
|
||||
#define twl_rtc_resume NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id twl_rtc_of_match[] = {
|
||||
{.compatible = "ti,twl4030-rtc", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
|
||||
#endif
|
||||
|
||||
MODULE_ALIAS("platform:twl_rtc");
|
||||
|
||||
static struct platform_driver twl4030rtc_driver = {
|
||||
@@ -604,7 +608,7 @@ static struct platform_driver twl4030rtc_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "twl_rtc",
|
||||
.of_match_table = twl_rtc_of_match,
|
||||
.of_match_table = of_match_ptr(twl_rtc_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -352,7 +352,7 @@ static int rtc_probe(struct platform_device *pdev)
|
||||
disable_irq(aie_irq);
|
||||
disable_irq(pie_irq);
|
||||
|
||||
printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
|
||||
dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n");
|
||||
|
||||
return 0;
|
||||
|
||||
|
@@ -231,20 +231,21 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
|
||||
resource_size(vt8500_rtc->res),
|
||||
"vt8500-rtc");
|
||||
vt8500_rtc->res = devm_request_mem_region(&pdev->dev,
|
||||
vt8500_rtc->res->start,
|
||||
resource_size(vt8500_rtc->res),
|
||||
"vt8500-rtc");
|
||||
if (vt8500_rtc->res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to request I/O memory\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
|
||||
vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start,
|
||||
resource_size(vt8500_rtc->res));
|
||||
if (!vt8500_rtc->regbase) {
|
||||
dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
|
||||
ret = -EBUSY;
|
||||
goto err_release;
|
||||
goto err_return;
|
||||
}
|
||||
|
||||
/* Enable RTC and set it to 24-hour mode */
|
||||
@@ -257,11 +258,11 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
|
||||
ret = PTR_ERR(vt8500_rtc->rtc);
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register RTC device -> %d\n", ret);
|
||||
goto err_unmap;
|
||||
goto err_return;
|
||||
}
|
||||
|
||||
ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
|
||||
"rtc alarm", vt8500_rtc);
|
||||
ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm,
|
||||
vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "can't get irq %i, err %d\n",
|
||||
vt8500_rtc->irq_alarm, ret);
|
||||
@@ -272,11 +273,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
err_unreg:
|
||||
rtc_device_unregister(vt8500_rtc->rtc);
|
||||
err_unmap:
|
||||
iounmap(vt8500_rtc->regbase);
|
||||
err_release:
|
||||
release_mem_region(vt8500_rtc->res->start,
|
||||
resource_size(vt8500_rtc->res));
|
||||
err_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -284,15 +281,10 @@ static int vt8500_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
|
||||
|
||||
rtc_device_unregister(vt8500_rtc->rtc);
|
||||
|
||||
/* Disable alarm matching */
|
||||
writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
|
||||
iounmap(vt8500_rtc->regbase);
|
||||
release_mem_region(vt8500_rtc->res->start,
|
||||
resource_size(vt8500_rtc->res));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
|
@@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
|
||||
IRQF_TRIGGER_RISING, "RTC alarm",
|
||||
wm831x_rtc);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
|
||||
wm831x_alm_irq,
|
||||
IRQF_TRIGGER_RISING, "RTC alarm",
|
||||
wm831x_rtc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
|
||||
alm_irq, ret);
|
||||
@@ -462,9 +463,7 @@ err:
|
||||
static int wm831x_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev);
|
||||
int alm_irq = platform_get_irq_byname(pdev, "ALM");
|
||||
|
||||
free_irq(alm_irq, wm831x_rtc);
|
||||
rtc_device_unregister(wm831x_rtc->rtc);
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user