.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * drivers/rtc/rtc-pcf85363.c |
---|
3 | 4 | * |
---|
4 | 5 | * Driver for NXP PCF85363 real-time clock. |
---|
5 | 6 | * |
---|
6 | 7 | * Copyright (C) 2017 Eric Nelson |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | | - * |
---|
12 | | - * Based loosely on rtc-8583 by Russell King, Wolfram Sang and Juergen Beisert |
---|
13 | 8 | */ |
---|
14 | 9 | #include <linux/module.h> |
---|
15 | 10 | #include <linux/i2c.h> |
---|
.. | .. |
---|
112 | 107 | |
---|
113 | 108 | #define NVRAM_SIZE 0x40 |
---|
114 | 109 | |
---|
115 | | -static struct i2c_driver pcf85363_driver; |
---|
116 | | - |
---|
117 | 110 | struct pcf85363 { |
---|
118 | | - struct device *dev; |
---|
119 | 111 | struct rtc_device *rtc; |
---|
120 | 112 | struct regmap *regmap; |
---|
| 113 | +}; |
---|
| 114 | + |
---|
| 115 | +struct pcf85x63_config { |
---|
| 116 | + struct regmap_config regmap; |
---|
| 117 | + unsigned int num_nvram; |
---|
121 | 118 | }; |
---|
122 | 119 | |
---|
123 | 120 | static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) |
---|
.. | .. |
---|
316 | 313 | val, bytes); |
---|
317 | 314 | } |
---|
318 | 315 | |
---|
319 | | -static const struct regmap_config regmap_config = { |
---|
320 | | - .reg_bits = 8, |
---|
321 | | - .val_bits = 8, |
---|
322 | | - .max_register = 0x7f, |
---|
| 316 | +static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val, |
---|
| 317 | + size_t bytes) |
---|
| 318 | +{ |
---|
| 319 | + struct pcf85363 *pcf85363 = priv; |
---|
| 320 | + unsigned int tmp_val; |
---|
| 321 | + int ret; |
---|
| 322 | + |
---|
| 323 | + ret = regmap_read(pcf85363->regmap, CTRL_RAMBYTE, &tmp_val); |
---|
| 324 | + (*(unsigned char *) val) = (unsigned char) tmp_val; |
---|
| 325 | + |
---|
| 326 | + return ret; |
---|
| 327 | +} |
---|
| 328 | + |
---|
| 329 | +static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val, |
---|
| 330 | + size_t bytes) |
---|
| 331 | +{ |
---|
| 332 | + struct pcf85363 *pcf85363 = priv; |
---|
| 333 | + unsigned char tmp_val; |
---|
| 334 | + |
---|
| 335 | + tmp_val = *((unsigned char *)val); |
---|
| 336 | + return regmap_write(pcf85363->regmap, CTRL_RAMBYTE, |
---|
| 337 | + (unsigned int)tmp_val); |
---|
| 338 | +} |
---|
| 339 | + |
---|
| 340 | +static const struct pcf85x63_config pcf_85263_config = { |
---|
| 341 | + .regmap = { |
---|
| 342 | + .reg_bits = 8, |
---|
| 343 | + .val_bits = 8, |
---|
| 344 | + .max_register = 0x2f, |
---|
| 345 | + }, |
---|
| 346 | + .num_nvram = 1 |
---|
| 347 | +}; |
---|
| 348 | + |
---|
| 349 | +static const struct pcf85x63_config pcf_85363_config = { |
---|
| 350 | + .regmap = { |
---|
| 351 | + .reg_bits = 8, |
---|
| 352 | + .val_bits = 8, |
---|
| 353 | + .max_register = 0x7f, |
---|
| 354 | + }, |
---|
| 355 | + .num_nvram = 2 |
---|
323 | 356 | }; |
---|
324 | 357 | |
---|
325 | 358 | static int pcf85363_probe(struct i2c_client *client, |
---|
326 | 359 | const struct i2c_device_id *id) |
---|
327 | 360 | { |
---|
328 | 361 | struct pcf85363 *pcf85363; |
---|
329 | | - struct nvmem_config nvmem_cfg = { |
---|
330 | | - .name = "pcf85363-", |
---|
331 | | - .word_size = 1, |
---|
332 | | - .stride = 1, |
---|
333 | | - .size = NVRAM_SIZE, |
---|
334 | | - .reg_read = pcf85363_nvram_read, |
---|
335 | | - .reg_write = pcf85363_nvram_write, |
---|
| 362 | + const struct pcf85x63_config *config = &pcf_85363_config; |
---|
| 363 | + const void *data = of_device_get_match_data(&client->dev); |
---|
| 364 | + static struct nvmem_config nvmem_cfg[] = { |
---|
| 365 | + { |
---|
| 366 | + .name = "pcf85x63-", |
---|
| 367 | + .word_size = 1, |
---|
| 368 | + .stride = 1, |
---|
| 369 | + .size = 1, |
---|
| 370 | + .reg_read = pcf85x63_nvram_read, |
---|
| 371 | + .reg_write = pcf85x63_nvram_write, |
---|
| 372 | + }, { |
---|
| 373 | + .name = "pcf85363-", |
---|
| 374 | + .word_size = 1, |
---|
| 375 | + .stride = 1, |
---|
| 376 | + .size = NVRAM_SIZE, |
---|
| 377 | + .reg_read = pcf85363_nvram_read, |
---|
| 378 | + .reg_write = pcf85363_nvram_write, |
---|
| 379 | + }, |
---|
336 | 380 | }; |
---|
337 | | - int ret; |
---|
| 381 | + int ret, i; |
---|
338 | 382 | |
---|
339 | | - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
---|
340 | | - return -ENODEV; |
---|
| 383 | + if (data) |
---|
| 384 | + config = data; |
---|
341 | 385 | |
---|
342 | 386 | pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363), |
---|
343 | 387 | GFP_KERNEL); |
---|
344 | 388 | if (!pcf85363) |
---|
345 | 389 | return -ENOMEM; |
---|
346 | 390 | |
---|
347 | | - pcf85363->regmap = devm_regmap_init_i2c(client, ®map_config); |
---|
| 391 | + pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap); |
---|
348 | 392 | if (IS_ERR(pcf85363->regmap)) { |
---|
349 | 393 | dev_err(&client->dev, "regmap allocation failed\n"); |
---|
350 | 394 | return PTR_ERR(pcf85363->regmap); |
---|
351 | 395 | } |
---|
352 | 396 | |
---|
353 | | - pcf85363->dev = &client->dev; |
---|
354 | 397 | i2c_set_clientdata(client, pcf85363); |
---|
355 | 398 | |
---|
356 | | - pcf85363->rtc = devm_rtc_allocate_device(pcf85363->dev); |
---|
| 399 | + pcf85363->rtc = devm_rtc_allocate_device(&client->dev); |
---|
357 | 400 | if (IS_ERR(pcf85363->rtc)) |
---|
358 | 401 | return PTR_ERR(pcf85363->rtc); |
---|
359 | 402 | |
---|
360 | 403 | pcf85363->rtc->ops = &rtc_ops; |
---|
| 404 | + pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; |
---|
| 405 | + pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; |
---|
361 | 406 | |
---|
362 | 407 | if (client->irq > 0) { |
---|
363 | 408 | regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); |
---|
364 | 409 | regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, |
---|
365 | 410 | PIN_IO_INTA_OUT, PIN_IO_INTAPM); |
---|
366 | | - ret = devm_request_threaded_irq(pcf85363->dev, client->irq, |
---|
| 411 | + ret = devm_request_threaded_irq(&client->dev, client->irq, |
---|
367 | 412 | NULL, pcf85363_rtc_handle_irq, |
---|
368 | 413 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
---|
369 | 414 | "pcf85363", client); |
---|
.. | .. |
---|
375 | 420 | |
---|
376 | 421 | ret = rtc_register_device(pcf85363->rtc); |
---|
377 | 422 | |
---|
378 | | - nvmem_cfg.priv = pcf85363; |
---|
379 | | - rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg); |
---|
| 423 | + for (i = 0; i < config->num_nvram; i++) { |
---|
| 424 | + nvmem_cfg[i].priv = pcf85363; |
---|
| 425 | + rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg[i]); |
---|
| 426 | + } |
---|
380 | 427 | |
---|
381 | 428 | return ret; |
---|
382 | 429 | } |
---|
383 | 430 | |
---|
384 | 431 | static const struct of_device_id dev_ids[] = { |
---|
385 | | - { .compatible = "nxp,pcf85363" }, |
---|
386 | | - {} |
---|
| 432 | + { .compatible = "nxp,pcf85263", .data = &pcf_85263_config }, |
---|
| 433 | + { .compatible = "nxp,pcf85363", .data = &pcf_85363_config }, |
---|
| 434 | + { /* sentinel */ } |
---|
387 | 435 | }; |
---|
388 | 436 | MODULE_DEVICE_TABLE(of, dev_ids); |
---|
389 | 437 | |
---|
.. | .. |
---|
398 | 446 | module_i2c_driver(pcf85363_driver); |
---|
399 | 447 | |
---|
400 | 448 | MODULE_AUTHOR("Eric Nelson"); |
---|
401 | | -MODULE_DESCRIPTION("pcf85363 I2C RTC driver"); |
---|
| 449 | +MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver"); |
---|
402 | 450 | MODULE_LICENSE("GPL"); |
---|