Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Real time clock driver for DA9055
0004  *
0005  * Copyright(c) 2012 Dialog Semiconductor Ltd.
0006  *
0007  * Author: Dajun Dajun Chen <dajun.chen@diasemi.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/rtc.h>
0013 
0014 #include <linux/mfd/da9055/core.h>
0015 #include <linux/mfd/da9055/reg.h>
0016 #include <linux/mfd/da9055/pdata.h>
0017 
0018 struct da9055_rtc {
0019     struct rtc_device *rtc;
0020     struct da9055 *da9055;
0021     int alarm_enable;
0022 };
0023 
0024 static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable)
0025 {
0026     int ret;
0027     if (enable) {
0028         ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
0029                     DA9055_RTC_ALM_EN,
0030                     DA9055_RTC_ALM_EN);
0031         if (ret != 0)
0032             dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n",
0033                 ret);
0034         rtc->alarm_enable = 1;
0035     } else {
0036         ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
0037                     DA9055_RTC_ALM_EN, 0);
0038         if (ret != 0)
0039             dev_err(rtc->da9055->dev,
0040                 "Failed to disable ALM: %d\n", ret);
0041         rtc->alarm_enable = 0;
0042     }
0043     return ret;
0044 }
0045 
0046 static irqreturn_t da9055_rtc_alm_irq(int irq, void *data)
0047 {
0048     struct da9055_rtc *rtc = data;
0049 
0050     da9055_rtc_enable_alarm(rtc, 0);
0051     rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
0052 
0053     return IRQ_HANDLED;
0054 }
0055 
0056 static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
0057 {
0058     int ret;
0059     uint8_t v[5];
0060 
0061     ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v);
0062     if (ret != 0) {
0063         dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret);
0064         return ret;
0065     }
0066 
0067     rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100;
0068     rtc_tm->tm_mon  = (v[3] & DA9055_RTC_ALM_MONTH) - 1;
0069     rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY;
0070     rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR;
0071     rtc_tm->tm_min  = v[0] & DA9055_RTC_ALM_MIN;
0072     rtc_tm->tm_sec = 0;
0073 
0074     return rtc_valid_tm(rtc_tm);
0075 }
0076 
0077 static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
0078 {
0079     int ret;
0080     uint8_t v[2];
0081 
0082     rtc_tm->tm_year -= 100;
0083     rtc_tm->tm_mon += 1;
0084 
0085     ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI,
0086                 DA9055_RTC_ALM_MIN, rtc_tm->tm_min);
0087     if (ret != 0) {
0088         dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret);
0089         return ret;
0090     }
0091 
0092     v[0] = rtc_tm->tm_hour;
0093     v[1] = rtc_tm->tm_mday;
0094 
0095     ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v);
0096     if (ret < 0)
0097         return ret;
0098 
0099     ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
0100                 DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon);
0101     if (ret < 0)
0102         dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret);
0103 
0104     ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y,
0105                 DA9055_RTC_ALM_YEAR, rtc_tm->tm_year);
0106     if (ret < 0)
0107         dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret);
0108 
0109     return ret;
0110 }
0111 
0112 static int da9055_rtc_get_alarm_status(struct da9055 *da9055)
0113 {
0114     int ret;
0115 
0116     ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y);
0117     if (ret < 0) {
0118         dev_err(da9055->dev, "Failed to read ALM: %d\n", ret);
0119         return ret;
0120     }
0121     ret &= DA9055_RTC_ALM_EN;
0122     return (ret > 0) ? 1 : 0;
0123 }
0124 
0125 static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
0126 {
0127     struct da9055_rtc *rtc = dev_get_drvdata(dev);
0128     uint8_t v[6];
0129     int ret;
0130 
0131     ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S);
0132     if (ret < 0)
0133         return ret;
0134 
0135     /*
0136      * Registers are only valid when RTC_READ
0137      * status bit is asserted
0138      */
0139     if (!(ret & DA9055_RTC_READ))
0140         return -EBUSY;
0141 
0142     ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
0143     if (ret < 0) {
0144         dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n",
0145             ret);
0146         return ret;
0147     }
0148 
0149     rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100;
0150     rtc_tm->tm_mon  = (v[4] & DA9055_RTC_MONTH) - 1;
0151     rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY;
0152     rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR;
0153     rtc_tm->tm_min  = v[1] & DA9055_RTC_MIN;
0154     rtc_tm->tm_sec  = v[0] & DA9055_RTC_SEC;
0155 
0156     return 0;
0157 }
0158 
0159 static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm)
0160 {
0161     struct da9055_rtc *rtc;
0162     uint8_t v[6];
0163 
0164     rtc = dev_get_drvdata(dev);
0165 
0166     v[0] = tm->tm_sec;
0167     v[1] = tm->tm_min;
0168     v[2] = tm->tm_hour;
0169     v[3] = tm->tm_mday;
0170     v[4] = tm->tm_mon + 1;
0171     v[5] = tm->tm_year - 100;
0172 
0173     return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
0174 }
0175 
0176 static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
0177 {
0178     int ret;
0179     struct rtc_time *tm = &alrm->time;
0180     struct da9055_rtc *rtc = dev_get_drvdata(dev);
0181 
0182     ret = da9055_read_alarm(rtc->da9055, tm);
0183 
0184     if (ret)
0185         return ret;
0186 
0187     alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055);
0188 
0189     return 0;
0190 }
0191 
0192 static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
0193 {
0194     int ret;
0195     struct rtc_time *tm = &alrm->time;
0196     struct da9055_rtc *rtc = dev_get_drvdata(dev);
0197 
0198     ret = da9055_rtc_enable_alarm(rtc, 0);
0199     if (ret < 0)
0200         return ret;
0201 
0202     ret = da9055_set_alarm(rtc->da9055, tm);
0203     if (ret)
0204         return ret;
0205 
0206     ret = da9055_rtc_enable_alarm(rtc, 1);
0207 
0208     return ret;
0209 }
0210 
0211 static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
0212 {
0213     struct da9055_rtc *rtc = dev_get_drvdata(dev);
0214 
0215     return da9055_rtc_enable_alarm(rtc, enabled);
0216 }
0217 
0218 static const struct rtc_class_ops da9055_rtc_ops = {
0219     .read_time  = da9055_rtc_read_time,
0220     .set_time   = da9055_rtc_set_time,
0221     .read_alarm = da9055_rtc_read_alarm,
0222     .set_alarm  = da9055_rtc_set_alarm,
0223     .alarm_irq_enable = da9055_rtc_alarm_irq_enable,
0224 };
0225 
0226 static int da9055_rtc_device_init(struct da9055 *da9055,
0227                     struct da9055_pdata *pdata)
0228 {
0229     int ret;
0230 
0231     /* Enable RTC and the internal Crystal */
0232     ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
0233                 DA9055_RTC_EN, DA9055_RTC_EN);
0234     if (ret < 0)
0235         return ret;
0236     ret = da9055_reg_update(da9055, DA9055_REG_EN_32K,
0237                 DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN);
0238     if (ret < 0)
0239         return ret;
0240 
0241     /* Enable RTC in Power Down mode */
0242     ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
0243                 DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD);
0244     if (ret < 0)
0245         return ret;
0246 
0247     /* Enable RTC in Reset mode */
0248     if (pdata && pdata->reset_enable) {
0249         ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
0250                     DA9055_RTC_MODE_SD,
0251                     DA9055_RTC_MODE_SD <<
0252                     DA9055_RTC_MODE_SD_SHIFT);
0253         if (ret < 0)
0254             return ret;
0255     }
0256 
0257     /* Disable the RTC TICK ALM */
0258     ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
0259                 DA9055_RTC_TICK_WAKE_MASK, 0);
0260     if (ret < 0)
0261         return ret;
0262 
0263     return 0;
0264 }
0265 
0266 static int da9055_rtc_probe(struct platform_device *pdev)
0267 {
0268     struct da9055_rtc *rtc;
0269     struct da9055_pdata *pdata = NULL;
0270     int ret, alm_irq;
0271 
0272     rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL);
0273     if (!rtc)
0274         return -ENOMEM;
0275 
0276     rtc->da9055 = dev_get_drvdata(pdev->dev.parent);
0277     pdata = dev_get_platdata(rtc->da9055->dev);
0278     platform_set_drvdata(pdev, rtc);
0279 
0280     ret = da9055_rtc_device_init(rtc->da9055, pdata);
0281     if (ret < 0)
0282         goto err_rtc;
0283 
0284     ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y);
0285     if (ret < 0)
0286         goto err_rtc;
0287 
0288     if (ret & DA9055_RTC_ALM_EN)
0289         rtc->alarm_enable = 1;
0290 
0291     device_init_wakeup(&pdev->dev, 1);
0292 
0293     rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
0294                     &da9055_rtc_ops, THIS_MODULE);
0295     if (IS_ERR(rtc->rtc)) {
0296         ret = PTR_ERR(rtc->rtc);
0297         goto err_rtc;
0298     }
0299 
0300     alm_irq = platform_get_irq_byname(pdev, "ALM");
0301     if (alm_irq < 0)
0302         return alm_irq;
0303 
0304     ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
0305                     da9055_rtc_alm_irq,
0306                     IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
0307                     "ALM", rtc);
0308     if (ret != 0)
0309         dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret);
0310 
0311 err_rtc:
0312     return ret;
0313 
0314 }
0315 
0316 #ifdef CONFIG_PM
0317 /* Turn off the alarm if it should not be a wake source. */
0318 static int da9055_rtc_suspend(struct device *dev)
0319 {
0320     struct platform_device *pdev = to_platform_device(dev);
0321     struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
0322     int ret;
0323 
0324     if (!device_may_wakeup(&pdev->dev)) {
0325         /* Disable the ALM IRQ */
0326         ret = da9055_rtc_enable_alarm(rtc, 0);
0327         if (ret < 0)
0328             dev_err(&pdev->dev, "Failed to disable RTC ALM\n");
0329     }
0330 
0331     return 0;
0332 }
0333 
0334 /* Enable the alarm if it should be enabled (in case it was disabled to
0335  * prevent use as a wake source).
0336  */
0337 static int da9055_rtc_resume(struct device *dev)
0338 {
0339     struct platform_device *pdev = to_platform_device(dev);
0340     struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
0341     int ret;
0342 
0343     if (!device_may_wakeup(&pdev->dev)) {
0344         if (rtc->alarm_enable) {
0345             ret = da9055_rtc_enable_alarm(rtc, 1);
0346             if (ret < 0)
0347                 dev_err(&pdev->dev,
0348                     "Failed to restart RTC ALM\n");
0349         }
0350     }
0351 
0352     return 0;
0353 }
0354 
0355 /* Unconditionally disable the alarm */
0356 static int da9055_rtc_freeze(struct device *dev)
0357 {
0358     struct platform_device *pdev = to_platform_device(dev);
0359     struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
0360     int ret;
0361 
0362     ret = da9055_rtc_enable_alarm(rtc, 0);
0363     if (ret < 0)
0364         dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n");
0365 
0366     return 0;
0367 
0368 }
0369 #else
0370 #define da9055_rtc_suspend NULL
0371 #define da9055_rtc_resume NULL
0372 #define da9055_rtc_freeze NULL
0373 #endif
0374 
0375 static const struct dev_pm_ops da9055_rtc_pm_ops = {
0376     .suspend = da9055_rtc_suspend,
0377     .resume = da9055_rtc_resume,
0378 
0379     .freeze = da9055_rtc_freeze,
0380     .thaw = da9055_rtc_resume,
0381     .restore = da9055_rtc_resume,
0382 
0383     .poweroff = da9055_rtc_suspend,
0384 };
0385 
0386 static struct platform_driver da9055_rtc_driver = {
0387     .probe  = da9055_rtc_probe,
0388     .driver = {
0389         .name   = "da9055-rtc",
0390         .pm = &da9055_rtc_pm_ops,
0391     },
0392 };
0393 
0394 module_platform_driver(da9055_rtc_driver);
0395 
0396 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
0397 MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC");
0398 MODULE_LICENSE("GPL");
0399 MODULE_ALIAS("platform:da9055-rtc");