1/* 2 * Real time clock driver for DA9055 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 19#include <linux/mfd/da9055/core.h> 20#include <linux/mfd/da9055/reg.h> 21#include <linux/mfd/da9055/pdata.h> 22 23struct da9055_rtc { 24 struct rtc_device *rtc; 25 struct da9055 *da9055; 26 int alarm_enable; 27}; 28 29static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable) 30{ 31 int ret; 32 if (enable) { 33 ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, 34 DA9055_RTC_ALM_EN, 35 DA9055_RTC_ALM_EN); 36 if (ret != 0) 37 dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n", 38 ret); 39 rtc->alarm_enable = 1; 40 } else { 41 ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, 42 DA9055_RTC_ALM_EN, 0); 43 if (ret != 0) 44 dev_err(rtc->da9055->dev, 45 "Failed to disable ALM: %d\n", ret); 46 rtc->alarm_enable = 0; 47 } 48 return ret; 49} 50 51static irqreturn_t da9055_rtc_alm_irq(int irq, void *data) 52{ 53 struct da9055_rtc *rtc = data; 54 55 da9055_rtc_enable_alarm(rtc, 0); 56 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); 57 58 return IRQ_HANDLED; 59} 60 61static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) 62{ 63 int ret; 64 uint8_t v[5]; 65 66 ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v); 67 if (ret != 0) { 68 dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret); 69 return ret; 70 } 71 72 rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100; 73 rtc_tm->tm_mon = (v[3] & DA9055_RTC_ALM_MONTH) - 1; 74 rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY; 75 rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR; 76 rtc_tm->tm_min = v[0] & DA9055_RTC_ALM_MIN; 77 78 return rtc_valid_tm(rtc_tm); 79} 80 81static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) 82{ 83 int ret; 84 uint8_t v[2]; 85 86 rtc_tm->tm_year -= 100; 87 rtc_tm->tm_mon += 1; 88 89 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI, 90 DA9055_RTC_ALM_MIN, rtc_tm->tm_min); 91 if (ret != 0) { 92 dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret); 93 return ret; 94 } 95 96 v[0] = rtc_tm->tm_hour; 97 v[1] = rtc_tm->tm_mday; 98 99 ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v); 100 if (ret < 0) 101 return ret; 102 103 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, 104 DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon); 105 if (ret < 0) 106 dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret); 107 108 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y, 109 DA9055_RTC_ALM_YEAR, rtc_tm->tm_year); 110 if (ret < 0) 111 dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret); 112 113 return ret; 114} 115 116static int da9055_rtc_get_alarm_status(struct da9055 *da9055) 117{ 118 int ret; 119 120 ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y); 121 if (ret < 0) { 122 dev_err(da9055->dev, "Failed to read ALM: %d\n", ret); 123 return ret; 124 } 125 ret &= DA9055_RTC_ALM_EN; 126 return (ret > 0) ? 1 : 0; 127} 128 129static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) 130{ 131 struct da9055_rtc *rtc = dev_get_drvdata(dev); 132 uint8_t v[6]; 133 int ret; 134 135 ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S); 136 if (ret < 0) 137 return ret; 138 139 /* 140 * Registers are only valid when RTC_READ 141 * status bit is asserted 142 */ 143 if (!(ret & DA9055_RTC_READ)) 144 return -EBUSY; 145 146 ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v); 147 if (ret < 0) { 148 dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n", 149 ret); 150 return ret; 151 } 152 153 rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100; 154 rtc_tm->tm_mon = (v[4] & DA9055_RTC_MONTH) - 1; 155 rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY; 156 rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR; 157 rtc_tm->tm_min = v[1] & DA9055_RTC_MIN; 158 rtc_tm->tm_sec = v[0] & DA9055_RTC_SEC; 159 160 return rtc_valid_tm(rtc_tm); 161} 162 163static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm) 164{ 165 struct da9055_rtc *rtc; 166 uint8_t v[6]; 167 168 rtc = dev_get_drvdata(dev); 169 170 v[0] = tm->tm_sec; 171 v[1] = tm->tm_min; 172 v[2] = tm->tm_hour; 173 v[3] = tm->tm_mday; 174 v[4] = tm->tm_mon + 1; 175 v[5] = tm->tm_year - 100; 176 177 return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v); 178} 179 180static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 181{ 182 int ret; 183 struct rtc_time *tm = &alrm->time; 184 struct da9055_rtc *rtc = dev_get_drvdata(dev); 185 186 ret = da9055_read_alarm(rtc->da9055, tm); 187 188 if (ret) 189 return ret; 190 191 alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055); 192 193 return 0; 194} 195 196static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 197{ 198 int ret; 199 struct rtc_time *tm = &alrm->time; 200 struct da9055_rtc *rtc = dev_get_drvdata(dev); 201 202 ret = da9055_rtc_enable_alarm(rtc, 0); 203 if (ret < 0) 204 return ret; 205 206 ret = da9055_set_alarm(rtc->da9055, tm); 207 if (ret) 208 return ret; 209 210 ret = da9055_rtc_enable_alarm(rtc, 1); 211 212 return ret; 213} 214 215static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 216{ 217 struct da9055_rtc *rtc = dev_get_drvdata(dev); 218 219 return da9055_rtc_enable_alarm(rtc, enabled); 220} 221 222static const struct rtc_class_ops da9055_rtc_ops = { 223 .read_time = da9055_rtc_read_time, 224 .set_time = da9055_rtc_set_time, 225 .read_alarm = da9055_rtc_read_alarm, 226 .set_alarm = da9055_rtc_set_alarm, 227 .alarm_irq_enable = da9055_rtc_alarm_irq_enable, 228}; 229 230static int da9055_rtc_device_init(struct da9055 *da9055, 231 struct da9055_pdata *pdata) 232{ 233 int ret; 234 235 /* Enable RTC and the internal Crystal */ 236 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, 237 DA9055_RTC_EN, DA9055_RTC_EN); 238 if (ret < 0) 239 return ret; 240 ret = da9055_reg_update(da9055, DA9055_REG_EN_32K, 241 DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN); 242 if (ret < 0) 243 return ret; 244 245 /* Enable RTC in Power Down mode */ 246 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, 247 DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD); 248 if (ret < 0) 249 return ret; 250 251 /* Enable RTC in Reset mode */ 252 if (pdata && pdata->reset_enable) { 253 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, 254 DA9055_RTC_MODE_SD, 255 DA9055_RTC_MODE_SD << 256 DA9055_RTC_MODE_SD_SHIFT); 257 if (ret < 0) 258 return ret; 259 } 260 261 /* Disable the RTC TICK ALM */ 262 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, 263 DA9055_RTC_TICK_WAKE_MASK, 0); 264 if (ret < 0) 265 return ret; 266 267 return 0; 268} 269 270static int da9055_rtc_probe(struct platform_device *pdev) 271{ 272 struct da9055_rtc *rtc; 273 struct da9055_pdata *pdata = NULL; 274 int ret, alm_irq; 275 276 rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL); 277 if (!rtc) 278 return -ENOMEM; 279 280 rtc->da9055 = dev_get_drvdata(pdev->dev.parent); 281 pdata = dev_get_platdata(rtc->da9055->dev); 282 platform_set_drvdata(pdev, rtc); 283 284 ret = da9055_rtc_device_init(rtc->da9055, pdata); 285 if (ret < 0) 286 goto err_rtc; 287 288 ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y); 289 if (ret < 0) 290 goto err_rtc; 291 292 if (ret & DA9055_RTC_ALM_EN) 293 rtc->alarm_enable = 1; 294 295 device_init_wakeup(&pdev->dev, 1); 296 297 rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 298 &da9055_rtc_ops, THIS_MODULE); 299 if (IS_ERR(rtc->rtc)) { 300 ret = PTR_ERR(rtc->rtc); 301 goto err_rtc; 302 } 303 304 alm_irq = platform_get_irq_byname(pdev, "ALM"); 305 if (alm_irq < 0) 306 return alm_irq; 307 308 ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, 309 da9055_rtc_alm_irq, 310 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 311 "ALM", rtc); 312 if (ret != 0) 313 dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret); 314 315err_rtc: 316 return ret; 317 318} 319 320#ifdef CONFIG_PM 321/* Turn off the alarm if it should not be a wake source. */ 322static int da9055_rtc_suspend(struct device *dev) 323{ 324 struct platform_device *pdev = to_platform_device(dev); 325 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); 326 int ret; 327 328 if (!device_may_wakeup(&pdev->dev)) { 329 /* Disable the ALM IRQ */ 330 ret = da9055_rtc_enable_alarm(rtc, 0); 331 if (ret < 0) 332 dev_err(&pdev->dev, "Failed to disable RTC ALM\n"); 333 } 334 335 return 0; 336} 337 338/* Enable the alarm if it should be enabled (in case it was disabled to 339 * prevent use as a wake source). 340 */ 341static int da9055_rtc_resume(struct device *dev) 342{ 343 struct platform_device *pdev = to_platform_device(dev); 344 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); 345 int ret; 346 347 if (!device_may_wakeup(&pdev->dev)) { 348 if (rtc->alarm_enable) { 349 ret = da9055_rtc_enable_alarm(rtc, 1); 350 if (ret < 0) 351 dev_err(&pdev->dev, 352 "Failed to restart RTC ALM\n"); 353 } 354 } 355 356 return 0; 357} 358 359/* Unconditionally disable the alarm */ 360static int da9055_rtc_freeze(struct device *dev) 361{ 362 struct platform_device *pdev = to_platform_device(dev); 363 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); 364 int ret; 365 366 ret = da9055_rtc_enable_alarm(rtc, 0); 367 if (ret < 0) 368 dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n"); 369 370 return 0; 371 372} 373#else 374#define da9055_rtc_suspend NULL 375#define da9055_rtc_resume NULL 376#define da9055_rtc_freeze NULL 377#endif 378 379static const struct dev_pm_ops da9055_rtc_pm_ops = { 380 .suspend = da9055_rtc_suspend, 381 .resume = da9055_rtc_resume, 382 383 .freeze = da9055_rtc_freeze, 384 .thaw = da9055_rtc_resume, 385 .restore = da9055_rtc_resume, 386 387 .poweroff = da9055_rtc_suspend, 388}; 389 390static struct platform_driver da9055_rtc_driver = { 391 .probe = da9055_rtc_probe, 392 .driver = { 393 .name = "da9055-rtc", 394 .pm = &da9055_rtc_pm_ops, 395 }, 396}; 397 398module_platform_driver(da9055_rtc_driver); 399 400MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 401MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC"); 402MODULE_LICENSE("GPL"); 403MODULE_ALIAS("platform:da9055-rtc"); 404