blob: 416499bce5b2a180047885458b860b68e064f0bd [file] [log] [blame]
Werner Zeh3cad2de2016-07-13 08:21:22 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2016 Siemens AG.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <device/smbus.h>
17#include <version.h>
18#include <console/console.h>
19#include <bcd.h>
20#include "chip.h"
21
22/* Set RTC date from coreboot build date. */
23static void pcf8523_set_build_date(struct device *dev)
24{
25 smbus_write_byte(dev, YEAR_REG, coreboot_build_date.year);
26 smbus_write_byte(dev, MONTH_REG, coreboot_build_date.month);
27 smbus_write_byte(dev, WEEKDAY_REG, coreboot_build_date.weekday);
28 smbus_write_byte(dev, DAY_REG, coreboot_build_date.day);
29}
30
31/* Set RTC date from user defined date (available in e.g. device tree). */
32static void pcf8523_set_user_date(struct device *dev)
33{
34 struct drivers_i2c_pcf8523_config *config = dev->chip_info;
35 smbus_write_byte(dev, YEAR_REG, bin2bcd(config->user_year));
36 smbus_write_byte(dev, MONTH_REG, bin2bcd(config->user_month));
37 smbus_write_byte(dev, DAY_REG, bin2bcd(config->user_day));
38 smbus_write_byte(dev, WEEKDAY_REG, bin2bcd(config->user_weekday));
39}
40
41static void pcf8523_final(struct device *dev)
42{
43 /* Read back current RTC date and time and print it to the console. */
44 printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n",
45 dev->chip_ops->name,
46 bcd2bin(smbus_read_byte(dev, MONTH_REG)),
47 bcd2bin(smbus_read_byte(dev, DAY_REG)),
48 bcd2bin(smbus_read_byte(dev, YEAR_REG)),
49 bcd2bin(smbus_read_byte(dev, HOUR_REG)),
50 bcd2bin(smbus_read_byte(dev, MINUTE_REG)),
51 bcd2bin(smbus_read_byte(dev, SECOND_REG)) & ~OS_BIT);
52}
53
54static void pcf8523_init(struct device *dev)
55{
56 struct drivers_i2c_pcf8523_config *config = dev->chip_info;
57 uint8_t reg = 0;
58
59 if (!(smbus_read_byte(dev, SECOND_REG) & OS_BIT)) {
60 /* Set control registers to a known good value even if no
61 * power loss event was recognized. There were issues with
62 * this RTC in the past where control registers were
63 * corrupted and OS bit was not set. */
64 reg = smbus_read_byte(dev, CTRL_REG_1);
65 reg &= ~(STOP_BIT | CAP_SEL);
Werner Zehf1f322b2016-12-13 08:03:10 +010066 reg |= ((!!config->cap_sel) << 7);
Werner Zeh3cad2de2016-07-13 08:21:22 +020067 smbus_write_byte(dev, CTRL_REG_1, reg);
68 reg = smbus_read_byte(dev, CTRL_REG_3);
69 reg &= ~PM_MASK;
Werner Zehf1f322b2016-12-13 08:03:10 +010070 reg |= ((config->power_mode & 0x07) << 5);
Werner Zeh3cad2de2016-07-13 08:21:22 +020071 smbus_write_byte(dev, CTRL_REG_3, reg);
72 reg = smbus_read_byte(dev, TMR_CLKOUT_REG);
73 reg &= ~COF_MASK;
Werner Zehf1f322b2016-12-13 08:03:10 +010074 reg |= ((config->cof_selection & 0x07) << 3);
Werner Zeh3cad2de2016-07-13 08:21:22 +020075 smbus_write_byte(dev, TMR_CLKOUT_REG, reg);
76 return;
77 }
78
79 /* Initialize the RTC fully only if a power-loss event was recognized.
80 * In this case RTC will be set up with default date and time. */
81 smbus_write_byte(dev, CTRL_REG_1, ((!!config->cap_sel) << 7) |
82 ((!!config->second_int_en) << 2) |
83 ((!!config->alarm_int_en) << 1) |
84 (!!config->correction_int_en));
85
86 smbus_write_byte(dev, CTRL_REG_2, ((!!config->wdt_int_en) << 2) |
87 ((!!config->tmrA_int_en) << 1) |
88 (!!config->tmrB_int_en));
89
Werner Zehf1f322b2016-12-13 08:03:10 +010090 smbus_write_byte(dev, CTRL_REG_3, ((config->power_mode & 0x07) << 5) |
Werner Zeh3cad2de2016-07-13 08:21:22 +020091 ((!!config->bat_switch_int_en) << 1) |
92 (!!config->bat_low_int_en));
93
94 smbus_write_byte(dev, OFFSET_REG, ((!!config->offset_mode) << 7) |
95 (config->offset_val & 0x7f));
96
97 smbus_write_byte(dev, TMR_CLKOUT_REG, ((!!config->tmrA_int_mode) << 7) |
98 ((!!config->tmrB_int_mode) << 6) |
Werner Zehf1f322b2016-12-13 08:03:10 +010099 ((config->cof_selection & 0x07) << 3) |
Werner Zeh3cad2de2016-07-13 08:21:22 +0200100 ((config->tmrA_mode & 0x03) << 1) |
101 (!!config->tmrB_mode));
102
103 smbus_write_byte(dev, TMR_A_FREQ_REG, (config->tmrA_prescaler & 0x7));
104
105 smbus_write_byte(dev, TMR_B_FREQ_REG, (config->tmrB_prescaler & 0x7) |
106 ((config->tmrB_pulse_cfg & 0x7) << 4));
107
108 /* Before setting the clock stop oscillator. */
109 reg = smbus_read_byte(dev, CTRL_REG_1);
110 reg |= STOP_BIT;
111 smbus_write_byte(dev, CTRL_REG_1, reg);
112 if (config->set_user_date) {
113 /* Set user date defined in device tree. */
114 printk(BIOS_DEBUG, "%s: Set to user date\n",
115 dev->chip_ops->name);
116 pcf8523_set_user_date(dev);
117 } else {
118 /* Set date from coreboot build. */
119 printk(BIOS_DEBUG, "%s: Set to coreboot build date\n",
120 dev->chip_ops->name);
121 pcf8523_set_build_date(dev);
122 }
123 /* Set time to 01:00:00 */
124 smbus_write_byte(dev, HOUR_REG, 1);
125 smbus_write_byte(dev, MINUTE_REG, 0);
126 smbus_write_byte(dev, SECOND_REG, 0);
127 /* Start oscillator again as the clock is set up now */
128 reg &= ~STOP_BIT;
129 smbus_write_byte(dev, CTRL_REG_1, reg);
130}
131
132static struct device_operations pcf8523c_ops = {
133 .read_resources = DEVICE_NOOP,
134 .set_resources = DEVICE_NOOP,
135 .enable_resources = DEVICE_NOOP,
136 .init = pcf8523_init,
137 .final = pcf8523_final
138};
139
140static void pcf8523_enable(struct device *dev)
141{
142 dev->ops = &pcf8523c_ops;
143}
144
145struct chip_operations drivers_i2c_pcf8523_ops = {
146 CHIP_NAME("PCF8523")
147 .enable_dev = pcf8523_enable
148};