/* * drivers/rtc/rtc-max77663.c * Max77663 RTC driver * * Copyright 2011-2012, Maxim Integrated Products, Inc. * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * */ #include #include #include #include #include #include #include /* RTC Registers */ #define MAX77663_RTC_IRQ 0x00 #define MAX77663_RTC_IRQ_MASK 0x01 #define MAX77663_RTC_CTRL_MODE 0x02 #define MAX77663_RTC_CTRL 0x03 #define MAX77663_RTC_UPDATE0 0x04 #define MAX77663_RTC_UPDATE1 0x05 #define MAX77663_RTC_SEC 0x07 #define MAX77663_RTC_MIN 0x08 #define MAX77663_RTC_HOUR 0x09 #define MAX77663_RTC_WEEKDAY 0x0A #define MAX77663_RTC_MONTH 0x0B #define MAX77663_RTC_YEAR 0x0C #define MAX77663_RTC_MONTHDAY 0x0D #define MAX77663_RTC_ALARM_SEC1 0x0E #define MAX77663_RTC_ALARM_MIN1 0x0F #define MAX77663_RTC_ALARM_HOUR1 0x10 #define MAX77663_RTC_ALARM_WEEKDAY1 0x11 #define MAX77663_RTC_ALARM_MONTH1 0x12 #define MAX77663_RTC_ALARM_YEAR1 0x13 #define MAX77663_RTC_ALARM_MONTHDAY1 0x14 #define RTC_IRQ_60SEC_MASK (1 << 0) #define RTC_IRQ_ALARM1_MASK (1 << 1) #define RTC_IRQ_ALARM2_MASK (1 << 2) #define RTC_IRQ_SMPL_MASK (1 << 3) #define RTC_IRQ_1SEC_MASK (1 << 4) #define RTC_IRQ_MASK 0x1F #define BCD_MODE_MASK (1 << 0) #define HR_MODE_MASK (1 << 1) #define WB_UPDATE_MASK (1 << 0) #define FLAG_AUTO_CLEAR_MASK (1 << 1) #define FREEZE_SEC_MASK (1 << 2) #define RTC_WAKE_MASK (1 << 3) #define RB_UPDATE_MASK (1 << 4) #define WB_UPDATE_FLAG_MASK (1 << 0) #define RB_UPDATE_FLAG_MASK (1 << 1) #define SEC_MASK 0x7F #define MIN_MASK 0x7F #define HOUR_MASK 0x3F #define WEEKDAY_MASK 0x7F #define MONTH_MASK 0x1F #define YEAR_MASK 0xFF #define MONTHDAY_MASK 0x3F #define ALARM_EN_MASK 0x80 #define ALARM_EN_SHIFT 7 #define RTC_YEAR_BASE 100 #define RTC_YEAR_MAX 99 /* ON/OFF Registers */ #define MAX77663_REG_ONOFF_CFG2 0x42 #define ONOFF_WK_ALARM1_MASK (1 << 2) enum { RTC_SEC, RTC_MIN, RTC_HOUR, RTC_WEEKDAY, RTC_MONTH, RTC_YEAR, RTC_MONTHDAY, RTC_NR }; struct max77663_rtc { struct rtc_device *rtc; struct device *dev; struct mutex io_lock; int irq; u8 irq_mask; bool shutdown_ongoing; }; static inline struct device *_to_parent(struct max77663_rtc *rtc) { return rtc->dev->parent; } static inline int max77663_rtc_update_buffer(struct max77663_rtc *rtc, int write) { struct device *parent = _to_parent(rtc); u8 val = FLAG_AUTO_CLEAR_MASK | RTC_WAKE_MASK; int ret; if (write) val |= WB_UPDATE_MASK; else val |= RB_UPDATE_MASK; dev_dbg(rtc->dev, "rtc_update_buffer: write=%d, addr=0x%x, val=0x%x\n", write, MAX77663_RTC_UPDATE0, val); ret = max77663_write(parent, MAX77663_RTC_UPDATE0, &val, 1, 1); if (ret < 0) { dev_err(rtc->dev, "rtc_update_buffer: " "Failed to get rtc update0\n"); return ret; } /* * Must wait 14ms for buffer update. * If the sleeping time is 10us - 20ms, usleep_range() is recommended. * Please refer Documentation/timers/timers-howto.txt. */ usleep_range(14000, 14000); return 0; } static inline int max77663_rtc_write(struct max77663_rtc *rtc, u8 addr, void *values, u32 len, int update_buffer) { struct device *parent = _to_parent(rtc); int ret; mutex_lock(&rtc->io_lock); dev_dbg(rtc->dev, "rtc_write: addr=0x%x, values=0x%x, len=%u, " "update_buffer=%d\n", addr, *((u8 *)values), len, update_buffer); ret = max77663_write(parent, addr, values, len, 1); if (ret < 0) goto out; if (update_buffer) ret = max77663_rtc_update_buffer(rtc, 1); out: mutex_unlock(&rtc->io_lock); return ret; } static inline int max77663_rtc_read(struct max77663_rtc *rtc, u8 addr, void *values, u32 len, int update_buffer) { struct device *parent = _to_parent(rtc); int ret; mutex_lock(&rtc->io_lock); if (update_buffer) { ret = max77663_rtc_update_buffer(rtc, 0); if (ret < 0) goto out; } ret = max77663_read(parent, addr, values, len, 1); dev_dbg(rtc->dev, "rtc_read: addr=0x%x, values=0x%x, len=%u, " "update_buffer=%d\n", addr, *((u8 *)values), len, update_buffer); out: mutex_unlock(&rtc->io_lock); return ret; } static inline int max77663_rtc_reg_to_tm(struct max77663_rtc *rtc, u8 *buf, struct rtc_time *tm) { int wday = buf[RTC_WEEKDAY] & WEEKDAY_MASK; if (unlikely(!wday)) { dev_err(rtc->dev, "rtc_reg_to_tm: Invalid day of week, %d\n", wday); return -EINVAL; } tm->tm_sec = (int)(buf[RTC_SEC] & SEC_MASK); tm->tm_min = (int)(buf[RTC_MIN] & MIN_MASK); tm->tm_hour = (int)(buf[RTC_HOUR] & HOUR_MASK); tm->tm_mday = (int)(buf[RTC_MONTHDAY] & MONTHDAY_MASK); tm->tm_mon = (int)(buf[RTC_MONTH] & MONTH_MASK) - 1; tm->tm_year = (int)(buf[RTC_YEAR] & YEAR_MASK) + RTC_YEAR_BASE; tm->tm_wday = ffs(wday) - 1; return 0; } static inline int max77663_rtc_tm_to_reg(struct max77663_rtc *rtc, u8 *buf, struct rtc_time *tm, int alarm) { u8 alarm_mask = alarm ? ALARM_EN_MASK : 0; if (unlikely((tm->tm_year < RTC_YEAR_BASE) || (tm->tm_year > RTC_YEAR_BASE + RTC_YEAR_MAX))) { dev_err(rtc->dev, "rtc_tm_to_reg: Invalid year, %d\n", tm->tm_year); return -EINVAL; } buf[RTC_SEC] = tm->tm_sec | alarm_mask; buf[RTC_MIN] = tm->tm_min | alarm_mask; buf[RTC_HOUR] = tm->tm_hour | alarm_mask; buf[RTC_MONTHDAY] = tm->tm_mday | alarm_mask; buf[RTC_MONTH] = (tm->tm_mon + 1) | alarm_mask; buf[RTC_YEAR] = (tm->tm_year - RTC_YEAR_BASE) | alarm_mask; /* The wday is configured only when disabled alarm. */ if (!alarm) buf[RTC_WEEKDAY] = (1 << tm->tm_wday); else buf[RTC_WEEKDAY] = 0; return 0; } static inline int max77663_rtc_irq_mask(struct max77663_rtc *rtc, u8 irq) { struct device *parent = _to_parent(rtc); u8 irq_mask = rtc->irq_mask | irq; int ret = 0; ret = max77663_write(parent, MAX77663_RTC_IRQ_MASK, &irq_mask, 1, 1); if (ret < 0) { dev_err(rtc->dev, "rtc_irq_mask: Failed to set rtc irq mask\n"); goto out; } rtc->irq_mask = irq_mask; out: return ret; } static inline int max77663_rtc_irq_unmask(struct max77663_rtc *rtc, u8 irq) { struct device *parent = _to_parent(rtc); u8 irq_mask = rtc->irq_mask & ~irq; int ret = 0; ret = max77663_write(parent, MAX77663_RTC_IRQ_MASK, &irq_mask, 1, 1); if (ret < 0) { dev_err(rtc->dev, "rtc_irq_unmask: Failed to set rtc irq mask\n"); goto out; } rtc->irq_mask = irq_mask; out: return ret; } static inline int max77663_rtc_do_irq(struct max77663_rtc *rtc) { struct device *parent = _to_parent(rtc); u8 irq_status; int ret; ret = max77663_rtc_update_buffer(rtc, 0); if (ret < 0) { dev_err(rtc->dev, "rtc_irq: Failed to get rtc update buffer\n"); return ret; } ret = max77663_read(parent, MAX77663_RTC_IRQ, &irq_status, 1, 1); if (ret < 0) { dev_err(rtc->dev, "rtc_irq: Failed to get rtc irq status\n"); return ret; } dev_dbg(rtc->dev, "rtc_do_irq: irq_mask=0x%02x, irq_status=0x%02x\n", rtc->irq_mask, irq_status); if (!(rtc->irq_mask & RTC_IRQ_ALARM1_MASK) && (irq_status & RTC_IRQ_ALARM1_MASK)) rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); if (!(rtc->irq_mask & RTC_IRQ_1SEC_MASK) && (irq_status & RTC_IRQ_1SEC_MASK)) rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF); return ret; } static irqreturn_t max77663_rtc_irq(int irq, void *data) { struct max77663_rtc *rtc = (struct max77663_rtc *)data; max77663_rtc_do_irq(rtc); return IRQ_HANDLED; } static int max77663_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct max77663_rtc *rtc = dev_get_drvdata(dev); int ret = 0; if (rtc->irq < 0) return -ENXIO; mutex_lock(&rtc->io_lock); /* Handle pending interrupt */ ret = max77663_rtc_do_irq(rtc); if (ret < 0) goto out; /* Config alarm interrupt */ if (enabled) { ret = max77663_rtc_irq_unmask(rtc, RTC_IRQ_ALARM1_MASK); if (ret < 0) goto out; } else { ret = max77663_rtc_irq_mask(rtc, RTC_IRQ_ALARM1_MASK); if (ret < 0) goto out; } out: mutex_unlock(&rtc->io_lock); return ret; } static int max77663_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct max77663_rtc *rtc = dev_get_drvdata(dev); u8 buf[RTC_NR]; int ret; ret = max77663_rtc_read(rtc, MAX77663_RTC_SEC, buf, sizeof(buf), 1); if (ret < 0) { dev_err(rtc->dev, "rtc_read_time: Failed to read rtc time\n"); return ret; } dev_dbg(rtc->dev, "rtc_read_time: " "buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY], buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]); ret = max77663_rtc_reg_to_tm(rtc, buf, tm); if (ret < 0) { dev_err(rtc->dev, "rtc_read_time: " "Failed to convert register format into time format\n"); return ret; } dev_dbg(rtc->dev, "rtc_read_time: " "tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); return ret; } static int max77663_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct max77663_rtc *rtc = dev_get_drvdata(dev); u8 buf[RTC_NR]; int ret; dev_dbg(rtc->dev, "rtc_set_time: " "tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); ret = max77663_rtc_tm_to_reg(rtc, buf, tm, 0); if (ret < 0) { dev_err(rtc->dev, "rtc_set_time: " "Failed to convert time format into register format\n"); return ret; } dev_dbg(rtc->dev, "rtc_set_time: " "buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY], buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]); return max77663_rtc_write(rtc, MAX77663_RTC_SEC, buf, sizeof(buf), 1); } static int max77663_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct max77663_rtc *rtc = dev_get_drvdata(dev); u8 buf[RTC_NR]; int ret; ret = max77663_rtc_read(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1); if (ret < 0) { dev_err(rtc->dev, "rtc_read_alarm: Failed to read rtc alarm time\n"); return ret; } dev_dbg(rtc->dev, "rtc_read_alarm: " "buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY], buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]); ret = max77663_rtc_reg_to_tm(rtc, buf, &alrm->time); if (ret < 0) { dev_err(rtc->dev, "rtc_read_alarm: " "Failed to convert register format into time format\n"); return ret; } dev_dbg(rtc->dev, "rtc_read_alarm: " "tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d\n", alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, alrm->time.tm_sec, alrm->time.tm_wday); if (rtc->irq_mask & RTC_IRQ_ALARM1_MASK) alrm->enabled = 1; else alrm->enabled = 0; return 0; } static int max77663_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct max77663_rtc *rtc = dev_get_drvdata(dev); u8 buf[RTC_NR]; int ret; if (rtc->shutdown_ongoing) { dev_warn(rtc->dev, "rtc_set_alarm: " "Device shutdown on-going, skip alarm setting.\n"); return -ESHUTDOWN; } dev_dbg(rtc->dev, "rtc_set_alarm: " "tm: %d-%02d-%02d %02d:%02d:%02d, wday=%d [%s]\n", alrm->time.tm_year, alrm->time.tm_mon, alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, alrm->time.tm_sec, alrm->time.tm_wday, alrm->enabled?"enable":"disable"); ret = max77663_rtc_tm_to_reg(rtc, buf, &alrm->time, 1); if (ret < 0) { dev_err(rtc->dev, "rtc_set_alarm: " "Failed to convert time format into register format\n"); return ret; } dev_dbg(rtc->dev, "rtc_set_alarm: " "buf: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[RTC_SEC], buf[RTC_MIN], buf[RTC_HOUR], buf[RTC_WEEKDAY], buf[RTC_MONTH], buf[RTC_YEAR], buf[RTC_MONTHDAY]); ret = max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1); if (ret < 0) { dev_err(rtc->dev, "rtc_set_alarm: Failed to write rtc alarm time\n"); return ret; } ret = max77663_rtc_alarm_irq_enable(dev, alrm->enabled); if (ret < 0) { dev_err(rtc->dev, "rtc_set_alarm: Failed to enable rtc alarm\n"); return ret; } return ret; } static const struct rtc_class_ops max77663_rtc_ops = { .read_time = max77663_rtc_read_time, .set_time = max77663_rtc_set_time, .read_alarm = max77663_rtc_read_alarm, .set_alarm = max77663_rtc_set_alarm, .alarm_irq_enable = max77663_rtc_alarm_irq_enable, }; static int max77663_rtc_preinit(struct max77663_rtc *rtc) { struct device *parent = _to_parent(rtc); u8 val; int ret; /* Mask all interrupts */ rtc->irq_mask = 0xFF; ret = max77663_rtc_write(rtc, MAX77663_RTC_IRQ_MASK, &rtc->irq_mask, 1, 0); if (ret < 0) { dev_err(rtc->dev, "preinit: Failed to set rtc irq mask\n"); return ret; } /* Configure Binary mode and 24hour mode */ val = HR_MODE_MASK; ret = max77663_rtc_write(rtc, MAX77663_RTC_CTRL, &val, 1, 0); if (ret < 0) { dev_err(rtc->dev, "preinit: Failed to set rtc control\n"); return ret; } /* It should be disabled alarm wakeup to wakeup from sleep * by EN1 input signal */ ret = max77663_set_bits(parent, MAX77663_REG_ONOFF_CFG2, ONOFF_WK_ALARM1_MASK, 0, 0); if (ret < 0) { dev_err(rtc->dev, "preinit: Failed to set onoff cfg2\n"); return ret; } return 0; } static int max77663_rtc_probe(struct platform_device *pdev) { struct max77663_platform_data *parent_pdata = pdev->dev.parent->platform_data; static struct max77663_rtc *rtc; int ret = 0; rtc = kzalloc(sizeof(struct max77663_rtc), GFP_KERNEL); if (!rtc) { dev_err(&pdev->dev, "probe: kzalloc() failed\n"); return -ENOMEM; } rtc->shutdown_ongoing = false; dev_set_drvdata(&pdev->dev, rtc); rtc->dev = &pdev->dev; mutex_init(&rtc->io_lock); ret = max77663_rtc_preinit(rtc); if (ret) { dev_err(&pdev->dev, "probe: Failed to rtc preinit\n"); goto out_kfree; } rtc->rtc = rtc_device_register("max77663-rtc", &pdev->dev, &max77663_rtc_ops, THIS_MODULE); if (IS_ERR_OR_NULL(rtc->rtc)) { dev_err(&pdev->dev, "probe: Failed to register rtc\n"); ret = PTR_ERR(rtc->rtc); goto out_kfree; } if (parent_pdata->irq_base < 0) goto out; rtc->irq = parent_pdata->irq_base + MAX77663_IRQ_RTC; ret = request_threaded_irq(rtc->irq, NULL, max77663_rtc_irq, IRQF_ONESHOT, "max77663-rtc", rtc); if (ret < 0) { dev_err(rtc->dev, "probe: Failed to request irq %d\n", rtc->irq); rtc->irq = -1; } else { device_init_wakeup(rtc->dev, 1); enable_irq_wake(rtc->irq); } return 0; out_kfree: mutex_destroy(&rtc->io_lock); kfree(rtc->rtc); out: return ret; } static int __devexit max77663_rtc_remove(struct platform_device *pdev) { struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev); if (rtc->irq != -1) free_irq(rtc->irq, rtc); rtc_device_unregister(rtc->rtc); mutex_destroy(&rtc->io_lock); kfree(rtc); return 0; } static void max77663_rtc_shutdown(struct platform_device *pdev) { struct max77663_rtc *rtc = dev_get_drvdata(&pdev->dev); u8 buf[RTC_NR] = { 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x1 }; rtc->shutdown_ongoing = true; dev_info(rtc->dev, "rtc_shutdown: clean alarm\n"); max77663_rtc_write(rtc, MAX77663_RTC_ALARM_SEC1, buf, sizeof(buf), 1); max77663_rtc_alarm_irq_enable(&pdev->dev, 0); } static struct platform_driver max77663_rtc_driver = { .probe = max77663_rtc_probe, .remove = __devexit_p(max77663_rtc_remove), .driver = { .name = "max77663-rtc", .owner = THIS_MODULE, }, .shutdown = max77663_rtc_shutdown, }; static int __init max77663_rtc_init(void) { return platform_driver_register(&max77663_rtc_driver); } module_init(max77663_rtc_init); static void __exit max77663_rtc_exit(void) { platform_driver_unregister(&max77663_rtc_driver); } module_exit(max77663_rtc_exit); MODULE_DESCRIPTION("max77663 RTC driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("1.0");