blob: 743b708c1982b3690322f1c8cb72c49f69b2611f [file] [log] [blame]
Mario Scheithauer7fd20be2017-05-08 16:09:26 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2017 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/i2c.h>
17#include <device/device.h>
18#include <version.h>
19#include <console/console.h>
20#include <bcd.h>
21#include "chip.h"
22#include "rx6110sa.h"
23
24#define I2C_BUS_NUM (dev->bus->secondary - 1)
25#define I2C_DEV_NUM (dev->path.i2c.device)
26
27/* Set RTC date from coreboot build date. */
28static void rx6110sa_set_build_date(struct device *dev)
29{
30 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG,
31 coreboot_build_date.year);
32 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG,
33 coreboot_build_date.month);
34 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG,
35 coreboot_build_date.day);
36 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, WEEK_REG,
37 (1 << coreboot_build_date.weekday));
38}
39
40/* Set RTC date from user defined date (available in e.g. device tree). */
41static void rx6110sa_set_user_date(struct device *dev)
42{
43 struct drivers_i2c_rx6110sa_config *config = dev->chip_info;
44
45 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG,
46 bin2bcd(config->user_year));
47 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG,
48 bin2bcd(config->user_month));
49 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG,
50 bin2bcd(config->user_day));
51 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, WEEK_REG,
52 (1 << config->user_weekday));
53}
54
55static void rx6110sa_final(struct device *dev)
56{
57 uint8_t hour, minute, second, year, month, day;
58
59 /* Read back current RTC date and time and print it to the console. */
60 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, HOUR_REG, &hour);
61 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, MINUTE_REG, &minute);
62 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, &second);
63 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, YEAR_REG, &year);
64 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, MONTH_REG, &month);
65 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, DAY_REG, &day);
66
67 printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n",
68 dev->chip_ops->name, bcd2bin(month), bcd2bin(day),
69 bcd2bin(year), bcd2bin(hour), bcd2bin(minute), bcd2bin(second));
70}
71
72static void rx6110sa_init(struct device *dev)
73{
74 struct drivers_i2c_rx6110sa_config *config = dev->chip_info;
75 uint8_t reg;
76
77 /* Do a dummy read first. */
78 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, &reg);
79
80 /*
81 * Check VLF-bit which indicates the RTC data loss, such as due to a
82 * supply voltage drop.
83 */
84 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, &reg);
85
86 if (!(reg & VLF_BIT))
87 /* No voltage low detected, everything is well. */
88 return;
89
90 /*
91 * Voltage low detected, initialize RX6110 SA again.
92 * Set first some registers to known state.
93 */
94 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, BATTERY_BACKUP_REG, 0x00);
95 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, RESERVED_BIT_REG, RTC_INIT_VALUE);
96 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, DIGITAL_REG, 0x00);
97 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, IRQ_CONTROL_REG, 0x00);
98
99 /* Clear timer enable bit and set frequency of clock output. */
100 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, EXTENSION_REG, &reg);
101 reg &= ~(FSEL_MASK | TE_BIT);
102 reg |= (config->cof_selection << 6);
103 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, EXTENSION_REG, reg);
104
105 /* Clear voltage low detect bit. */
106 i2c_readb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, &reg);
107 reg &= ~VLF_BIT;
108 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, FLAG_REGISTER, reg);
109
110 /* Before setting the clock stop oscillator. */
111 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, CTRL_REG, STOP_BIT);
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 rx6110sa_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 rx6110sa_set_build_date(dev);
122 }
123 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, HOUR_REG, 1);
124 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, MINUTE_REG, 0);
125 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, SECOND_REG, 0);
126 /* Start oscillator again as the RTC is set up now. */
127 i2c_writeb(I2C_BUS_NUM, I2C_DEV_NUM, CTRL_REG, 0x00);
128}
129
130static struct device_operations rx6110sa_ops = {
131 .read_resources = DEVICE_NOOP,
132 .set_resources = DEVICE_NOOP,
133 .enable_resources = DEVICE_NOOP,
134 .init = rx6110sa_init,
135 .final = rx6110sa_final
136};
137
138static void rx6110sa_enable(struct device *dev)
139{
140 dev->ops = &rx6110sa_ops;
141}
142
143struct chip_operations drivers_i2c_rx6110sa_ops = {
144 CHIP_NAME("RX6110 SA")
145 .enable_dev = rx6110sa_enable
146};