linux/drivers/rtc/rtc-rc5t583.c
<<
>>
Prefs
   1/*
   2 * rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock
   3 *
   4 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
   5 * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms and conditions of the GNU General Public License,
   9 * version 2, as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>. */
  18
  19#include <linux/kernel.h>
  20#include <linux/errno.h>
  21#include <linux/init.h>
  22#include <linux/module.h>
  23#include <linux/types.h>
  24#include <linux/rtc.h>
  25#include <linux/bcd.h>
  26#include <linux/platform_device.h>
  27#include <linux/interrupt.h>
  28#include <linux/mfd/rc5t583.h>
  29
  30struct rc5t583_rtc {
  31        struct rtc_device       *rtc;
  32        /* To store the list of enabled interrupts, during system suspend */
  33        u32 irqen;
  34};
  35
  36/* Total number of RTC registers needed to set time*/
  37#define NUM_TIME_REGS   (RC5T583_RTC_YEAR - RC5T583_RTC_SEC + 1)
  38
  39/* Total number of RTC registers needed to set Y-Alarm*/
  40#define NUM_YAL_REGS    (RC5T583_RTC_AY_YEAR - RC5T583_RTC_AY_MIN + 1)
  41
  42/* Set Y-Alarm interrupt */
  43#define SET_YAL BIT(5)
  44
  45/* Get Y-Alarm interrupt status*/
  46#define GET_YAL_STATUS BIT(3)
  47
  48static int rc5t583_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
  49{
  50        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
  51        u8 val;
  52
  53        /* Set Y-Alarm, based on 'enabled' */
  54        val = enabled ? SET_YAL : 0;
  55
  56        return regmap_update_bits(rc5t583->regmap, RC5T583_RTC_CTL1, SET_YAL,
  57                val);
  58}
  59
  60/*
  61 * Gets current rc5t583 RTC time and date parameters.
  62 *
  63 * The RTC's time/alarm representation is not what gmtime(3) requires
  64 * Linux to use:
  65 *
  66 *  - Months are 1..12 vs Linux 0-11
  67 *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
  68 */
  69static int rc5t583_rtc_read_time(struct device *dev, struct rtc_time *tm)
  70{
  71        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
  72        u8 rtc_data[NUM_TIME_REGS];
  73        int ret;
  74
  75        ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
  76                NUM_TIME_REGS);
  77        if (ret < 0) {
  78                dev_err(dev, "RTC read time failed with err:%d\n", ret);
  79                return ret;
  80        }
  81
  82        tm->tm_sec = bcd2bin(rtc_data[0]);
  83        tm->tm_min = bcd2bin(rtc_data[1]);
  84        tm->tm_hour = bcd2bin(rtc_data[2]);
  85        tm->tm_wday = bcd2bin(rtc_data[3]);
  86        tm->tm_mday = bcd2bin(rtc_data[4]);
  87        tm->tm_mon = bcd2bin(rtc_data[5]) - 1;
  88        tm->tm_year = bcd2bin(rtc_data[6]) + 100;
  89
  90        return ret;
  91}
  92
  93static int rc5t583_rtc_set_time(struct device *dev, struct rtc_time *tm)
  94{
  95        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
  96        unsigned char rtc_data[NUM_TIME_REGS];
  97        int ret;
  98
  99        rtc_data[0] = bin2bcd(tm->tm_sec);
 100        rtc_data[1] = bin2bcd(tm->tm_min);
 101        rtc_data[2] = bin2bcd(tm->tm_hour);
 102        rtc_data[3] = bin2bcd(tm->tm_wday);
 103        rtc_data[4] = bin2bcd(tm->tm_mday);
 104        rtc_data[5] = bin2bcd(tm->tm_mon + 1);
 105        rtc_data[6] = bin2bcd(tm->tm_year - 100);
 106
 107        ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data,
 108                NUM_TIME_REGS);
 109        if (ret < 0) {
 110                dev_err(dev, "RTC set time failed with error %d\n", ret);
 111                return ret;
 112        }
 113
 114        return ret;
 115}
 116
 117static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 118{
 119        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 120        unsigned char alarm_data[NUM_YAL_REGS];
 121        u32 interrupt_enable;
 122        int ret;
 123
 124        ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
 125                NUM_YAL_REGS);
 126        if (ret < 0) {
 127                dev_err(dev, "rtc_read_alarm error %d\n", ret);
 128                return ret;
 129        }
 130
 131        alm->time.tm_min = bcd2bin(alarm_data[0]);
 132        alm->time.tm_hour = bcd2bin(alarm_data[1]);
 133        alm->time.tm_mday = bcd2bin(alarm_data[2]);
 134        alm->time.tm_mon = bcd2bin(alarm_data[3]) - 1;
 135        alm->time.tm_year = bcd2bin(alarm_data[4]) + 100;
 136
 137        ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, &interrupt_enable);
 138        if (ret < 0)
 139                return ret;
 140
 141        /* check if YALE is set */
 142        if (interrupt_enable & SET_YAL)
 143                alm->enabled = 1;
 144
 145        return ret;
 146}
 147
 148static int rc5t583_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 149{
 150        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 151        unsigned char alarm_data[NUM_YAL_REGS];
 152        int ret;
 153
 154        ret = rc5t583_rtc_alarm_irq_enable(dev, 0);
 155        if (ret)
 156                return ret;
 157
 158        alarm_data[0] = bin2bcd(alm->time.tm_min);
 159        alarm_data[1] = bin2bcd(alm->time.tm_hour);
 160        alarm_data[2] = bin2bcd(alm->time.tm_mday);
 161        alarm_data[3] = bin2bcd(alm->time.tm_mon + 1);
 162        alarm_data[4] = bin2bcd(alm->time.tm_year - 100);
 163
 164        ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data,
 165                NUM_YAL_REGS);
 166        if (ret) {
 167                dev_err(dev, "rtc_set_alarm error %d\n", ret);
 168                return ret;
 169        }
 170
 171        if (alm->enabled)
 172                ret = rc5t583_rtc_alarm_irq_enable(dev, 1);
 173
 174        return ret;
 175}
 176
 177static irqreturn_t rc5t583_rtc_interrupt(int irq, void *rtc)
 178{
 179        struct device *dev = rtc;
 180        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 181        struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
 182        unsigned long events = 0;
 183        int ret;
 184        u32 rtc_reg;
 185
 186        ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL2, &rtc_reg);
 187        if (ret < 0)
 188                return IRQ_NONE;
 189
 190        if (rtc_reg & GET_YAL_STATUS) {
 191                events = RTC_IRQF | RTC_AF;
 192                /* clear pending Y-alarm interrupt bit */
 193                rtc_reg &= ~GET_YAL_STATUS;
 194        }
 195
 196        ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, rtc_reg);
 197        if (ret)
 198                return IRQ_NONE;
 199
 200        /* Notify RTC core on event */
 201        rtc_update_irq(rc5t583_rtc->rtc, 1, events);
 202
 203        return IRQ_HANDLED;
 204}
 205
 206static const struct rtc_class_ops rc5t583_rtc_ops = {
 207        .read_time      = rc5t583_rtc_read_time,
 208        .set_time       = rc5t583_rtc_set_time,
 209        .read_alarm     = rc5t583_rtc_read_alarm,
 210        .set_alarm      = rc5t583_rtc_set_alarm,
 211        .alarm_irq_enable = rc5t583_rtc_alarm_irq_enable,
 212};
 213
 214static int rc5t583_rtc_probe(struct platform_device *pdev)
 215{
 216        struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
 217        struct rc5t583_rtc *ricoh_rtc;
 218        struct rc5t583_platform_data *pmic_plat_data;
 219        int ret;
 220        int irq;
 221
 222        ricoh_rtc = devm_kzalloc(&pdev->dev, sizeof(struct rc5t583_rtc),
 223                        GFP_KERNEL);
 224        if (!ricoh_rtc)
 225                return -ENOMEM;
 226
 227        platform_set_drvdata(pdev, ricoh_rtc);
 228
 229        /* Clear pending interrupts */
 230        ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, 0);
 231        if (ret < 0)
 232                return ret;
 233
 234        /* clear RTC Adjust register */
 235        ret = regmap_write(rc5t583->regmap, RC5T583_RTC_ADJ, 0);
 236        if (ret < 0) {
 237                dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
 238                return -EBUSY;
 239        }
 240
 241        pmic_plat_data = dev_get_platdata(rc5t583->dev);
 242        irq = pmic_plat_data->irq_base;
 243        if (irq <= 0) {
 244                dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
 245                        irq);
 246                return ret;
 247        }
 248
 249        irq += RC5T583_IRQ_YALE;
 250        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 251                rc5t583_rtc_interrupt, IRQF_TRIGGER_LOW,
 252                "rtc-rc5t583", &pdev->dev);
 253        if (ret < 0) {
 254                dev_err(&pdev->dev, "IRQ is not free.\n");
 255                return ret;
 256        }
 257        device_init_wakeup(&pdev->dev, 1);
 258
 259        ricoh_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
 260                &rc5t583_rtc_ops, THIS_MODULE);
 261        if (IS_ERR(ricoh_rtc->rtc)) {
 262                ret = PTR_ERR(ricoh_rtc->rtc);
 263                dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
 264                return ret;
 265        }
 266
 267        return 0;
 268}
 269
 270/*
 271 * Disable rc5t583 RTC interrupts.
 272 * Sets status flag to free.
 273 */
 274static int rc5t583_rtc_remove(struct platform_device *pdev)
 275{
 276        struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev);
 277
 278        rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
 279        return 0;
 280}
 281
 282#ifdef CONFIG_PM_SLEEP
 283static int rc5t583_rtc_suspend(struct device *dev)
 284{
 285        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 286        struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
 287        int ret;
 288
 289        /* Store current list of enabled interrupts*/
 290        ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1,
 291                &rc5t583_rtc->irqen);
 292        return ret;
 293}
 294
 295static int rc5t583_rtc_resume(struct device *dev)
 296{
 297        struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
 298        struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev);
 299
 300        /* Restore list of enabled interrupts before suspend */
 301        return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1,
 302                rc5t583_rtc->irqen);
 303}
 304#endif
 305
 306static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
 307                        rc5t583_rtc_resume);
 308
 309static struct platform_driver rc5t583_rtc_driver = {
 310        .probe          = rc5t583_rtc_probe,
 311        .remove         = rc5t583_rtc_remove,
 312        .driver         = {
 313                .owner  = THIS_MODULE,
 314                .name   = "rtc-rc5t583",
 315                .pm     = &rc5t583_rtc_pm_ops,
 316        },
 317};
 318
 319module_platform_driver(rc5t583_rtc_driver);
 320MODULE_ALIAS("platform:rtc-rc5t583");
 321MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
 322MODULE_LICENSE("GPL v2");
 323
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.