Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc7 331 lines 8.5 kB view raw
1/* 2 * Motorola CPCAP PMIC RTC driver 3 * 4 * Based on cpcap-regulator.c from Motorola Linux kernel tree 5 * Copyright (C) 2009 Motorola, Inc. 6 * 7 * Rewritten for mainline kernel 8 * - use DT 9 * - use regmap 10 * - use standard interrupt framework 11 * - use managed device resources 12 * - remove custom "secure clock daemon" helpers 13 * 14 * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org> 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License version 2 as 18 * published by the Free Software Foundation. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 */ 25#include <linux/kernel.h> 26#include <linux/module.h> 27#include <linux/mod_devicetable.h> 28#include <linux/init.h> 29#include <linux/device.h> 30#include <linux/platform_device.h> 31#include <linux/rtc.h> 32#include <linux/err.h> 33#include <linux/regmap.h> 34#include <linux/mfd/motorola-cpcap.h> 35#include <linux/slab.h> 36#include <linux/sched.h> 37 38#define SECS_PER_DAY 86400 39#define DAY_MASK 0x7FFF 40#define TOD1_MASK 0x00FF 41#define TOD2_MASK 0x01FF 42 43struct cpcap_time { 44 int day; 45 int tod1; 46 int tod2; 47}; 48 49struct cpcap_rtc { 50 struct regmap *regmap; 51 struct rtc_device *rtc_dev; 52 u16 vendor; 53 int alarm_irq; 54 bool alarm_enabled; 55 int update_irq; 56 bool update_enabled; 57}; 58 59static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap) 60{ 61 unsigned long int tod; 62 unsigned long int time; 63 64 tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8); 65 time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY); 66 67 rtc_time_to_tm(time, rtc); 68} 69 70static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc) 71{ 72 unsigned long time; 73 74 rtc_tm_to_time(rtc, &time); 75 76 cpcap->day = time / SECS_PER_DAY; 77 time %= SECS_PER_DAY; 78 cpcap->tod2 = (time >> 8) & TOD2_MASK; 79 cpcap->tod1 = time & TOD1_MASK; 80} 81 82static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 83{ 84 struct cpcap_rtc *rtc = dev_get_drvdata(dev); 85 86 if (rtc->alarm_enabled == enabled) 87 return 0; 88 89 if (enabled) 90 enable_irq(rtc->alarm_irq); 91 else 92 disable_irq(rtc->alarm_irq); 93 94 rtc->alarm_enabled = !!enabled; 95 96 return 0; 97} 98 99static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm) 100{ 101 struct cpcap_rtc *rtc; 102 struct cpcap_time cpcap_tm; 103 int temp_tod2; 104 int ret; 105 106 rtc = dev_get_drvdata(dev); 107 108 ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2); 109 ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day); 110 ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1); 111 ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2); 112 113 if (temp_tod2 > cpcap_tm.tod2) 114 ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day); 115 116 if (ret) { 117 dev_err(dev, "Failed to read time\n"); 118 return -EIO; 119 } 120 121 cpcap2rtc_time(tm, &cpcap_tm); 122 123 return 0; 124} 125 126static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm) 127{ 128 struct cpcap_rtc *rtc; 129 struct cpcap_time cpcap_tm; 130 int ret = 0; 131 132 rtc = dev_get_drvdata(dev); 133 134 rtc2cpcap_time(&cpcap_tm, tm); 135 136 if (rtc->alarm_enabled) 137 disable_irq(rtc->alarm_irq); 138 if (rtc->update_enabled) 139 disable_irq(rtc->update_irq); 140 141 if (rtc->vendor == CPCAP_VENDOR_ST) { 142 /* The TOD1 and TOD2 registers MUST be written in this order 143 * for the change to properly set. 144 */ 145 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1, 146 TOD1_MASK, cpcap_tm.tod1); 147 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2, 148 TOD2_MASK, cpcap_tm.tod2); 149 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY, 150 DAY_MASK, cpcap_tm.day); 151 } else { 152 /* Clearing the upper lower 8 bits of the TOD guarantees that 153 * the upper half of TOD (TOD2) will not increment for 0xFF RTC 154 * ticks (255 seconds). During this time we can safely write 155 * to DAY, TOD2, then TOD1 (in that order) and expect RTC to be 156 * synchronized to the exact time requested upon the final write 157 * to TOD1. 158 */ 159 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1, 160 TOD1_MASK, 0); 161 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY, 162 DAY_MASK, cpcap_tm.day); 163 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2, 164 TOD2_MASK, cpcap_tm.tod2); 165 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1, 166 TOD1_MASK, cpcap_tm.tod1); 167 } 168 169 if (rtc->update_enabled) 170 enable_irq(rtc->update_irq); 171 if (rtc->alarm_enabled) 172 enable_irq(rtc->alarm_irq); 173 174 return ret; 175} 176 177static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 178{ 179 struct cpcap_rtc *rtc; 180 struct cpcap_time cpcap_tm; 181 int ret; 182 183 rtc = dev_get_drvdata(dev); 184 185 alrm->enabled = rtc->alarm_enabled; 186 187 ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day); 188 ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2); 189 ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1); 190 191 if (ret) { 192 dev_err(dev, "Failed to read time\n"); 193 return -EIO; 194 } 195 196 cpcap2rtc_time(&alrm->time, &cpcap_tm); 197 return rtc_valid_tm(&alrm->time); 198} 199 200static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 201{ 202 struct cpcap_rtc *rtc; 203 struct cpcap_time cpcap_tm; 204 int ret; 205 206 rtc = dev_get_drvdata(dev); 207 208 rtc2cpcap_time(&cpcap_tm, &alrm->time); 209 210 if (rtc->alarm_enabled) 211 disable_irq(rtc->alarm_irq); 212 213 ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK, 214 cpcap_tm.day); 215 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK, 216 cpcap_tm.tod2); 217 ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK, 218 cpcap_tm.tod1); 219 220 if (!ret) { 221 enable_irq(rtc->alarm_irq); 222 rtc->alarm_enabled = true; 223 } 224 225 return ret; 226} 227 228static const struct rtc_class_ops cpcap_rtc_ops = { 229 .read_time = cpcap_rtc_read_time, 230 .set_time = cpcap_rtc_set_time, 231 .read_alarm = cpcap_rtc_read_alarm, 232 .set_alarm = cpcap_rtc_set_alarm, 233 .alarm_irq_enable = cpcap_rtc_alarm_irq_enable, 234}; 235 236static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data) 237{ 238 struct cpcap_rtc *rtc = data; 239 240 rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); 241 return IRQ_HANDLED; 242} 243 244static irqreturn_t cpcap_rtc_update_irq(int irq, void *data) 245{ 246 struct cpcap_rtc *rtc = data; 247 248 rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); 249 return IRQ_HANDLED; 250} 251 252static int cpcap_rtc_probe(struct platform_device *pdev) 253{ 254 struct device *dev = &pdev->dev; 255 struct cpcap_rtc *rtc; 256 int err; 257 258 rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); 259 if (!rtc) 260 return -ENOMEM; 261 262 rtc->regmap = dev_get_regmap(dev->parent, NULL); 263 if (!rtc->regmap) 264 return -ENODEV; 265 266 platform_set_drvdata(pdev, rtc); 267 rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc", 268 &cpcap_rtc_ops, THIS_MODULE); 269 270 if (IS_ERR(rtc->rtc_dev)) 271 return PTR_ERR(rtc->rtc_dev); 272 273 err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor); 274 if (err) 275 return err; 276 277 rtc->alarm_irq = platform_get_irq(pdev, 0); 278 err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL, 279 cpcap_rtc_alarm_irq, IRQF_TRIGGER_NONE, 280 "rtc_alarm", rtc); 281 if (err) { 282 dev_err(dev, "Could not request alarm irq: %d\n", err); 283 return err; 284 } 285 disable_irq(rtc->alarm_irq); 286 287 /* Stock Android uses the 1 Hz interrupt for "secure clock daemon", 288 * which is not supported by the mainline kernel. The mainline kernel 289 * does not use the irq at the moment, but we explicitly request and 290 * disable it, so that its masked and does not wake up the processor 291 * every second. 292 */ 293 rtc->update_irq = platform_get_irq(pdev, 1); 294 err = devm_request_threaded_irq(dev, rtc->update_irq, NULL, 295 cpcap_rtc_update_irq, IRQF_TRIGGER_NONE, 296 "rtc_1hz", rtc); 297 if (err) { 298 dev_err(dev, "Could not request update irq: %d\n", err); 299 return err; 300 } 301 disable_irq(rtc->update_irq); 302 303 err = device_init_wakeup(dev, 1); 304 if (err) { 305 dev_err(dev, "wakeup initialization failed (%d)\n", err); 306 /* ignore error and continue without wakeup support */ 307 } 308 309 return 0; 310} 311 312static const struct of_device_id cpcap_rtc_of_match[] = { 313 { .compatible = "motorola,cpcap-rtc", }, 314 {}, 315}; 316MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match); 317 318static struct platform_driver cpcap_rtc_driver = { 319 .probe = cpcap_rtc_probe, 320 .driver = { 321 .name = "cpcap-rtc", 322 .of_match_table = cpcap_rtc_of_match, 323 }, 324}; 325 326module_platform_driver(cpcap_rtc_driver); 327 328MODULE_ALIAS("platform:cpcap-rtc"); 329MODULE_DESCRIPTION("CPCAP RTC driver"); 330MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>"); 331MODULE_LICENSE("GPL");