xref: /aosp_15_r20/external/coreboot/src/drivers/i2c/pcf8523/pcf8523.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/bsd/bcd.h>
4 #include <console/console.h>
5 #include <device/smbus.h>
6 #include <version.h>
7 #include "chip.h"
8 
9 /* Set RTC date from coreboot build date. */
pcf8523_set_build_date(struct device * dev)10 static void pcf8523_set_build_date(struct device *dev)
11 {
12 	smbus_write_byte(dev, YEAR_REG, coreboot_build_date.year);
13 	smbus_write_byte(dev, MONTH_REG, coreboot_build_date.month);
14 	smbus_write_byte(dev, WEEKDAY_REG, coreboot_build_date.weekday);
15 	smbus_write_byte(dev, DAY_REG, coreboot_build_date.day);
16 }
17 
18 /* Set RTC date from user defined date (available in e.g. device tree). */
pcf8523_set_user_date(struct device * dev)19 static void pcf8523_set_user_date(struct device *dev)
20 {
21 	struct drivers_i2c_pcf8523_config *config = dev->chip_info;
22 	smbus_write_byte(dev, YEAR_REG, bin2bcd(config->user_year));
23 	smbus_write_byte(dev, MONTH_REG, bin2bcd(config->user_month));
24 	smbus_write_byte(dev, DAY_REG, bin2bcd(config->user_day));
25 	smbus_write_byte(dev, WEEKDAY_REG, bin2bcd(config->user_weekday));
26 }
27 
pcf8523_final(struct device * dev)28 static void pcf8523_final(struct device *dev)
29 {
30 	/* Read back current RTC date and time and print it to the console. */
31 	printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n",
32 		dev->chip_ops->name,
33 		bcd2bin(smbus_read_byte(dev, MONTH_REG)),
34 		bcd2bin(smbus_read_byte(dev, DAY_REG)),
35 		bcd2bin(smbus_read_byte(dev, YEAR_REG)),
36 		bcd2bin(smbus_read_byte(dev, HOUR_REG)),
37 		bcd2bin(smbus_read_byte(dev, MINUTE_REG)),
38 		bcd2bin(smbus_read_byte(dev, SECOND_REG)) & ~OS_BIT);
39 }
40 
pcf8523_init(struct device * dev)41 static void pcf8523_init(struct device *dev)
42 {
43 	struct drivers_i2c_pcf8523_config *config = dev->chip_info;
44 	uint8_t reg = 0;
45 
46 	if (!(smbus_read_byte(dev, SECOND_REG) & OS_BIT)) {
47 		/* Set control registers to a known good value even if no
48 		 * power loss event was recognized. There were issues with
49 		 * this RTC in the past where control registers were
50 		 * corrupted and OS bit was not set. */
51 		reg = smbus_read_byte(dev, CTRL_REG_1);
52 		reg &= ~(STOP_BIT | CAP_SEL);
53 		reg |= ((!!config->cap_sel) << 7);
54 		smbus_write_byte(dev, CTRL_REG_1, reg);
55 		reg = smbus_read_byte(dev, CTRL_REG_3);
56 		reg &= ~PM_MASK;
57 		reg |= ((config->power_mode & 0x07) << 5);
58 		smbus_write_byte(dev, CTRL_REG_3, reg);
59 		reg = smbus_read_byte(dev, TMR_CLKOUT_REG);
60 		reg &= ~COF_MASK;
61 		reg |= ((config->cof_selection & 0x07) << 3);
62 		smbus_write_byte(dev, TMR_CLKOUT_REG, reg);
63 		return;
64 	}
65 
66 	/* Initialize the RTC fully only if a power-loss event was recognized.
67 	 * In this case RTC will be set up with default date and time. */
68 	smbus_write_byte(dev, CTRL_REG_1, ((!!config->cap_sel) << 7) |
69 					  ((!!config->second_int_en) << 2) |
70 					  ((!!config->alarm_int_en) << 1) |
71 					  (!!config->correction_int_en));
72 
73 	smbus_write_byte(dev, CTRL_REG_2, ((!!config->wdt_int_en) << 2) |
74 					  ((!!config->tmrA_int_en) << 1) |
75 					  (!!config->tmrB_int_en));
76 
77 	smbus_write_byte(dev, CTRL_REG_3, ((config->power_mode & 0x07) << 5) |
78 					  ((!!config->bat_switch_int_en) << 1) |
79 					  (!!config->bat_low_int_en));
80 
81 	smbus_write_byte(dev, OFFSET_REG, ((!!config->offset_mode) << 7) |
82 					  (config->offset_val & 0x7f));
83 
84 	smbus_write_byte(dev, TMR_CLKOUT_REG, ((!!config->tmrA_int_mode) << 7) |
85 					((!!config->tmrB_int_mode) << 6) |
86 					((config->cof_selection & 0x07) << 3) |
87 					((config->tmrA_mode & 0x03) << 1) |
88 					(!!config->tmrB_mode));
89 
90 	smbus_write_byte(dev, TMR_A_FREQ_REG, (config->tmrA_prescaler & 0x7));
91 
92 	smbus_write_byte(dev, TMR_B_FREQ_REG,  (config->tmrB_prescaler & 0x7) |
93 					((config->tmrB_pulse_cfg & 0x7) << 4));
94 
95 	/* Before setting the clock stop oscillator. */
96 	reg = smbus_read_byte(dev, CTRL_REG_1);
97 	reg |= STOP_BIT;
98 	smbus_write_byte(dev, CTRL_REG_1, reg);
99 	if (config->set_user_date) {
100 		/* Set user date defined in device tree. */
101 		printk(BIOS_DEBUG, "%s: Set to user date\n",
102 			dev->chip_ops->name);
103 		pcf8523_set_user_date(dev);
104 	} else {
105 		/* Set date from coreboot build. */
106 		printk(BIOS_DEBUG, "%s: Set to coreboot build date\n",
107 			dev->chip_ops->name);
108 		pcf8523_set_build_date(dev);
109 	}
110 	/* Set time to 01:00:00 */
111 	smbus_write_byte(dev, HOUR_REG, 1);
112 	smbus_write_byte(dev, MINUTE_REG, 0);
113 	smbus_write_byte(dev, SECOND_REG, 0);
114 	/* Start oscillator again as the clock is set up now */
115 	reg &= ~STOP_BIT;
116 	smbus_write_byte(dev, CTRL_REG_1, reg);
117 }
118 
119 static struct device_operations pcf8523c_ops = {
120 	.read_resources		= noop_read_resources,
121 	.set_resources		= noop_set_resources,
122 	.init			= pcf8523_init,
123 	.final			= pcf8523_final
124 };
125 
pcf8523_enable(struct device * dev)126 static void pcf8523_enable(struct device *dev)
127 {
128 	dev->ops = &pcf8523c_ops;
129 }
130 
131 struct chip_operations drivers_i2c_pcf8523_ops = {
132 	.name = "PCF8523",
133 	.enable_dev = pcf8523_enable
134 };
135