linux/drivers/rtc/rtc-da9052.c
<<
>>
Prefs
   1/*
   2 * Real time clock driver for DA9052
   3 *
   4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
   5 *
   6 * Author: Dajun Dajun Chen <dajun.chen@diasemi.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/platform_device.h>
  17#include <linux/rtc.h>
  18#include <linux/err.h>
  19
  20#include <linux/mfd/da9052/da9052.h>
  21#include <linux/mfd/da9052/reg.h>
  22
  23#define rtc_err(da9052, fmt, ...) \
  24                dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
  25
  26struct da9052_rtc {
  27        struct rtc_device *rtc;
  28        struct da9052 *da9052;
  29        int irq;
  30};
  31
  32static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
  33{
  34        int ret;
  35        if (enable) {
  36                ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
  37                                        DA9052_ALARM_Y_ALARM_ON,
  38                                        DA9052_ALARM_Y_ALARM_ON);
  39                if (ret != 0)
  40                        rtc_err(da9052, "Failed to enable ALM: %d\n", ret);
  41        } else {
  42                ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
  43                                        DA9052_ALARM_Y_ALARM_ON, 0);
  44                if (ret != 0)
  45                        rtc_err(da9052, "Write error: %d\n", ret);
  46        }
  47        return ret;
  48}
  49
  50static irqreturn_t da9052_rtc_irq(int irq, void *data)
  51{
  52        struct da9052_rtc *rtc = data;
  53        int ret;
  54
  55        ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG);
  56        if (ret < 0) {
  57                rtc_err(rtc->da9052, "Read error: %d\n", ret);
  58                return IRQ_NONE;
  59        }
  60
  61        if (ret & DA9052_ALARMMI_ALARMTYPE) {
  62                da9052_rtc_enable_alarm(rtc->da9052, 0);
  63                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
  64        } else
  65                rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF);
  66
  67        return IRQ_HANDLED;
  68}
  69
  70static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
  71{
  72        int ret;
  73        uint8_t v[5];
  74
  75        ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v);
  76        if (ret != 0) {
  77                rtc_err(da9052, "Failed to group read ALM: %d\n", ret);
  78                return ret;
  79        }
  80
  81        rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100;
  82        rtc_tm->tm_mon  = (v[3] & DA9052_RTC_MONTH) - 1;
  83        rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY;
  84        rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR;
  85        rtc_tm->tm_min  = v[0] & DA9052_RTC_MIN;
  86
  87        ret = rtc_valid_tm(rtc_tm);
  88        if (ret != 0)
  89                return ret;
  90        return ret;
  91}
  92
  93static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
  94{
  95        int ret;
  96        uint8_t v[3];
  97
  98        rtc_tm->tm_year -= 100;
  99        rtc_tm->tm_mon += 1;
 100
 101        ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,
 102                                DA9052_RTC_MIN, rtc_tm->tm_min);
 103        if (ret != 0) {
 104                rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret);
 105                return ret;
 106        }
 107
 108        v[0] = rtc_tm->tm_hour;
 109        v[1] = rtc_tm->tm_mday;
 110        v[2] = rtc_tm->tm_mon;
 111
 112        ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v);
 113        if (ret < 0)
 114                return ret;
 115
 116        ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
 117                                DA9052_RTC_YEAR, rtc_tm->tm_year);
 118        if (ret != 0)
 119                rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret);
 120
 121        return ret;
 122}
 123
 124static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
 125{
 126        int ret;
 127
 128        ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG);
 129        if (ret < 0) {
 130                rtc_err(da9052, "Failed to read ALM: %d\n", ret);
 131                return ret;
 132        }
 133        ret &= DA9052_ALARM_Y_ALARM_ON;
 134        return (ret > 0) ? 1 : 0;
 135}
 136
 137static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
 138{
 139        struct da9052_rtc *rtc = dev_get_drvdata(dev);
 140        uint8_t v[6];
 141        int ret;
 142
 143        ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
 144        if (ret < 0) {
 145                rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret);
 146                return ret;
 147        }
 148
 149        rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100;
 150        rtc_tm->tm_mon  = (v[4] & DA9052_RTC_MONTH) - 1;
 151        rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY;
 152        rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR;
 153        rtc_tm->tm_min  = v[1] & DA9052_RTC_MIN;
 154        rtc_tm->tm_sec  = v[0] & DA9052_RTC_SEC;
 155
 156        ret = rtc_valid_tm(rtc_tm);
 157        if (ret != 0) {
 158                rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret);
 159                return ret;
 160        }
 161
 162        return 0;
 163}
 164
 165static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
 166{
 167        struct da9052_rtc *rtc;
 168        uint8_t v[6];
 169
 170        rtc = dev_get_drvdata(dev);
 171
 172        v[0] = tm->tm_sec;
 173        v[1] = tm->tm_min;
 174        v[2] = tm->tm_hour;
 175        v[3] = tm->tm_mday;
 176        v[4] = tm->tm_mon + 1;
 177        v[5] = tm->tm_year - 100;
 178
 179        return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
 180}
 181
 182static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 183{
 184        int ret;
 185        struct rtc_time *tm = &alrm->time;
 186        struct da9052_rtc *rtc = dev_get_drvdata(dev);
 187
 188        ret = da9052_read_alarm(rtc->da9052, tm);
 189
 190        if (ret)
 191                return ret;
 192
 193        alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052);
 194
 195        return 0;
 196}
 197
 198static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 199{
 200        int ret;
 201        struct rtc_time *tm = &alrm->time;
 202        struct da9052_rtc *rtc = dev_get_drvdata(dev);
 203
 204        ret = da9052_rtc_enable_alarm(rtc->da9052, 0);
 205        if (ret < 0)
 206                return ret;
 207
 208        ret = da9052_set_alarm(rtc->da9052, tm);
 209        if (ret)
 210                return ret;
 211
 212        ret = da9052_rtc_enable_alarm(rtc->da9052, 1);
 213
 214        return ret;
 215}
 216
 217static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 218{
 219        struct da9052_rtc *rtc = dev_get_drvdata(dev);
 220
 221        return da9052_rtc_enable_alarm(rtc->da9052, enabled);
 222}
 223
 224static const struct rtc_class_ops da9052_rtc_ops = {
 225        .read_time      = da9052_rtc_read_time,
 226        .set_time       = da9052_rtc_set_time,
 227        .read_alarm     = da9052_rtc_read_alarm,
 228        .set_alarm      = da9052_rtc_set_alarm,
 229        .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
 230};
 231
 232static int da9052_rtc_probe(struct platform_device *pdev)
 233{
 234        struct da9052_rtc *rtc;
 235        int ret;
 236
 237        rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL);
 238        if (!rtc)
 239                return -ENOMEM;
 240
 241        rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
 242        platform_set_drvdata(pdev, rtc);
 243        rtc->irq =  DA9052_IRQ_ALARM;
 244        ret = da9052_request_irq(rtc->da9052, rtc->irq, "ALM",
 245                                da9052_rtc_irq, rtc);
 246        if (ret != 0) {
 247                rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
 248                return ret;
 249        }
 250
 251        rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
 252                                       &da9052_rtc_ops, THIS_MODULE);
 253        return PTR_RET(rtc->rtc);
 254}
 255
 256static struct platform_driver da9052_rtc_driver = {
 257        .probe  = da9052_rtc_probe,
 258        .driver = {
 259                .name   = "da9052-rtc",
 260                .owner  = THIS_MODULE,
 261        },
 262};
 263
 264module_platform_driver(da9052_rtc_driver);
 265
 266MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
 267MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
 268MODULE_LICENSE("GPL");
 269MODULE_ALIAS("platform:da9052-rtc");
 270
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.