12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 25f119f29SThomas Bogendoerfer /* 35f119f29SThomas Bogendoerfer * DS1286 Real Time Clock interface for Linux 45f119f29SThomas Bogendoerfer * 55f119f29SThomas Bogendoerfer * Copyright (C) 1998, 1999, 2000 Ralf Baechle 65f119f29SThomas Bogendoerfer * Copyright (C) 2008 Thomas Bogendoerfer 75f119f29SThomas Bogendoerfer * 85f119f29SThomas Bogendoerfer * Based on code written by Paul Gortmaker. 95f119f29SThomas Bogendoerfer */ 105f119f29SThomas Bogendoerfer 115f119f29SThomas Bogendoerfer #include <linux/module.h> 125f119f29SThomas Bogendoerfer #include <linux/rtc.h> 135f119f29SThomas Bogendoerfer #include <linux/platform_device.h> 145f119f29SThomas Bogendoerfer #include <linux/bcd.h> 15d4a5f6d7SAlexandre Belloni #include <linux/rtc/ds1286.h> 16d7a6119fSGeert Uytterhoeven #include <linux/io.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 185f119f29SThomas Bogendoerfer 195f119f29SThomas Bogendoerfer struct ds1286_priv { 205f119f29SThomas Bogendoerfer struct rtc_device *rtc; 215f119f29SThomas Bogendoerfer u32 __iomem *rtcregs; 225f119f29SThomas Bogendoerfer spinlock_t lock; 235f119f29SThomas Bogendoerfer }; 245f119f29SThomas Bogendoerfer 255f119f29SThomas Bogendoerfer static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg) 265f119f29SThomas Bogendoerfer { 275f119f29SThomas Bogendoerfer return __raw_readl(&priv->rtcregs[reg]) & 0xff; 285f119f29SThomas Bogendoerfer } 295f119f29SThomas Bogendoerfer 305f119f29SThomas Bogendoerfer static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg) 315f119f29SThomas Bogendoerfer { 325f119f29SThomas Bogendoerfer __raw_writel(data, &priv->rtcregs[reg]); 335f119f29SThomas Bogendoerfer } 345f119f29SThomas Bogendoerfer 3516380c15SJohn Stultz 3616380c15SJohn Stultz static int ds1286_alarm_irq_enable(struct device *dev, unsigned int enabled) 3716380c15SJohn Stultz { 3816380c15SJohn Stultz struct ds1286_priv *priv = dev_get_drvdata(dev); 3916380c15SJohn Stultz unsigned long flags; 4016380c15SJohn Stultz unsigned char val; 4116380c15SJohn Stultz 4216380c15SJohn Stultz /* Allow or mask alarm interrupts */ 4316380c15SJohn Stultz spin_lock_irqsave(&priv->lock, flags); 4416380c15SJohn Stultz val = ds1286_rtc_read(priv, RTC_CMD); 4516380c15SJohn Stultz if (enabled) 4616380c15SJohn Stultz val &= ~RTC_TDM; 4716380c15SJohn Stultz else 4816380c15SJohn Stultz val |= RTC_TDM; 4916380c15SJohn Stultz ds1286_rtc_write(priv, val, RTC_CMD); 5016380c15SJohn Stultz spin_unlock_irqrestore(&priv->lock, flags); 5116380c15SJohn Stultz 5216380c15SJohn Stultz return 0; 5316380c15SJohn Stultz } 5416380c15SJohn Stultz 555f119f29SThomas Bogendoerfer #ifdef CONFIG_RTC_INTF_DEV 565f119f29SThomas Bogendoerfer 575f119f29SThomas Bogendoerfer static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 585f119f29SThomas Bogendoerfer { 595f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 605f119f29SThomas Bogendoerfer unsigned long flags; 615f119f29SThomas Bogendoerfer unsigned char val; 625f119f29SThomas Bogendoerfer 635f119f29SThomas Bogendoerfer switch (cmd) { 645f119f29SThomas Bogendoerfer case RTC_WIE_OFF: 655f119f29SThomas Bogendoerfer /* Mask watchdog int. enab. bit */ 665f119f29SThomas Bogendoerfer spin_lock_irqsave(&priv->lock, flags); 675f119f29SThomas Bogendoerfer val = ds1286_rtc_read(priv, RTC_CMD); 685f119f29SThomas Bogendoerfer val |= RTC_WAM; 695f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, val, RTC_CMD); 705f119f29SThomas Bogendoerfer spin_unlock_irqrestore(&priv->lock, flags); 715f119f29SThomas Bogendoerfer break; 725f119f29SThomas Bogendoerfer case RTC_WIE_ON: 735f119f29SThomas Bogendoerfer /* Allow watchdog interrupts. */ 745f119f29SThomas Bogendoerfer spin_lock_irqsave(&priv->lock, flags); 755f119f29SThomas Bogendoerfer val = ds1286_rtc_read(priv, RTC_CMD); 765f119f29SThomas Bogendoerfer val &= ~RTC_WAM; 775f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, val, RTC_CMD); 785f119f29SThomas Bogendoerfer spin_unlock_irqrestore(&priv->lock, flags); 795f119f29SThomas Bogendoerfer break; 805f119f29SThomas Bogendoerfer default: 815f119f29SThomas Bogendoerfer return -ENOIOCTLCMD; 825f119f29SThomas Bogendoerfer } 835f119f29SThomas Bogendoerfer return 0; 845f119f29SThomas Bogendoerfer } 855f119f29SThomas Bogendoerfer 865f119f29SThomas Bogendoerfer #else 875f119f29SThomas Bogendoerfer #define ds1286_ioctl NULL 885f119f29SThomas Bogendoerfer #endif 895f119f29SThomas Bogendoerfer 905f119f29SThomas Bogendoerfer #ifdef CONFIG_PROC_FS 915f119f29SThomas Bogendoerfer 925f119f29SThomas Bogendoerfer static int ds1286_proc(struct device *dev, struct seq_file *seq) 935f119f29SThomas Bogendoerfer { 945f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 955f119f29SThomas Bogendoerfer unsigned char month, cmd, amode; 965f119f29SThomas Bogendoerfer const char *s; 975f119f29SThomas Bogendoerfer 985f119f29SThomas Bogendoerfer month = ds1286_rtc_read(priv, RTC_MONTH); 995f119f29SThomas Bogendoerfer seq_printf(seq, 1005f119f29SThomas Bogendoerfer "oscillator\t: %s\n" 1015f119f29SThomas Bogendoerfer "square_wave\t: %s\n", 1025f119f29SThomas Bogendoerfer (month & RTC_EOSC) ? "disabled" : "enabled", 1035f119f29SThomas Bogendoerfer (month & RTC_ESQW) ? "disabled" : "enabled"); 1045f119f29SThomas Bogendoerfer 1055f119f29SThomas Bogendoerfer amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) | 1065f119f29SThomas Bogendoerfer ((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) | 1075f119f29SThomas Bogendoerfer ((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7); 1085f119f29SThomas Bogendoerfer switch (amode) { 1095f119f29SThomas Bogendoerfer case 7: 1105f119f29SThomas Bogendoerfer s = "each minute"; 1115f119f29SThomas Bogendoerfer break; 1125f119f29SThomas Bogendoerfer case 3: 1135f119f29SThomas Bogendoerfer s = "minutes match"; 1145f119f29SThomas Bogendoerfer break; 1155f119f29SThomas Bogendoerfer case 1: 1165f119f29SThomas Bogendoerfer s = "hours and minutes match"; 1175f119f29SThomas Bogendoerfer break; 1185f119f29SThomas Bogendoerfer case 0: 1195f119f29SThomas Bogendoerfer s = "days, hours and minutes match"; 1205f119f29SThomas Bogendoerfer break; 1215f119f29SThomas Bogendoerfer default: 1225f119f29SThomas Bogendoerfer s = "invalid"; 1235f119f29SThomas Bogendoerfer break; 1245f119f29SThomas Bogendoerfer } 1255f119f29SThomas Bogendoerfer seq_printf(seq, "alarm_mode\t: %s\n", s); 1265f119f29SThomas Bogendoerfer 1275f119f29SThomas Bogendoerfer cmd = ds1286_rtc_read(priv, RTC_CMD); 1285f119f29SThomas Bogendoerfer seq_printf(seq, 1295f119f29SThomas Bogendoerfer "alarm_enable\t: %s\n" 1305f119f29SThomas Bogendoerfer "wdog_alarm\t: %s\n" 1315f119f29SThomas Bogendoerfer "alarm_mask\t: %s\n" 1325f119f29SThomas Bogendoerfer "wdog_alarm_mask\t: %s\n" 1335f119f29SThomas Bogendoerfer "interrupt_mode\t: %s\n" 1345f119f29SThomas Bogendoerfer "INTB_mode\t: %s_active\n" 1355f119f29SThomas Bogendoerfer "interrupt_pins\t: %s\n", 1365f119f29SThomas Bogendoerfer (cmd & RTC_TDF) ? "yes" : "no", 1375f119f29SThomas Bogendoerfer (cmd & RTC_WAF) ? "yes" : "no", 1385f119f29SThomas Bogendoerfer (cmd & RTC_TDM) ? "disabled" : "enabled", 1395f119f29SThomas Bogendoerfer (cmd & RTC_WAM) ? "disabled" : "enabled", 1405f119f29SThomas Bogendoerfer (cmd & RTC_PU_LVL) ? "pulse" : "level", 1415f119f29SThomas Bogendoerfer (cmd & RTC_IBH_LO) ? "low" : "high", 1425f119f29SThomas Bogendoerfer (cmd & RTC_IPSW) ? "unswapped" : "swapped"); 1435f119f29SThomas Bogendoerfer return 0; 1445f119f29SThomas Bogendoerfer } 1455f119f29SThomas Bogendoerfer 1465f119f29SThomas Bogendoerfer #else 1475f119f29SThomas Bogendoerfer #define ds1286_proc NULL 1485f119f29SThomas Bogendoerfer #endif 1495f119f29SThomas Bogendoerfer 1505f119f29SThomas Bogendoerfer static int ds1286_read_time(struct device *dev, struct rtc_time *tm) 1515f119f29SThomas Bogendoerfer { 1525f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 1535f119f29SThomas Bogendoerfer unsigned char save_control; 1545f119f29SThomas Bogendoerfer unsigned long flags; 1555f119f29SThomas Bogendoerfer unsigned long uip_watchdog = jiffies; 1565f119f29SThomas Bogendoerfer 1575f119f29SThomas Bogendoerfer /* 1585f119f29SThomas Bogendoerfer * read RTC once any update in progress is done. The update 1595f119f29SThomas Bogendoerfer * can take just over 2ms. We wait 10 to 20ms. There is no need to 1605f119f29SThomas Bogendoerfer * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. 1615f119f29SThomas Bogendoerfer * If you need to know *exactly* when a second has started, enable 1625f119f29SThomas Bogendoerfer * periodic update complete interrupts, (via ioctl) and then 1635f119f29SThomas Bogendoerfer * immediately read /dev/rtc which will block until you get the IRQ. 1645f119f29SThomas Bogendoerfer * Once the read clears, read the RTC time (again via ioctl). Easy. 1655f119f29SThomas Bogendoerfer */ 1665f119f29SThomas Bogendoerfer 1675f119f29SThomas Bogendoerfer if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE) 1685f119f29SThomas Bogendoerfer while (time_before(jiffies, uip_watchdog + 2*HZ/100)) 1695f119f29SThomas Bogendoerfer barrier(); 1705f119f29SThomas Bogendoerfer 1715f119f29SThomas Bogendoerfer /* 1725f119f29SThomas Bogendoerfer * Only the values that we read from the RTC are set. We leave 1735f119f29SThomas Bogendoerfer * tm_wday, tm_yday and tm_isdst untouched. Even though the 1745f119f29SThomas Bogendoerfer * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated 1755f119f29SThomas Bogendoerfer * by the RTC when initially set to a non-zero value. 1765f119f29SThomas Bogendoerfer */ 1775f119f29SThomas Bogendoerfer spin_lock_irqsave(&priv->lock, flags); 1785f119f29SThomas Bogendoerfer save_control = ds1286_rtc_read(priv, RTC_CMD); 1795f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD); 1805f119f29SThomas Bogendoerfer 1815f119f29SThomas Bogendoerfer tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS); 1825f119f29SThomas Bogendoerfer tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES); 1835f119f29SThomas Bogendoerfer tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f; 1845f119f29SThomas Bogendoerfer tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE); 1855f119f29SThomas Bogendoerfer tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f; 1865f119f29SThomas Bogendoerfer tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR); 1875f119f29SThomas Bogendoerfer 1885f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, save_control, RTC_CMD); 1895f119f29SThomas Bogendoerfer spin_unlock_irqrestore(&priv->lock, flags); 1905f119f29SThomas Bogendoerfer 1915f119f29SThomas Bogendoerfer tm->tm_sec = bcd2bin(tm->tm_sec); 1925f119f29SThomas Bogendoerfer tm->tm_min = bcd2bin(tm->tm_min); 1935f119f29SThomas Bogendoerfer tm->tm_hour = bcd2bin(tm->tm_hour); 1945f119f29SThomas Bogendoerfer tm->tm_mday = bcd2bin(tm->tm_mday); 1955f119f29SThomas Bogendoerfer tm->tm_mon = bcd2bin(tm->tm_mon); 1965f119f29SThomas Bogendoerfer tm->tm_year = bcd2bin(tm->tm_year); 1975f119f29SThomas Bogendoerfer 1985f119f29SThomas Bogendoerfer /* 1995f119f29SThomas Bogendoerfer * Account for differences between how the RTC uses the values 2005f119f29SThomas Bogendoerfer * and how they are defined in a struct rtc_time; 2015f119f29SThomas Bogendoerfer */ 2025f119f29SThomas Bogendoerfer if (tm->tm_year < 45) 2035f119f29SThomas Bogendoerfer tm->tm_year += 30; 2045f119f29SThomas Bogendoerfer tm->tm_year += 40; 2055f119f29SThomas Bogendoerfer if (tm->tm_year < 70) 2065f119f29SThomas Bogendoerfer tm->tm_year += 100; 2075f119f29SThomas Bogendoerfer 2085f119f29SThomas Bogendoerfer tm->tm_mon--; 2095f119f29SThomas Bogendoerfer 21022652ba7SAlexandre Belloni return 0; 2115f119f29SThomas Bogendoerfer } 2125f119f29SThomas Bogendoerfer 2135f119f29SThomas Bogendoerfer static int ds1286_set_time(struct device *dev, struct rtc_time *tm) 2145f119f29SThomas Bogendoerfer { 2155f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 2165f119f29SThomas Bogendoerfer unsigned char mon, day, hrs, min, sec; 2175f119f29SThomas Bogendoerfer unsigned char save_control; 2185f119f29SThomas Bogendoerfer unsigned int yrs; 2195f119f29SThomas Bogendoerfer unsigned long flags; 2205f119f29SThomas Bogendoerfer 2215f119f29SThomas Bogendoerfer yrs = tm->tm_year + 1900; 2225f119f29SThomas Bogendoerfer mon = tm->tm_mon + 1; /* tm_mon starts at zero */ 2235f119f29SThomas Bogendoerfer day = tm->tm_mday; 2245f119f29SThomas Bogendoerfer hrs = tm->tm_hour; 2255f119f29SThomas Bogendoerfer min = tm->tm_min; 2265f119f29SThomas Bogendoerfer sec = tm->tm_sec; 2275f119f29SThomas Bogendoerfer 2285f119f29SThomas Bogendoerfer if (yrs < 1970) 2295f119f29SThomas Bogendoerfer return -EINVAL; 2305f119f29SThomas Bogendoerfer 2315f119f29SThomas Bogendoerfer yrs -= 1940; 2325f119f29SThomas Bogendoerfer if (yrs > 255) /* They are unsigned */ 2335f119f29SThomas Bogendoerfer return -EINVAL; 2345f119f29SThomas Bogendoerfer 2355f119f29SThomas Bogendoerfer if (yrs >= 100) 2365f119f29SThomas Bogendoerfer yrs -= 100; 2375f119f29SThomas Bogendoerfer 2385f119f29SThomas Bogendoerfer sec = bin2bcd(sec); 2395f119f29SThomas Bogendoerfer min = bin2bcd(min); 2405f119f29SThomas Bogendoerfer hrs = bin2bcd(hrs); 2415f119f29SThomas Bogendoerfer day = bin2bcd(day); 2425f119f29SThomas Bogendoerfer mon = bin2bcd(mon); 2435f119f29SThomas Bogendoerfer yrs = bin2bcd(yrs); 2445f119f29SThomas Bogendoerfer 2455f119f29SThomas Bogendoerfer spin_lock_irqsave(&priv->lock, flags); 2465f119f29SThomas Bogendoerfer save_control = ds1286_rtc_read(priv, RTC_CMD); 2475f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD); 2485f119f29SThomas Bogendoerfer 2495f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, yrs, RTC_YEAR); 2505f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, mon, RTC_MONTH); 2515f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, day, RTC_DATE); 2525f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, hrs, RTC_HOURS); 2535f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, min, RTC_MINUTES); 2545f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, sec, RTC_SECONDS); 2555f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND); 2565f119f29SThomas Bogendoerfer 2575f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, save_control, RTC_CMD); 2585f119f29SThomas Bogendoerfer spin_unlock_irqrestore(&priv->lock, flags); 2595f119f29SThomas Bogendoerfer return 0; 2605f119f29SThomas Bogendoerfer } 2615f119f29SThomas Bogendoerfer 2625f119f29SThomas Bogendoerfer static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm) 2635f119f29SThomas Bogendoerfer { 2645f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 2655f119f29SThomas Bogendoerfer unsigned long flags; 2665f119f29SThomas Bogendoerfer 2675f119f29SThomas Bogendoerfer /* 2685f119f29SThomas Bogendoerfer * Only the values that we read from the RTC are set. That 2695f119f29SThomas Bogendoerfer * means only tm_wday, tm_hour, tm_min. 2705f119f29SThomas Bogendoerfer */ 2715f119f29SThomas Bogendoerfer spin_lock_irqsave(&priv->lock, flags); 2725f119f29SThomas Bogendoerfer alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f; 2735f119f29SThomas Bogendoerfer alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f; 2745f119f29SThomas Bogendoerfer alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07; 275cb72f60cSDevendra Naga ds1286_rtc_read(priv, RTC_CMD); 2765f119f29SThomas Bogendoerfer spin_unlock_irqrestore(&priv->lock, flags); 2775f119f29SThomas Bogendoerfer 2785f119f29SThomas Bogendoerfer alm->time.tm_min = bcd2bin(alm->time.tm_min); 2795f119f29SThomas Bogendoerfer alm->time.tm_hour = bcd2bin(alm->time.tm_hour); 2805f119f29SThomas Bogendoerfer alm->time.tm_sec = 0; 2815f119f29SThomas Bogendoerfer return 0; 2825f119f29SThomas Bogendoerfer } 2835f119f29SThomas Bogendoerfer 2845f119f29SThomas Bogendoerfer static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm) 2855f119f29SThomas Bogendoerfer { 2865f119f29SThomas Bogendoerfer struct ds1286_priv *priv = dev_get_drvdata(dev); 2875f119f29SThomas Bogendoerfer unsigned char hrs, min, sec; 2885f119f29SThomas Bogendoerfer 2895f119f29SThomas Bogendoerfer hrs = alm->time.tm_hour; 2905f119f29SThomas Bogendoerfer min = alm->time.tm_min; 2915f119f29SThomas Bogendoerfer sec = alm->time.tm_sec; 2925f119f29SThomas Bogendoerfer 2935f119f29SThomas Bogendoerfer if (hrs >= 24) 2945f119f29SThomas Bogendoerfer hrs = 0xff; 2955f119f29SThomas Bogendoerfer 2965f119f29SThomas Bogendoerfer if (min >= 60) 2975f119f29SThomas Bogendoerfer min = 0xff; 2985f119f29SThomas Bogendoerfer 2995f119f29SThomas Bogendoerfer if (sec != 0) 3005f119f29SThomas Bogendoerfer return -EINVAL; 3015f119f29SThomas Bogendoerfer 3025f119f29SThomas Bogendoerfer min = bin2bcd(min); 3035f119f29SThomas Bogendoerfer hrs = bin2bcd(hrs); 3045f119f29SThomas Bogendoerfer 3055f119f29SThomas Bogendoerfer spin_lock(&priv->lock); 3065f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM); 3075f119f29SThomas Bogendoerfer ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM); 3085f119f29SThomas Bogendoerfer spin_unlock(&priv->lock); 3095f119f29SThomas Bogendoerfer 3105f119f29SThomas Bogendoerfer return 0; 3115f119f29SThomas Bogendoerfer } 3125f119f29SThomas Bogendoerfer 3135f119f29SThomas Bogendoerfer static const struct rtc_class_ops ds1286_ops = { 3145f119f29SThomas Bogendoerfer .ioctl = ds1286_ioctl, 3155f119f29SThomas Bogendoerfer .proc = ds1286_proc, 3165f119f29SThomas Bogendoerfer .read_time = ds1286_read_time, 3175f119f29SThomas Bogendoerfer .set_time = ds1286_set_time, 3185f119f29SThomas Bogendoerfer .read_alarm = ds1286_read_alarm, 3195f119f29SThomas Bogendoerfer .set_alarm = ds1286_set_alarm, 32016380c15SJohn Stultz .alarm_irq_enable = ds1286_alarm_irq_enable, 3215f119f29SThomas Bogendoerfer }; 3225f119f29SThomas Bogendoerfer 3235a167f45SGreg Kroah-Hartman static int ds1286_probe(struct platform_device *pdev) 3245f119f29SThomas Bogendoerfer { 3255f119f29SThomas Bogendoerfer struct rtc_device *rtc; 3265f119f29SThomas Bogendoerfer struct ds1286_priv *priv; 3275f119f29SThomas Bogendoerfer 328061d698eSJingoo Han priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL); 3295f119f29SThomas Bogendoerfer if (!priv) 3305f119f29SThomas Bogendoerfer return -ENOMEM; 3315f119f29SThomas Bogendoerfer 332*09ef18bcSYueHaibing priv->rtcregs = devm_platform_ioremap_resource(pdev, 0); 333061d698eSJingoo Han if (IS_ERR(priv->rtcregs)) 334061d698eSJingoo Han return PTR_ERR(priv->rtcregs); 335061d698eSJingoo Han 3365f119f29SThomas Bogendoerfer spin_lock_init(&priv->lock); 3379a281a67SJohn Stultz platform_set_drvdata(pdev, priv); 338061d698eSJingoo Han rtc = devm_rtc_device_register(&pdev->dev, "ds1286", &ds1286_ops, 339061d698eSJingoo Han THIS_MODULE); 340061d698eSJingoo Han if (IS_ERR(rtc)) 341061d698eSJingoo Han return PTR_ERR(rtc); 3425f119f29SThomas Bogendoerfer priv->rtc = rtc; 3435f119f29SThomas Bogendoerfer return 0; 3445f119f29SThomas Bogendoerfer } 3455f119f29SThomas Bogendoerfer 3465f119f29SThomas Bogendoerfer static struct platform_driver ds1286_platform_driver = { 3475f119f29SThomas Bogendoerfer .driver = { 3485f119f29SThomas Bogendoerfer .name = "rtc-ds1286", 3495f119f29SThomas Bogendoerfer }, 3505f119f29SThomas Bogendoerfer .probe = ds1286_probe, 3515f119f29SThomas Bogendoerfer }; 3525f119f29SThomas Bogendoerfer 3530c4eae66SAxel Lin module_platform_driver(ds1286_platform_driver); 3545f119f29SThomas Bogendoerfer 3555f119f29SThomas Bogendoerfer MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); 3565f119f29SThomas Bogendoerfer MODULE_DESCRIPTION("DS1286 RTC driver"); 3575f119f29SThomas Bogendoerfer MODULE_LICENSE("GPL"); 3585f119f29SThomas Bogendoerfer MODULE_ALIAS("platform:rtc-ds1286"); 359