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 19 #include <linux/mfd/da9052/da9052.h> 20 #include <linux/mfd/da9052/reg.h> 21 22 #define rtc_err(da9052, fmt, ...) \ 23 dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) 24 25 struct da9052_rtc { 26 struct rtc_device *rtc; 27 struct da9052 *da9052; 28 int irq; 29 }; 30 31 static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable) 32 { 33 int ret; 34 if (enable) { 35 ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, 36 DA9052_ALARM_Y_ALARM_ON, 37 DA9052_ALARM_Y_ALARM_ON); 38 if (ret != 0) 39 rtc_err(da9052, "Failed to enable ALM: %d\n", ret); 40 } else { 41 ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, 42 DA9052_ALARM_Y_ALARM_ON, 0); 43 if (ret != 0) 44 rtc_err(da9052, "Write error: %d\n", ret); 45 } 46 return ret; 47 } 48 49 static irqreturn_t da9052_rtc_irq(int irq, void *data) 50 { 51 struct da9052_rtc *rtc = data; 52 int ret; 53 54 ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG); 55 if (ret < 0) { 56 rtc_err(rtc->da9052, "Read error: %d\n", ret); 57 return IRQ_NONE; 58 } 59 60 if (ret & DA9052_ALARMMI_ALARMTYPE) { 61 da9052_rtc_enable_alarm(rtc->da9052, 0); 62 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); 63 } else 64 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF); 65 66 return IRQ_HANDLED; 67 } 68 69 static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) 70 { 71 int ret; 72 uint8_t v[5]; 73 74 ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v); 75 if (ret != 0) { 76 rtc_err(da9052, "Failed to group read ALM: %d\n", ret); 77 return ret; 78 } 79 80 rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100; 81 rtc_tm->tm_mon = (v[3] & DA9052_RTC_MONTH) - 1; 82 rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY; 83 rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR; 84 rtc_tm->tm_min = v[0] & DA9052_RTC_MIN; 85 86 ret = rtc_valid_tm(rtc_tm); 87 if (ret != 0) 88 return ret; 89 return ret; 90 } 91 92 static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) 93 { 94 int ret; 95 uint8_t v[3]; 96 97 rtc_tm->tm_year -= 100; 98 rtc_tm->tm_mon += 1; 99 100 ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG, 101 DA9052_RTC_MIN, rtc_tm->tm_min); 102 if (ret != 0) { 103 rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret); 104 return ret; 105 } 106 107 v[0] = rtc_tm->tm_hour; 108 v[1] = rtc_tm->tm_mday; 109 v[2] = rtc_tm->tm_mon; 110 111 ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v); 112 if (ret < 0) 113 return ret; 114 115 ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, 116 DA9052_RTC_YEAR, rtc_tm->tm_year); 117 if (ret != 0) 118 rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret); 119 120 return ret; 121 } 122 123 static int da9052_rtc_get_alarm_status(struct da9052 *da9052) 124 { 125 int ret; 126 127 ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG); 128 if (ret < 0) { 129 rtc_err(da9052, "Failed to read ALM: %d\n", ret); 130 return ret; 131 } 132 ret &= DA9052_ALARM_Y_ALARM_ON; 133 return (ret > 0) ? 1 : 0; 134 } 135 136 static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) 137 { 138 struct da9052_rtc *rtc = dev_get_drvdata(dev); 139 uint8_t v[6]; 140 int ret; 141 142 ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v); 143 if (ret < 0) { 144 rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret); 145 return ret; 146 } 147 148 rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100; 149 rtc_tm->tm_mon = (v[4] & DA9052_RTC_MONTH) - 1; 150 rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY; 151 rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR; 152 rtc_tm->tm_min = v[1] & DA9052_RTC_MIN; 153 rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC; 154 155 ret = rtc_valid_tm(rtc_tm); 156 if (ret != 0) { 157 rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret); 158 return ret; 159 } 160 161 return 0; 162 } 163 164 static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm) 165 { 166 struct da9052_rtc *rtc; 167 uint8_t v[6]; 168 169 rtc = dev_get_drvdata(dev); 170 171 v[0] = tm->tm_sec; 172 v[1] = tm->tm_min; 173 v[2] = tm->tm_hour; 174 v[3] = tm->tm_mday; 175 v[4] = tm->tm_mon + 1; 176 v[5] = tm->tm_year - 100; 177 178 return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); 179 } 180 181 static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 182 { 183 int ret; 184 struct rtc_time *tm = &alrm->time; 185 struct da9052_rtc *rtc = dev_get_drvdata(dev); 186 187 ret = da9052_read_alarm(rtc->da9052, tm); 188 189 if (ret) 190 return ret; 191 192 alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052); 193 194 return 0; 195 } 196 197 static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 198 { 199 int ret; 200 struct rtc_time *tm = &alrm->time; 201 struct da9052_rtc *rtc = dev_get_drvdata(dev); 202 203 ret = da9052_rtc_enable_alarm(rtc->da9052, 0); 204 if (ret < 0) 205 return ret; 206 207 ret = da9052_set_alarm(rtc->da9052, tm); 208 if (ret) 209 return ret; 210 211 ret = da9052_rtc_enable_alarm(rtc->da9052, 1); 212 213 return ret; 214 } 215 216 static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 217 { 218 struct da9052_rtc *rtc = dev_get_drvdata(dev); 219 220 return da9052_rtc_enable_alarm(rtc->da9052, enabled); 221 } 222 223 static const struct rtc_class_ops da9052_rtc_ops = { 224 .read_time = da9052_rtc_read_time, 225 .set_time = da9052_rtc_set_time, 226 .read_alarm = da9052_rtc_read_alarm, 227 .set_alarm = da9052_rtc_set_alarm, 228 .alarm_irq_enable = da9052_rtc_alarm_irq_enable, 229 }; 230 231 static int __devinit da9052_rtc_probe(struct platform_device *pdev) 232 { 233 struct da9052_rtc *rtc; 234 int ret; 235 236 rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL); 237 if (!rtc) 238 return -ENOMEM; 239 240 rtc->da9052 = dev_get_drvdata(pdev->dev.parent); 241 platform_set_drvdata(pdev, rtc); 242 rtc->irq = platform_get_irq_byname(pdev, "ALM"); 243 ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq, 244 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 245 "ALM", rtc); 246 if (ret != 0) { 247 rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); 248 return ret; 249 } 250 251 rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, 252 &da9052_rtc_ops, THIS_MODULE); 253 if (IS_ERR(rtc->rtc)) { 254 ret = PTR_ERR(rtc->rtc); 255 goto err_free_irq; 256 } 257 258 return 0; 259 260 err_free_irq: 261 free_irq(rtc->irq, rtc); 262 return ret; 263 } 264 265 static int __devexit da9052_rtc_remove(struct platform_device *pdev) 266 { 267 struct da9052_rtc *rtc = pdev->dev.platform_data; 268 269 rtc_device_unregister(rtc->rtc); 270 free_irq(rtc->irq, rtc); 271 platform_set_drvdata(pdev, NULL); 272 273 return 0; 274 } 275 276 static struct platform_driver da9052_rtc_driver = { 277 .probe = da9052_rtc_probe, 278 .remove = __devexit_p(da9052_rtc_remove), 279 .driver = { 280 .name = "da9052-rtc", 281 .owner = THIS_MODULE, 282 }, 283 }; 284 285 module_platform_driver(da9052_rtc_driver); 286 287 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 288 MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC"); 289 MODULE_LICENSE("GPL"); 290 MODULE_ALIAS("platform:da9052-rtc"); 291