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

rtc: add NXP PCF2127 support (i2c)

Added support for NXP PCF2127 RTC (i2c).

[akpm@linux-foundation.org: fix typo, fix warnings]
Signed-off-by: Renaud Cerrato <r.cerrato@til-technologies.fr>
Cc: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Renaud Cerrato and committed by
Linus Torvalds
18cb6368 2c5a5b30

+251
+9
drivers/rtc/Kconfig
··· 313 313 This driver can also be built as a module. If so, the module 314 314 will be called rtc-palma. 315 315 316 + config RTC_DRV_PCF2127 317 + tristate "NXP PCF2127" 318 + help 319 + If you say yes here you get support for the NXP PCF2127/29 RTC 320 + chips. 321 + 322 + This driver can also be built as a module. If so, the module 323 + will be called rtc-pcf2127. 324 + 316 325 config RTC_DRV_PCF8523 317 326 tristate "NXP PCF8523" 318 327 help
+1
drivers/rtc/Makefile
··· 83 83 obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o 84 84 obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o 85 85 obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o 86 + obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o 86 87 obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o 87 88 obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o 88 89 obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
+241
drivers/rtc/rtc-pcf2127.c
··· 1 + /* 2 + * An I2C driver for the NXP PCF2127 RTC 3 + * Copyright 2013 Til-Technologies 4 + * 5 + * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> 6 + * 7 + * based on the other drivers in this same directory. 8 + * 9 + * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License version 2 as 13 + * published by the Free Software Foundation. 14 + */ 15 + 16 + #include <linux/i2c.h> 17 + #include <linux/bcd.h> 18 + #include <linux/rtc.h> 19 + #include <linux/slab.h> 20 + #include <linux/module.h> 21 + #include <linux/of.h> 22 + 23 + #define DRV_VERSION "0.0.1" 24 + 25 + #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ 26 + #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ 27 + #define PCF2127_REG_CTRL3 (0x02) /* Control Register 3 */ 28 + #define PCF2127_REG_SC (0x03) /* datetime */ 29 + #define PCF2127_REG_MN (0x04) 30 + #define PCF2127_REG_HR (0x05) 31 + #define PCF2127_REG_DM (0x06) 32 + #define PCF2127_REG_DW (0x07) 33 + #define PCF2127_REG_MO (0x08) 34 + #define PCF2127_REG_YR (0x09) 35 + 36 + static struct i2c_driver pcf2127_driver; 37 + 38 + struct pcf2127 { 39 + struct rtc_device *rtc; 40 + int voltage_low; /* indicates if a low_voltage was detected */ 41 + }; 42 + 43 + /* 44 + * In the routines that deal directly with the pcf2127 hardware, we use 45 + * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. 46 + */ 47 + static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) 48 + { 49 + struct pcf2127 *pcf2127 = i2c_get_clientdata(client); 50 + unsigned char buf[10] = { PCF2127_REG_CTRL1 }; 51 + 52 + /* read registers */ 53 + if (i2c_master_send(client, buf, 1) != 1 || 54 + i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) { 55 + dev_err(&client->dev, "%s: read error\n", __func__); 56 + return -EIO; 57 + } 58 + 59 + if (buf[PCF2127_REG_CTRL3] & 0x04) { 60 + pcf2127->voltage_low = 1; 61 + dev_info(&client->dev, 62 + "low voltage detected, date/time is not reliable.\n"); 63 + } 64 + 65 + dev_dbg(&client->dev, 66 + "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " 67 + "sec=%02x, min=%02x, hr=%02x, " 68 + "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", 69 + __func__, 70 + buf[0], buf[1], buf[2], 71 + buf[3], buf[4], buf[5], 72 + buf[6], buf[7], buf[8], buf[9]); 73 + 74 + 75 + tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); 76 + tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); 77 + tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ 78 + tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); 79 + tm->tm_wday = buf[PCF2127_REG_DW] & 0x07; 80 + tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ 81 + tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]); 82 + if (tm->tm_year < 70) 83 + tm->tm_year += 100; /* assume we are in 1970...2069 */ 84 + 85 + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " 86 + "mday=%d, mon=%d, year=%d, wday=%d\n", 87 + __func__, 88 + tm->tm_sec, tm->tm_min, tm->tm_hour, 89 + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 90 + 91 + /* the clock can give out invalid datetime, but we cannot return 92 + * -EINVAL otherwise hwclock will refuse to set the time on bootup. 93 + */ 94 + if (rtc_valid_tm(tm) < 0) 95 + dev_err(&client->dev, "retrieved date/time is not valid.\n"); 96 + 97 + return 0; 98 + } 99 + 100 + static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) 101 + { 102 + unsigned char buf[8]; 103 + int i = 0, err; 104 + 105 + dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " 106 + "mday=%d, mon=%d, year=%d, wday=%d\n", 107 + __func__, 108 + tm->tm_sec, tm->tm_min, tm->tm_hour, 109 + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 110 + 111 + /* start register address */ 112 + buf[i++] = PCF2127_REG_SC; 113 + 114 + /* hours, minutes and seconds */ 115 + buf[i++] = bin2bcd(tm->tm_sec); 116 + buf[i++] = bin2bcd(tm->tm_min); 117 + buf[i++] = bin2bcd(tm->tm_hour); 118 + buf[i++] = bin2bcd(tm->tm_mday); 119 + buf[i++] = tm->tm_wday & 0x07; 120 + 121 + /* month, 1 - 12 */ 122 + buf[i++] = bin2bcd(tm->tm_mon + 1); 123 + 124 + /* year */ 125 + buf[i++] = bin2bcd(tm->tm_year % 100); 126 + 127 + /* write register's data */ 128 + err = i2c_master_send(client, buf, i); 129 + if (err != i) { 130 + dev_err(&client->dev, 131 + "%s: err=%d", __func__, err); 132 + return -EIO; 133 + } 134 + 135 + return 0; 136 + } 137 + 138 + #ifdef CONFIG_RTC_INTF_DEV 139 + static int pcf2127_rtc_ioctl(struct device *dev, 140 + unsigned int cmd, unsigned long arg) 141 + { 142 + struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev)); 143 + 144 + switch (cmd) { 145 + case RTC_VL_READ: 146 + if (pcf2127->voltage_low) 147 + dev_info(dev, "low voltage detected, date/time is not reliable.\n"); 148 + 149 + if (copy_to_user((void __user *)arg, &pcf2127->voltage_low, 150 + sizeof(int))) 151 + return -EFAULT; 152 + return 0; 153 + default: 154 + return -ENOIOCTLCMD; 155 + } 156 + } 157 + #else 158 + #define pcf2127_rtc_ioctl NULL 159 + #endif 160 + 161 + static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) 162 + { 163 + return pcf2127_get_datetime(to_i2c_client(dev), tm); 164 + } 165 + 166 + static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) 167 + { 168 + return pcf2127_set_datetime(to_i2c_client(dev), tm); 169 + } 170 + 171 + static const struct rtc_class_ops pcf2127_rtc_ops = { 172 + .ioctl = pcf2127_rtc_ioctl, 173 + .read_time = pcf2127_rtc_read_time, 174 + .set_time = pcf2127_rtc_set_time, 175 + }; 176 + 177 + static int pcf2127_probe(struct i2c_client *client, 178 + const struct i2c_device_id *id) 179 + { 180 + struct pcf2127 *pcf2127; 181 + 182 + dev_dbg(&client->dev, "%s\n", __func__); 183 + 184 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 185 + return -ENODEV; 186 + 187 + pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127), 188 + GFP_KERNEL); 189 + if (!pcf2127) 190 + return -ENOMEM; 191 + 192 + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); 193 + 194 + i2c_set_clientdata(client, pcf2127); 195 + 196 + pcf2127->rtc = devm_rtc_device_register(&client->dev, 197 + pcf2127_driver.driver.name, 198 + &pcf2127_rtc_ops, THIS_MODULE); 199 + 200 + if (IS_ERR(pcf2127->rtc)) 201 + return PTR_ERR(pcf2127->rtc); 202 + 203 + return 0; 204 + } 205 + 206 + static int pcf2127_remove(struct i2c_client *client) 207 + { 208 + return 0; 209 + } 210 + 211 + static const struct i2c_device_id pcf2127_id[] = { 212 + { "pcf2127", 0 }, 213 + { } 214 + }; 215 + MODULE_DEVICE_TABLE(i2c, pcf2127_id); 216 + 217 + #ifdef CONFIG_OF 218 + static const struct of_device_id pcf2127_of_match[] = { 219 + { .compatible = "nxp,pcf2127" }, 220 + {} 221 + }; 222 + MODULE_DEVICE_TABLE(of, pcf2127_of_match); 223 + #endif 224 + 225 + static struct i2c_driver pcf2127_driver = { 226 + .driver = { 227 + .name = "rtc-pcf2127", 228 + .owner = THIS_MODULE, 229 + .of_match_table = of_match_ptr(pcf2127_of_match), 230 + }, 231 + .probe = pcf2127_probe, 232 + .remove = pcf2127_remove, 233 + .id_table = pcf2127_id, 234 + }; 235 + 236 + module_i2c_driver(pcf2127_driver); 237 + 238 + MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>"); 239 + MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); 240 + MODULE_LICENSE("GPL"); 241 + MODULE_VERSION(DRV_VERSION);