| 1 | |
| 2 | |
| 3 | * drivers/rtc/rtc-pcf85363.c
|
| 4 | *
|
| 5 | * Driver for NXP PCF85363 real-time clock.
|
| 6 | *
|
| 7 | * Copyright (C) 2017 Eric Nelson
|
| 8 |
|
| 9 | #include <linux/module.h>
|
| 10 | #include <linux/i2c.h>
|
| 11 | #include <linux/slab.h>
|
| 12 | #include <linux/rtc.h>
|
| 13 | #include <linux/init.h>
|
| 14 | #include <linux/err.h>
|
| 15 | #include <linux/errno.h>
|
| 16 | #include <linux/bcd.h>
|
| 17 | #include <linux/of.h>
|
| 18 | #include <linux/regmap.h>
|
| 19 |
|
| 20 | |
| 21 | * Date/Time registers
|
| 22 |
|
| 23 | #define DT_100THS 0x00
|
| 24 | #define DT_SECS 0x01
|
| 25 | #define DT_MINUTES 0x02
|
| 26 | #define DT_HOURS 0x03
|
| 27 | #define DT_DAYS 0x04
|
| 28 | #define DT_WEEKDAYS 0x05
|
| 29 | #define DT_MONTHS 0x06
|
| 30 | #define DT_YEARS 0x07
|
| 31 |
|
| 32 | |
| 33 | * Alarm registers
|
| 34 |
|
| 35 | #define DT_SECOND_ALM1 0x08
|
| 36 | #define DT_MINUTE_ALM1 0x09
|
| 37 | #define DT_HOUR_ALM1 0x0a
|
| 38 | #define DT_DAY_ALM1 0x0b
|
| 39 | #define DT_MONTH_ALM1 0x0c
|
| 40 | #define DT_MINUTE_ALM2 0x0d
|
| 41 | #define DT_HOUR_ALM2 0x0e
|
| 42 | #define DT_WEEKDAY_ALM2 0x0f
|
| 43 | #define DT_ALARM_EN 0x10
|
| 44 |
|
| 45 | |
| 46 | * Time stamp registers
|
| 47 |
|
| 48 | #define DT_TIMESTAMP1 0x11
|
| 49 | #define DT_TIMESTAMP2 0x17
|
| 50 | #define DT_TIMESTAMP3 0x1d
|
| 51 | #define DT_TS_MODE 0x23
|
| 52 |
|
| 53 | |
| 54 | * control registers
|
| 55 |
|
| 56 | #define CTRL_OFFSET 0x24
|
| 57 | #define CTRL_OSCILLATOR 0x25
|
| 58 | #define CTRL_BATTERY 0x26
|
| 59 | #define CTRL_PIN_IO 0x27
|
| 60 | #define CTRL_FUNCTION 0x28
|
| 61 | #define CTRL_INTA_EN 0x29
|
| 62 | #define CTRL_INTB_EN 0x2a
|
| 63 | #define CTRL_FLAGS 0x2b
|
| 64 | #define CTRL_RAMBYTE 0x2c
|
| 65 | #define CTRL_WDOG 0x2d
|
| 66 | #define CTRL_STOP_EN 0x2e
|
| 67 | #define CTRL_RESETS 0x2f
|
| 68 | #define CTRL_RAM 0x40
|
| 69 |
|
| 70 | #define ALRM_SEC_A1E BIT(0)
|
| 71 | #define ALRM_MIN_A1E BIT(1)
|
| 72 | #define ALRM_HR_A1E BIT(2)
|
| 73 | #define ALRM_DAY_A1E BIT(3)
|
| 74 | #define ALRM_MON_A1E BIT(4)
|
| 75 | #define ALRM_MIN_A2E BIT(5)
|
| 76 | #define ALRM_HR_A2E BIT(6)
|
| 77 | #define ALRM_DAY_A2E BIT(7)
|
| 78 |
|
| 79 | #define INT_WDIE BIT(0)
|
| 80 | #define INT_BSIE BIT(1)
|
| 81 | #define INT_TSRIE BIT(2)
|
| 82 | #define INT_A2IE BIT(3)
|
| 83 | #define INT_A1IE BIT(4)
|
| 84 | #define INT_OIE BIT(5)
|
| 85 | #define INT_PIE BIT(6)
|
| 86 | #define INT_ILP BIT(7)
|
| 87 |
|
| 88 | #define FLAGS_TSR1F BIT(0)
|
| 89 | #define FLAGS_TSR2F BIT(1)
|
| 90 | #define FLAGS_TSR3F BIT(2)
|
| 91 | #define FLAGS_BSF BIT(3)
|
| 92 | #define FLAGS_WDF BIT(4)
|
| 93 | #define FLAGS_A1F BIT(5)
|
| 94 | #define FLAGS_A2F BIT(6)
|
| 95 | #define FLAGS_PIF BIT(7)
|
| 96 |
|
| 97 | #define PIN_IO_INTAPM GENMASK(1, 0)
|
| 98 | #define PIN_IO_INTA_CLK 0
|
| 99 | #define PIN_IO_INTA_BAT 1
|
| 100 | #define PIN_IO_INTA_OUT 2
|
| 101 | #define PIN_IO_INTA_HIZ 3
|
| 102 |
|
| 103 | #define OSC_CAP_SEL GENMASK(1, 0)
|
| 104 | #define OSC_CAP_6000 0x01
|
| 105 | #define OSC_CAP_12500 0x02
|
| 106 |
|
| 107 | #define STOP_EN_STOP BIT(0)
|
| 108 |
|
| 109 | #define RESET_CPR 0xa4
|
| 110 |
|
| 111 | #define NVRAM_SIZE 0x40
|
| 112 |
|
| 113 | struct pcf85363 {
|
| 114 | struct rtc_device *rtc;
|
| 115 | struct regmap *regmap;
|
| 116 | };
|
| 117 |
|
| 118 | struct pcf85x63_config {
|
| 119 | struct regmap_config regmap;
|
| 120 | unsigned int num_nvram;
|
| 121 | };
|
| 122 |
|
| 123 | static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node)
|
| 124 | {
|
| 125 | u32 load = 7000;
|
| 126 | u8 value = 0;
|
| 127 |
|
| 128 | of_property_read_u32(node, "quartz-load-femtofarads", &load);
|
| 129 |
|
| 130 | switch (load) {
|
| 131 | default:
|
| 132 | dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
|
| 133 | load);
|
| 134 | fallthrough;
|
| 135 | case 7000:
|
| 136 | break;
|
| 137 | case 6000:
|
| 138 | value = OSC_CAP_6000;
|
| 139 | break;
|
| 140 | case 12500:
|
| 141 | value = OSC_CAP_12500;
|
| 142 | break;
|
| 143 | }
|
| 144 |
|
| 145 | return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR,
|
| 146 | OSC_CAP_SEL, value);
|
| 147 | }
|
| 148 |
|
| 149 | static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
| 150 | {
|
| 151 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
|
| 152 | unsigned char buf[DT_YEARS + 1];
|
| 153 | int ret, len = sizeof(buf);
|
| 154 |
|
| 155 |
|
| 156 | ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len);
|
| 157 | if (ret) {
|
| 158 | dev_err(dev, "%s: error %d\n", __func__, ret);
|
| 159 | return ret;
|
| 160 | }
|
| 161 |
|
| 162 | tm->tm_year = bcd2bin(buf[DT_YEARS]);
|
| 163 |
|
| 164 | tm->tm_year += 100;
|
| 165 |
|
| 166 | tm->tm_wday = buf[DT_WEEKDAYS] & 7;
|
| 167 | buf[DT_SECS] &= 0x7F;
|
| 168 | tm->tm_sec = bcd2bin(buf[DT_SECS]);
|
| 169 | buf[DT_MINUTES] &= 0x7F;
|
| 170 | tm->tm_min = bcd2bin(buf[DT_MINUTES]);
|
| 171 | tm->tm_hour = bcd2bin(buf[DT_HOURS]);
|
| 172 | tm->tm_mday = bcd2bin(buf[DT_DAYS]);
|
| 173 | tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1;
|
| 174 |
|
| 175 | return 0;
|
| 176 | }
|
| 177 |
|
| 178 | static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
| 179 | {
|
| 180 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
|
| 181 | unsigned char tmp[11];
|
| 182 | unsigned char *buf = &tmp[2];
|
| 183 | int ret;
|
| 184 |
|
| 185 | tmp[0] = STOP_EN_STOP;
|
| 186 | tmp[1] = RESET_CPR;
|
| 187 |
|
| 188 | buf[DT_100THS] = 0;
|
| 189 | buf[DT_SECS] = bin2bcd(tm->tm_sec);
|
| 190 | buf[DT_MINUTES] = bin2bcd(tm->tm_min);
|
| 191 | buf[DT_HOURS] = bin2bcd(tm->tm_hour);
|
| 192 | buf[DT_DAYS] = bin2bcd(tm->tm_mday);
|
| 193 | buf[DT_WEEKDAYS] = tm->tm_wday;
|
| 194 | buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1);
|
| 195 | buf[DT_YEARS] = bin2bcd(tm->tm_year % 100);
|
| 196 |
|
| 197 | ret = regmap_bulk_write(pcf85363->regmap, CTRL_STOP_EN,
|
| 198 | tmp, 2);
|
| 199 | if (ret)
|
| 200 | return ret;
|
| 201 |
|
| 202 | ret = regmap_bulk_write(pcf85363->regmap, DT_100THS,
|
| 203 | buf, sizeof(tmp) - 2);
|
| 204 | if (ret)
|
| 205 | return ret;
|
| 206 |
|
| 207 | return regmap_write(pcf85363->regmap, CTRL_STOP_EN, 0);
|
| 208 | }
|
| 209 |
|
| 210 | static int pcf85363_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
| 211 | {
|
| 212 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
|
| 213 | unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1];
|
| 214 | unsigned int val;
|
| 215 | int ret;
|
| 216 |
|
| 217 | ret = regmap_bulk_read(pcf85363->regmap, DT_SECOND_ALM1, buf,
|
| 218 | sizeof(buf));
|
| 219 | if (ret)
|
| 220 | return ret;
|
| 221 |
|
| 222 | alrm->time.tm_sec = bcd2bin(buf[0]);
|
| 223 | alrm->time.tm_min = bcd2bin(buf[1]);
|
| 224 | alrm->time.tm_hour = bcd2bin(buf[2]);
|
| 225 | alrm->time.tm_mday = bcd2bin(buf[3]);
|
| 226 | alrm->time.tm_mon = bcd2bin(buf[4]) - 1;
|
| 227 |
|
| 228 | ret = regmap_read(pcf85363->regmap, CTRL_INTA_EN, &val);
|
| 229 | if (ret)
|
| 230 | return ret;
|
| 231 |
|
| 232 | alrm->enabled = !!(val & INT_A1IE);
|
| 233 |
|
| 234 | return 0;
|
| 235 | }
|
| 236 |
|
| 237 | static int _pcf85363_rtc_alarm_irq_enable(struct pcf85363 *pcf85363, unsigned
|
| 238 | int enabled)
|
| 239 | {
|
| 240 | unsigned int alarm_flags = ALRM_SEC_A1E | ALRM_MIN_A1E | ALRM_HR_A1E |
|
| 241 | ALRM_DAY_A1E | ALRM_MON_A1E;
|
| 242 | int ret;
|
| 243 |
|
| 244 | ret = regmap_update_bits(pcf85363->regmap, DT_ALARM_EN, alarm_flags,
|
| 245 | enabled ? alarm_flags : 0);
|
| 246 | if (ret)
|
| 247 | return ret;
|
| 248 |
|
| 249 | ret = regmap_update_bits(pcf85363->regmap, CTRL_INTA_EN,
|
| 250 | INT_A1IE, enabled ? INT_A1IE : 0);
|
| 251 |
|
| 252 | if (ret || enabled)
|
| 253 | return ret;
|
| 254 |
|
| 255 |
|
| 256 | return regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0);
|
| 257 | }
|
| 258 |
|
| 259 | static int pcf85363_rtc_alarm_irq_enable(struct device *dev,
|
| 260 | unsigned int enabled)
|
| 261 | {
|
| 262 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
|
| 263 |
|
| 264 | return _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled);
|
| 265 | }
|
| 266 |
|
| 267 | static int pcf85363_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
| 268 | {
|
| 269 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
|
| 270 | unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1];
|
| 271 | int ret;
|
| 272 |
|
| 273 | buf[0] = bin2bcd(alrm->time.tm_sec);
|
| 274 | buf[1] = bin2bcd(alrm->time.tm_min);
|
| 275 | buf[2] = bin2bcd(alrm->time.tm_hour);
|
| 276 | buf[3] = bin2bcd(alrm->time.tm_mday);
|
| 277 | buf[4] = bin2bcd(alrm->time.tm_mon + 1);
|
| 278 |
|
| 279 | |
| 280 | * Disable the alarm interrupt before changing the value to avoid
|
| 281 | * spurious interrupts
|
| 282 |
|
| 283 | ret = _pcf85363_rtc_alarm_irq_enable(pcf85363, 0);
|
| 284 | if (ret)
|
| 285 | return ret;
|
| 286 |
|
| 287 | ret = regmap_bulk_write(pcf85363->regmap, DT_SECOND_ALM1, buf,
|
| 288 | sizeof(buf));
|
| 289 | if (ret)
|
| 290 | return ret;
|
| 291 |
|
| 292 | return _pcf85363_rtc_alarm_irq_enable(pcf85363, alrm->enabled);
|
| 293 | }
|
| 294 |
|
| 295 | static irqreturn_t pcf85363_rtc_handle_irq(int irq, void *dev_id)
|
| 296 | {
|
| 297 | struct pcf85363 *pcf85363 = i2c_get_clientdata(dev_id);
|
| 298 | unsigned int flags;
|
| 299 | int err;
|
| 300 |
|
| 301 | err = regmap_read(pcf85363->regmap, CTRL_FLAGS, &flags);
|
| 302 | if (err)
|
| 303 | return IRQ_NONE;
|
| 304 |
|
| 305 | if (flags & FLAGS_A1F) {
|
| 306 | rtc_update_irq(pcf85363->rtc, 1, RTC_IRQF | RTC_AF);
|
| 307 | regmap_update_bits(pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, 0);
|
| 308 | return IRQ_HANDLED;
|
| 309 | }
|
| 310 |
|
| 311 | return IRQ_NONE;
|
| 312 | }
|
| 313 |
|
| 314 | static const struct rtc_class_ops rtc_ops = {
|
| 315 | .read_time = pcf85363_rtc_read_time,
|
| 316 | .set_time = pcf85363_rtc_set_time,
|
| 317 | .read_alarm = pcf85363_rtc_read_alarm,
|
| 318 | .set_alarm = pcf85363_rtc_set_alarm,
|
| 319 | .alarm_irq_enable = pcf85363_rtc_alarm_irq_enable,
|
| 320 | };
|
| 321 |
|
| 322 | static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val,
|
| 323 | size_t bytes)
|
| 324 | {
|
| 325 | struct pcf85363 *pcf85363 = priv;
|
| 326 |
|
| 327 | return regmap_bulk_read(pcf85363->regmap, CTRL_RAM + offset,
|
| 328 | val, bytes);
|
| 329 | }
|
| 330 |
|
| 331 | static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val,
|
| 332 | size_t bytes)
|
| 333 | {
|
| 334 | struct pcf85363 *pcf85363 = priv;
|
| 335 |
|
| 336 | return regmap_bulk_write(pcf85363->regmap, CTRL_RAM + offset,
|
| 337 | val, bytes);
|
| 338 | }
|
| 339 |
|
| 340 | static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val,
|
| 341 | size_t bytes)
|
| 342 | {
|
| 343 | struct pcf85363 *pcf85363 = priv;
|
| 344 | unsigned int tmp_val;
|
| 345 | int ret;
|
| 346 |
|
| 347 | ret = regmap_read(pcf85363->regmap, CTRL_RAMBYTE, &tmp_val);
|
| 348 | (*(unsigned char *) val) = (unsigned char) tmp_val;
|
| 349 |
|
| 350 | return ret;
|
| 351 | }
|
| 352 |
|
| 353 | static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val,
|
| 354 | size_t bytes)
|
| 355 | {
|
| 356 | struct pcf85363 *pcf85363 = priv;
|
| 357 | unsigned char tmp_val;
|
| 358 |
|
| 359 | tmp_val = *((unsigned char *)val);
|
| 360 | return regmap_write(pcf85363->regmap, CTRL_RAMBYTE,
|
| 361 | (unsigned int)tmp_val);
|
| 362 | }
|
| 363 |
|
| 364 | static const struct pcf85x63_config pcf_85263_config = {
|
| 365 | .regmap = {
|
| 366 | .reg_bits = 8,
|
| 367 | .val_bits = 8,
|
| 368 | .max_register = 0x2f,
|
| 369 | },
|
| 370 | .num_nvram = 1
|
| 371 | };
|
| 372 |
|
| 373 | static const struct pcf85x63_config pcf_85363_config = {
|
| 374 | .regmap = {
|
| 375 | .reg_bits = 8,
|
| 376 | .val_bits = 8,
|
| 377 | .max_register = 0x7f,
|
| 378 | },
|
| 379 | .num_nvram = 2
|
| 380 | };
|
| 381 |
|
| 382 | static int pcf85363_probe(struct i2c_client *client)
|
| 383 | {
|
| 384 | struct pcf85363 *pcf85363;
|
| 385 | const struct pcf85x63_config *config = &pcf_85363_config;
|
| 386 | const void *data = of_device_get_match_data(&client->dev);
|
| 387 | static struct nvmem_config nvmem_cfg[] = {
|
| 388 | {
|
| 389 | .name = "pcf85x63-",
|
| 390 | .word_size = 1,
|
| 391 | .stride = 1,
|
| 392 | .size = 1,
|
| 393 | .reg_read = pcf85x63_nvram_read,
|
| 394 | .reg_write = pcf85x63_nvram_write,
|
| 395 | }, {
|
| 396 | .name = "pcf85363-",
|
| 397 | .word_size = 1,
|
| 398 | .stride = 1,
|
| 399 | .size = NVRAM_SIZE,
|
| 400 | .reg_read = pcf85363_nvram_read,
|
| 401 | .reg_write = pcf85363_nvram_write,
|
| 402 | },
|
| 403 | };
|
| 404 | int ret, i, err;
|
| 405 | bool wakeup_source;
|
| 406 |
|
| 407 | if (data)
|
| 408 | config = data;
|
| 409 |
|
| 410 | pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363),
|
| 411 | GFP_KERNEL);
|
| 412 | if (!pcf85363)
|
| 413 | return -ENOMEM;
|
| 414 |
|
| 415 | pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap);
|
| 416 | if (IS_ERR(pcf85363->regmap)) {
|
| 417 | dev_err(&client->dev, "regmap allocation failed\n");
|
| 418 | return PTR_ERR(pcf85363->regmap);
|
| 419 | }
|
| 420 |
|
| 421 | i2c_set_clientdata(client, pcf85363);
|
| 422 |
|
| 423 | pcf85363->rtc = devm_rtc_allocate_device(&client->dev);
|
| 424 | if (IS_ERR(pcf85363->rtc))
|
| 425 | return PTR_ERR(pcf85363->rtc);
|
| 426 |
|
| 427 | err = pcf85363_load_capacitance(pcf85363, client->dev.of_node);
|
| 428 | if (err < 0)
|
| 429 | return dev_err_probe(&client->dev, err,
|
| 430 | "failed to set xtal load capacitance\n");
|
| 431 |
|
| 432 | pcf85363->rtc->ops = &rtc_ops;
|
| 433 | pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
| 434 | pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
| 435 |
|
| 436 | wakeup_source = device_property_read_bool(&client->dev,
|
| 437 | "wakeup-source");
|
| 438 | if (client->irq > 0 || wakeup_source) {
|
| 439 | err = regmap_write(pcf85363->regmap, CTRL_FLAGS, 0);
|
| 440 | if (err)
|
| 441 | return dev_err_probe(&client->dev, err,
|
| 442 | "failed to clear flags\n");
|
| 443 |
|
| 444 | err = regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO,
|
| 445 | PIN_IO_INTAPM, PIN_IO_INTA_OUT);
|
| 446 | if (err)
|
| 447 | return dev_err_probe(&client->dev, err,
|
| 448 | "failed to set interrupt pin mode\n");
|
| 449 | }
|
| 450 |
|
| 451 | if (client->irq > 0) {
|
| 452 | unsigned long irqflags = IRQF_TRIGGER_LOW;
|
| 453 |
|
| 454 | if (dev_fwnode(&client->dev))
|
| 455 | irqflags = 0;
|
| 456 | ret = devm_request_threaded_irq(&client->dev, client->irq,
|
| 457 | NULL, pcf85363_rtc_handle_irq,
|
| 458 | irqflags | IRQF_ONESHOT,
|
| 459 | "pcf85363", client);
|
| 460 | if (ret) {
|
| 461 | dev_warn(&client->dev,
|
| 462 | "unable to request IRQ, alarms disabled\n");
|
| 463 | client->irq = 0;
|
| 464 | }
|
| 465 | }
|
| 466 |
|
| 467 | if (client->irq > 0 || wakeup_source) {
|
| 468 | device_init_wakeup(&client->dev, true);
|
| 469 | set_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
|
| 470 | } else {
|
| 471 | clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
|
| 472 | }
|
| 473 |
|
| 474 | ret = devm_rtc_register_device(pcf85363->rtc);
|
| 475 |
|
| 476 | for (i = 0; i < config->num_nvram; i++) {
|
| 477 | nvmem_cfg[i].priv = pcf85363;
|
| 478 | devm_rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg[i]);
|
| 479 | }
|
| 480 |
|
| 481 | return ret;
|
| 482 | }
|
| 483 |
|
| 484 | static const __maybe_unused struct of_device_id dev_ids[] = {
|
| 485 | { .compatible = "nxp,pcf85263", .data = &pcf_85263_config },
|
| 486 | { .compatible = "nxp,pcf85363", .data = &pcf_85363_config },
|
| 487 | { }
|
| 488 | };
|
| 489 | MODULE_DEVICE_TABLE(of, dev_ids);
|
| 490 |
|
| 491 | static struct i2c_driver pcf85363_driver = {
|
| 492 | .driver = {
|
| 493 | .name = "pcf85363",
|
| 494 | .of_match_table = of_match_ptr(dev_ids),
|
| 495 | },
|
| 496 | .probe = pcf85363_probe,
|
| 497 | };
|
| 498 |
|
| 499 | module_i2c_driver(pcf85363_driver);
|
| 500 |
|
| 501 | MODULE_AUTHOR("Eric Nelson");
|
| 502 | MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver");
|
| 503 | MODULE_LICENSE("GPL");
|