1 /* 2 * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs 3 * 4 * Copyright (C) 2013 ams AG 5 * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. 6 * 7 * Author: Florian Lobmaier <florian.lobmaier@ams.com> 8 * Author: Laxman Dewangan <ldewangan@nvidia.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 #include <linux/bcd.h> 22 #include <linux/completion.h> 23 #include <linux/delay.h> 24 #include <linux/interrupt.h> 25 #include <linux/ioctl.h> 26 #include <linux/kernel.h> 27 #include <linux/module.h> 28 #include <linux/mfd/as3722.h> 29 #include <linux/platform_device.h> 30 #include <linux/rtc.h> 31 #include <linux/time.h> 32 33 #define AS3722_RTC_START_YEAR 2000 34 struct as3722_rtc { 35 struct rtc_device *rtc; 36 struct device *dev; 37 struct as3722 *as3722; 38 int alarm_irq; 39 bool irq_enable; 40 }; 41 42 static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) 43 { 44 rbuff[0] = bin2bcd(tm->tm_sec); 45 rbuff[1] = bin2bcd(tm->tm_min); 46 rbuff[2] = bin2bcd(tm->tm_hour); 47 rbuff[3] = bin2bcd(tm->tm_mday); 48 rbuff[4] = bin2bcd(tm->tm_mon); 49 rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); 50 } 51 52 static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) 53 { 54 tm->tm_sec = bcd2bin(rbuff[0] & 0x7F); 55 tm->tm_min = bcd2bin(rbuff[1] & 0x7F); 56 tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); 57 tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); 58 tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); 59 tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); 60 return; 61 } 62 63 static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm) 64 { 65 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 66 struct as3722 *as3722 = as3722_rtc->as3722; 67 u8 as_time_array[6]; 68 int ret; 69 70 ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG, 71 6, as_time_array); 72 if (ret < 0) { 73 dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret); 74 return ret; 75 } 76 as3722_reg_to_time(as_time_array, tm); 77 return 0; 78 } 79 80 static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm) 81 { 82 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 83 struct as3722 *as3722 = as3722_rtc->as3722; 84 u8 as_time_array[6]; 85 int ret; 86 87 if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900)) 88 return -EINVAL; 89 90 as3722_time_to_reg(as_time_array, tm); 91 ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6, 92 as_time_array); 93 if (ret < 0) 94 dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret); 95 return ret; 96 } 97 98 static int as3722_rtc_alarm_irq_enable(struct device *dev, 99 unsigned int enabled) 100 { 101 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 102 103 if (enabled && !as3722_rtc->irq_enable) { 104 enable_irq(as3722_rtc->alarm_irq); 105 as3722_rtc->irq_enable = true; 106 } else if (!enabled && as3722_rtc->irq_enable) { 107 disable_irq(as3722_rtc->alarm_irq); 108 as3722_rtc->irq_enable = false; 109 } 110 return 0; 111 } 112 113 static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 114 { 115 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 116 struct as3722 *as3722 = as3722_rtc->as3722; 117 u8 as_time_array[6]; 118 int ret; 119 120 ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, 121 as_time_array); 122 if (ret < 0) { 123 dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret); 124 return ret; 125 } 126 127 as3722_reg_to_time(as_time_array, &alrm->time); 128 return 0; 129 } 130 131 static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 132 { 133 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 134 struct as3722 *as3722 = as3722_rtc->as3722; 135 u8 as_time_array[6]; 136 int ret; 137 138 if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900)) 139 return -EINVAL; 140 141 ret = as3722_rtc_alarm_irq_enable(dev, 0); 142 if (ret < 0) { 143 dev_err(dev, "Disable RTC alarm failed\n"); 144 return ret; 145 } 146 147 as3722_time_to_reg(as_time_array, &alrm->time); 148 ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, 149 as_time_array); 150 if (ret < 0) { 151 dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret); 152 return ret; 153 } 154 155 if (alrm->enabled) 156 ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled); 157 return ret; 158 } 159 160 static irqreturn_t as3722_alarm_irq(int irq, void *data) 161 { 162 struct as3722_rtc *as3722_rtc = data; 163 164 rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF); 165 return IRQ_HANDLED; 166 } 167 168 static const struct rtc_class_ops as3722_rtc_ops = { 169 .read_time = as3722_rtc_read_time, 170 .set_time = as3722_rtc_set_time, 171 .read_alarm = as3722_rtc_read_alarm, 172 .set_alarm = as3722_rtc_set_alarm, 173 .alarm_irq_enable = as3722_rtc_alarm_irq_enable, 174 }; 175 176 static int as3722_rtc_probe(struct platform_device *pdev) 177 { 178 struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); 179 struct as3722_rtc *as3722_rtc; 180 int ret; 181 182 as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL); 183 if (!as3722_rtc) 184 return -ENOMEM; 185 186 as3722_rtc->as3722 = as3722; 187 as3722_rtc->dev = &pdev->dev; 188 platform_set_drvdata(pdev, as3722_rtc); 189 190 /* Enable the RTC to make sure it is running. */ 191 ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG, 192 AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN, 193 AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN); 194 if (ret < 0) { 195 dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret); 196 return ret; 197 } 198 199 device_init_wakeup(&pdev->dev, 1); 200 201 as3722_rtc->rtc = rtc_device_register("as3722", &pdev->dev, 202 &as3722_rtc_ops, THIS_MODULE); 203 if (IS_ERR(as3722_rtc->rtc)) { 204 ret = PTR_ERR(as3722_rtc->rtc); 205 dev_err(&pdev->dev, "RTC register failed: %d\n", ret); 206 return ret; 207 } 208 209 as3722_rtc->alarm_irq = platform_get_irq(pdev, 0); 210 dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); 211 212 ret = request_threaded_irq(as3722_rtc->alarm_irq, NULL, 213 as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, 214 "rtc-alarm", as3722_rtc); 215 if (ret < 0) { 216 dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", 217 as3722_rtc->alarm_irq, ret); 218 goto scrub; 219 } 220 disable_irq(as3722_rtc->alarm_irq); 221 return 0; 222 scrub: 223 rtc_device_unregister(as3722_rtc->rtc); 224 return ret; 225 } 226 227 static int as3722_rtc_remove(struct platform_device *pdev) 228 { 229 struct as3722_rtc *as3722_rtc = platform_get_drvdata(pdev); 230 231 free_irq(as3722_rtc->alarm_irq, as3722_rtc); 232 rtc_device_unregister(as3722_rtc->rtc); 233 return 0; 234 } 235 236 #ifdef CONFIG_PM_SLEEP 237 static int as3722_rtc_suspend(struct device *dev) 238 { 239 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 240 241 if (device_may_wakeup(dev)) 242 enable_irq_wake(as3722_rtc->alarm_irq); 243 244 return 0; 245 } 246 247 static int as3722_rtc_resume(struct device *dev) 248 { 249 struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); 250 251 if (device_may_wakeup(dev)) 252 disable_irq_wake(as3722_rtc->alarm_irq); 253 return 0; 254 } 255 #endif 256 257 static const struct dev_pm_ops as3722_rtc_pm_ops = { 258 SET_SYSTEM_SLEEP_PM_OPS(as3722_rtc_suspend, as3722_rtc_resume) 259 }; 260 261 static struct platform_driver as3722_rtc_driver = { 262 .probe = as3722_rtc_probe, 263 .remove = as3722_rtc_remove, 264 .driver = { 265 .name = "as3722-rtc", 266 .pm = &as3722_rtc_pm_ops, 267 }, 268 }; 269 module_platform_driver(as3722_rtc_driver); 270 271 MODULE_DESCRIPTION("RTC driver for AS3722 PMICs"); 272 MODULE_ALIAS("platform:as3722-rtc"); 273 MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); 274 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 275 MODULE_LICENSE("GPL"); 276