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

rtc: add support for the S-35390A RTC chip

This adds basic get/set time support for the Seiko Instruments S-35390A.
This chip communicates using I2C and is used on the QNAP TS-109/TS-209 NAS
devices.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Byron Bradley <byron.bbradley@gmail.com>
Acked-by: Jean Delvare <khali@linux-fr.org>
Acked-by: David Brownell <david-b@pacbell.net>
Tested-by: Tim Ellis <tim@ngndg.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Byron Bradley and committed by
Linus Torvalds
c46288b0 fb78922c

+326
+9
drivers/rtc/Kconfig
··· 250 250 platforms. The support is integrated with the rest of 251 251 the Menelaus driver; it's not separate module. 252 252 253 + config RTC_DRV_S35390A 254 + tristate "Seiko Instruments S-35390A" 255 + help 256 + If you say yes here you will get support for the Seiko 257 + Instruments S-35390A. 258 + 259 + This driver can also be built as a module. If so the module 260 + will be called rtc-s35390a. 261 + 253 262 endif # I2C 254 263 255 264 comment "SPI RTC drivers"
+1
drivers/rtc/Makefile
··· 45 45 obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o 46 46 obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o 47 47 obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o 48 + obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o 48 49 obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o 49 50 obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o 50 51 obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+316
drivers/rtc/rtc-s35390a.c
··· 1 + /* 2 + * Seiko Instruments S-35390A RTC Driver 3 + * 4 + * Copyright (c) 2007 Byron Bradley 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/rtc.h> 14 + #include <linux/i2c.h> 15 + #include <linux/bitrev.h> 16 + #include <linux/bcd.h> 17 + #include <linux/slab.h> 18 + 19 + #define S35390A_CMD_STATUS1 0 20 + #define S35390A_CMD_STATUS2 1 21 + #define S35390A_CMD_TIME1 2 22 + 23 + #define S35390A_BYTE_YEAR 0 24 + #define S35390A_BYTE_MONTH 1 25 + #define S35390A_BYTE_DAY 2 26 + #define S35390A_BYTE_WDAY 3 27 + #define S35390A_BYTE_HOURS 4 28 + #define S35390A_BYTE_MINS 5 29 + #define S35390A_BYTE_SECS 6 30 + 31 + #define S35390A_FLAG_POC 0x01 32 + #define S35390A_FLAG_BLD 0x02 33 + #define S35390A_FLAG_24H 0x40 34 + #define S35390A_FLAG_RESET 0x80 35 + #define S35390A_FLAG_TEST 0x01 36 + 37 + struct s35390a { 38 + struct i2c_client *client[8]; 39 + struct rtc_device *rtc; 40 + int twentyfourhour; 41 + }; 42 + 43 + static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) 44 + { 45 + struct i2c_client *client = s35390a->client[reg]; 46 + struct i2c_msg msg[] = { 47 + { client->addr, 0, len, buf }, 48 + }; 49 + 50 + if ((i2c_transfer(client->adapter, msg, 1)) != 1) 51 + return -EIO; 52 + 53 + return 0; 54 + } 55 + 56 + static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) 57 + { 58 + struct i2c_client *client = s35390a->client[reg]; 59 + struct i2c_msg msg[] = { 60 + { client->addr, I2C_M_RD, len, buf }, 61 + }; 62 + 63 + if ((i2c_transfer(client->adapter, msg, 1)) != 1) 64 + return -EIO; 65 + 66 + return 0; 67 + } 68 + 69 + static int s35390a_reset(struct s35390a *s35390a) 70 + { 71 + char buf[1]; 72 + 73 + if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0) 74 + return -EIO; 75 + 76 + if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD))) 77 + return 0; 78 + 79 + buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H); 80 + buf[0] &= 0xf0; 81 + return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)); 82 + } 83 + 84 + static int s35390a_disable_test_mode(struct s35390a *s35390a) 85 + { 86 + char buf[1]; 87 + 88 + if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)) < 0) 89 + return -EIO; 90 + 91 + if (!(buf[0] & S35390A_FLAG_TEST)) 92 + return 0; 93 + 94 + buf[0] &= ~S35390A_FLAG_TEST; 95 + return s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, buf, sizeof(buf)); 96 + } 97 + 98 + static char s35390a_hr2reg(struct s35390a *s35390a, int hour) 99 + { 100 + if (s35390a->twentyfourhour) 101 + return BIN2BCD(hour); 102 + 103 + if (hour < 12) 104 + return BIN2BCD(hour); 105 + 106 + return 0x40 | BIN2BCD(hour - 12); 107 + } 108 + 109 + static int s35390a_reg2hr(struct s35390a *s35390a, char reg) 110 + { 111 + unsigned hour; 112 + 113 + if (s35390a->twentyfourhour) 114 + return BCD2BIN(reg & 0x3f); 115 + 116 + hour = BCD2BIN(reg & 0x3f); 117 + if (reg & 0x40) 118 + hour += 12; 119 + 120 + return hour; 121 + } 122 + 123 + static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm) 124 + { 125 + struct s35390a *s35390a = i2c_get_clientdata(client); 126 + int i, err; 127 + char buf[7]; 128 + 129 + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, " 130 + "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, 131 + tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, 132 + tm->tm_wday); 133 + 134 + buf[S35390A_BYTE_YEAR] = BIN2BCD(tm->tm_year - 100); 135 + buf[S35390A_BYTE_MONTH] = BIN2BCD(tm->tm_mon + 1); 136 + buf[S35390A_BYTE_DAY] = BIN2BCD(tm->tm_mday); 137 + buf[S35390A_BYTE_WDAY] = BIN2BCD(tm->tm_wday); 138 + buf[S35390A_BYTE_HOURS] = s35390a_hr2reg(s35390a, tm->tm_hour); 139 + buf[S35390A_BYTE_MINS] = BIN2BCD(tm->tm_min); 140 + buf[S35390A_BYTE_SECS] = BIN2BCD(tm->tm_sec); 141 + 142 + /* This chip expects the bits of each byte to be in reverse order */ 143 + for (i = 0; i < 7; ++i) 144 + buf[i] = bitrev8(buf[i]); 145 + 146 + err = s35390a_set_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); 147 + 148 + return err; 149 + } 150 + 151 + static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm) 152 + { 153 + struct s35390a *s35390a = i2c_get_clientdata(client); 154 + char buf[7]; 155 + int i, err; 156 + 157 + err = s35390a_get_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf)); 158 + if (err < 0) 159 + return err; 160 + 161 + /* This chip returns the bits of each byte in reverse order */ 162 + for (i = 0; i < 7; ++i) 163 + buf[i] = bitrev8(buf[i]); 164 + 165 + tm->tm_sec = BCD2BIN(buf[S35390A_BYTE_SECS]); 166 + tm->tm_min = BCD2BIN(buf[S35390A_BYTE_MINS]); 167 + tm->tm_hour = s35390a_reg2hr(s35390a, buf[S35390A_BYTE_HOURS]); 168 + tm->tm_wday = BCD2BIN(buf[S35390A_BYTE_WDAY]); 169 + tm->tm_mday = BCD2BIN(buf[S35390A_BYTE_DAY]); 170 + tm->tm_mon = BCD2BIN(buf[S35390A_BYTE_MONTH]) - 1; 171 + tm->tm_year = BCD2BIN(buf[S35390A_BYTE_YEAR]) + 100; 172 + 173 + dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, " 174 + "mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, 175 + tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, 176 + tm->tm_wday); 177 + 178 + return rtc_valid_tm(tm); 179 + } 180 + 181 + static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) 182 + { 183 + return s35390a_get_datetime(to_i2c_client(dev), tm); 184 + } 185 + 186 + static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) 187 + { 188 + return s35390a_set_datetime(to_i2c_client(dev), tm); 189 + } 190 + 191 + static const struct rtc_class_ops s35390a_rtc_ops = { 192 + .read_time = s35390a_rtc_read_time, 193 + .set_time = s35390a_rtc_set_time, 194 + }; 195 + 196 + static struct i2c_driver s35390a_driver; 197 + 198 + static int s35390a_probe(struct i2c_client *client) 199 + { 200 + int err; 201 + unsigned int i; 202 + struct s35390a *s35390a; 203 + struct rtc_time tm; 204 + char buf[1]; 205 + 206 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 207 + err = -ENODEV; 208 + goto exit; 209 + } 210 + 211 + s35390a = kzalloc(sizeof(struct s35390a), GFP_KERNEL); 212 + if (!s35390a) { 213 + err = -ENOMEM; 214 + goto exit; 215 + } 216 + 217 + s35390a->client[0] = client; 218 + i2c_set_clientdata(client, s35390a); 219 + 220 + /* This chip uses multiple addresses, use dummy devices for them */ 221 + for (i = 1; i < 8; ++i) { 222 + s35390a->client[i] = i2c_new_dummy(client->adapter, 223 + client->addr + i, "rtc-s35390a"); 224 + if (!s35390a->client[i]) { 225 + dev_err(&client->dev, "Address %02x unavailable\n", 226 + client->addr + i); 227 + err = -EBUSY; 228 + goto exit_dummy; 229 + } 230 + } 231 + 232 + err = s35390a_reset(s35390a); 233 + if (err < 0) { 234 + dev_err(&client->dev, "error resetting chip\n"); 235 + goto exit_dummy; 236 + } 237 + 238 + err = s35390a_disable_test_mode(s35390a); 239 + if (err < 0) { 240 + dev_err(&client->dev, "error disabling test mode\n"); 241 + goto exit_dummy; 242 + } 243 + 244 + err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)); 245 + if (err < 0) { 246 + dev_err(&client->dev, "error checking 12/24 hour mode\n"); 247 + goto exit_dummy; 248 + } 249 + if (buf[0] & S35390A_FLAG_24H) 250 + s35390a->twentyfourhour = 1; 251 + else 252 + s35390a->twentyfourhour = 0; 253 + 254 + if (s35390a_get_datetime(client, &tm) < 0) 255 + dev_warn(&client->dev, "clock needs to be set\n"); 256 + 257 + s35390a->rtc = rtc_device_register(s35390a_driver.driver.name, 258 + &client->dev, &s35390a_rtc_ops, THIS_MODULE); 259 + 260 + if (IS_ERR(s35390a->rtc)) { 261 + err = PTR_ERR(s35390a->rtc); 262 + goto exit_dummy; 263 + } 264 + return 0; 265 + 266 + exit_dummy: 267 + for (i = 1; i < 8; ++i) 268 + if (s35390a->client[i]) 269 + i2c_unregister_device(s35390a->client[i]); 270 + kfree(s35390a); 271 + i2c_set_clientdata(client, NULL); 272 + 273 + exit: 274 + return err; 275 + } 276 + 277 + static int s35390a_remove(struct i2c_client *client) 278 + { 279 + unsigned int i; 280 + 281 + struct s35390a *s35390a = i2c_get_clientdata(client); 282 + for (i = 1; i < 8; ++i) 283 + if (s35390a->client[i]) 284 + i2c_unregister_device(s35390a->client[i]); 285 + 286 + rtc_device_unregister(s35390a->rtc); 287 + kfree(s35390a); 288 + i2c_set_clientdata(client, NULL); 289 + 290 + return 0; 291 + } 292 + 293 + static struct i2c_driver s35390a_driver = { 294 + .driver = { 295 + .name = "rtc-s35390a", 296 + }, 297 + .probe = s35390a_probe, 298 + .remove = s35390a_remove, 299 + }; 300 + 301 + static int __init s35390a_rtc_init(void) 302 + { 303 + return i2c_add_driver(&s35390a_driver); 304 + } 305 + 306 + static void __exit s35390a_rtc_exit(void) 307 + { 308 + i2c_del_driver(&s35390a_driver); 309 + } 310 + 311 + MODULE_AUTHOR("Byron Bradley <byron.bbradley@gmail.com>"); 312 + MODULE_DESCRIPTION("S35390A RTC driver"); 313 + MODULE_LICENSE("GPL"); 314 + 315 + module_init(s35390a_rtc_init); 316 + module_exit(s35390a_rtc_exit);