aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorHeiko Schocher <hs@denx.de>2015-10-16 07:31:29 -0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2015-11-08 08:12:29 -0500
commita39a6405d5f949bc651694028a55d74c514ef1f9 (patch)
treee4d7958c093e69a71233c55e91cf73a7c51f2239 /drivers/rtc
parentdbb812b141f3bf3dbea75353da799da3d3373d53 (diff)
rtc: pcf8563: add CLKOUT to common clock framework
Add the clkout output clk to the common clock framework. Disable the CLKOUT of the RTC after power-up. After power-up/reset of the RTC, CLKOUT is enabled by default, with CLKOUT enabled the RTC chip has 2-3 times higher power consumption. Signed-off-by: Heiko Schocher <hs@denx.de> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-pcf8563.c170
1 files changed, 169 insertions, 1 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index e569243db57e..c8f95b8e463a 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -14,6 +14,7 @@
14 * published by the Free Software Foundation. 14 * published by the Free Software Foundation.
15 */ 15 */
16 16
17#include <linux/clk-provider.h>
17#include <linux/i2c.h> 18#include <linux/i2c.h>
18#include <linux/bcd.h> 19#include <linux/bcd.h>
19#include <linux/rtc.h> 20#include <linux/rtc.h>
@@ -40,7 +41,14 @@
40 41
41#define PCF8563_REG_AMN 0x09 /* alarm */ 42#define PCF8563_REG_AMN 0x09 /* alarm */
42 43
43#define PCF8563_REG_CLKO 0x0D /* clock out */ 44#define PCF8563_REG_CLKO 0x0D /* clock out */
45#define PCF8563_REG_CLKO_FE 0x80 /* clock out enabled */
46#define PCF8563_REG_CLKO_F_MASK 0x03 /* frequenc mask */
47#define PCF8563_REG_CLKO_F_32768HZ 0x00
48#define PCF8563_REG_CLKO_F_1024HZ 0x01
49#define PCF8563_REG_CLKO_F_32HZ 0x02
50#define PCF8563_REG_CLKO_F_1HZ 0x03
51
44#define PCF8563_REG_TMRC 0x0E /* timer control */ 52#define PCF8563_REG_TMRC 0x0E /* timer control */
45#define PCF8563_TMRC_ENABLE BIT(7) 53#define PCF8563_TMRC_ENABLE BIT(7)
46#define PCF8563_TMRC_4096 0 54#define PCF8563_TMRC_4096 0
@@ -76,6 +84,9 @@ struct pcf8563 {
76 int voltage_low; /* incicates if a low_voltage was detected */ 84 int voltage_low; /* incicates if a low_voltage was detected */
77 85
78 struct i2c_client *client; 86 struct i2c_client *client;
87#ifdef CONFIG_COMMON_CLK
88 struct clk_hw clkout_hw;
89#endif
79}; 90};
80 91
81static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, 92static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg,
@@ -390,6 +401,158 @@ static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
390 return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); 401 return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
391} 402}
392 403
404#ifdef CONFIG_COMMON_CLK
405/*
406 * Handling of the clkout
407 */
408
409#define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw)
410
411static int clkout_rates[] = {
412 32768,
413 1024,
414 32,
415 1,
416};
417
418static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
419 unsigned long parent_rate)
420{
421 struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
422 struct i2c_client *client = pcf8563->client;
423 unsigned char buf;
424 int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
425
426 if (ret < 0)
427 return 0;
428
429 buf &= PCF8563_REG_CLKO_F_MASK;
430 return clkout_rates[ret];
431}
432
433static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
434 unsigned long *prate)
435{
436 int i;
437
438 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
439 if (clkout_rates[i] <= rate)
440 return clkout_rates[i];
441
442 return 0;
443}
444
445static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
446 unsigned long parent_rate)
447{
448 struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
449 struct i2c_client *client = pcf8563->client;
450 unsigned char buf;
451 int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
452 int i;
453
454 if (ret < 0)
455 return ret;
456
457 for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
458 if (clkout_rates[i] == rate) {
459 buf &= ~PCF8563_REG_CLKO_F_MASK;
460 buf |= i;
461 ret = pcf8563_write_block_data(client,
462 PCF8563_REG_CLKO, 1,
463 &buf);
464 return ret;
465 }
466
467 return -EINVAL;
468}
469
470static int pcf8563_clkout_control(struct clk_hw *hw, bool enable)
471{
472 struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
473 struct i2c_client *client = pcf8563->client;
474 unsigned char buf;
475 int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
476
477 if (ret < 0)
478 return ret;
479
480 if (enable)
481 buf |= PCF8563_REG_CLKO_FE;
482 else
483 buf &= ~PCF8563_REG_CLKO_FE;
484
485 ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
486 return ret;
487}
488
489static int pcf8563_clkout_prepare(struct clk_hw *hw)
490{
491 return pcf8563_clkout_control(hw, 1);
492}
493
494static void pcf8563_clkout_unprepare(struct clk_hw *hw)
495{
496 pcf8563_clkout_control(hw, 0);
497}
498
499static int pcf8563_clkout_is_prepared(struct clk_hw *hw)
500{
501 struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw);
502 struct i2c_client *client = pcf8563->client;
503 unsigned char buf;
504 int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf);
505
506 if (ret < 0)
507 return ret;
508
509 return !!(buf & PCF8563_REG_CLKO_FE);
510}
511
512static const struct clk_ops pcf8563_clkout_ops = {
513 .prepare = pcf8563_clkout_prepare,
514 .unprepare = pcf8563_clkout_unprepare,
515 .is_prepared = pcf8563_clkout_is_prepared,
516 .recalc_rate = pcf8563_clkout_recalc_rate,
517 .round_rate = pcf8563_clkout_round_rate,
518 .set_rate = pcf8563_clkout_set_rate,
519};
520
521static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
522{
523 struct i2c_client *client = pcf8563->client;
524 struct device_node *node = client->dev.of_node;
525 struct clk *clk;
526 struct clk_init_data init;
527 int ret;
528 unsigned char buf;
529
530 /* disable the clkout output */
531 buf = 0;
532 ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf);
533 if (ret < 0)
534 return ERR_PTR(ret);
535
536 init.name = "pcf8563-clkout";
537 init.ops = &pcf8563_clkout_ops;
538 init.flags = CLK_IS_ROOT;
539 init.parent_names = NULL;
540 init.num_parents = 0;
541 pcf8563->clkout_hw.init = &init;
542
543 /* optional override of the clockname */
544 of_property_read_string(node, "clock-output-names", &init.name);
545
546 /* register the clock */
547 clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw);
548
549 if (!IS_ERR(clk))
550 of_clk_add_provider(node, of_clk_src_simple_get, clk);
551
552 return clk;
553}
554#endif
555
393static const struct rtc_class_ops pcf8563_rtc_ops = { 556static const struct rtc_class_ops pcf8563_rtc_ops = {
394 .ioctl = pcf8563_rtc_ioctl, 557 .ioctl = pcf8563_rtc_ioctl,
395 .read_time = pcf8563_rtc_read_time, 558 .read_time = pcf8563_rtc_read_time,
@@ -459,6 +622,11 @@ static int pcf8563_probe(struct i2c_client *client,
459 622
460 } 623 }
461 624
625#ifdef CONFIG_COMMON_CLK
626 /* register clk in common clk framework */
627 pcf8563_clkout_register_clk(pcf8563);
628#endif
629
462 /* the pcf8563 alarm only supports a minute accuracy */ 630 /* the pcf8563 alarm only supports a minute accuracy */
463 pcf8563->rtc->uie_unsupported = 1; 631 pcf8563->rtc->uie_unsupported = 1;
464 632