[coreboot-gerrit] New patch to review for coreboot: drivers/i2c: Add new driver for RTC type PCF8523

Werner Zeh (werner.zeh@siemens.com) gerrit at coreboot.org
Wed Jul 13 08:36:37 CEST 2016


Werner Zeh (werner.zeh at siemens.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15641

-gerrit

commit 291feca5f678d95ba4c7c5bb3b608c8a0cbaff16
Author: Werner Zeh <werner.zeh at siemens.com>
Date:   Wed Jul 13 08:21:22 2016 +0200

    drivers/i2c: Add new driver for RTC type PCF8523
    
    This driver enables the usage of an external RTC chip PCF8523 which is
    connected to the I2C bus. The I2C address of this device is fixed.
    One can change parameters in device tree so that the used set up can be
    adopted in device tree to match the configuration of the device on the
    mainboard.
    
    Change-Id: I2d7e161c9e12b720ec4925f1acfd1dd8ee6ee5f5
    Signed-off-by: Werner Zeh <werner.zeh at siemens.com>
---
 src/drivers/i2c/pcf8523/Kconfig      |  18 +++++
 src/drivers/i2c/pcf8523/Makefile.inc |  16 ++++
 src/drivers/i2c/pcf8523/chip.h       |  44 +++++++++++
 src/drivers/i2c/pcf8523/pcf8523.c    | 148 +++++++++++++++++++++++++++++++++++
 src/drivers/i2c/pcf8523/pcf8523.h    |  97 +++++++++++++++++++++++
 5 files changed, 323 insertions(+)

diff --git a/src/drivers/i2c/pcf8523/Kconfig b/src/drivers/i2c/pcf8523/Kconfig
new file mode 100644
index 0000000..c6d40a2
--- /dev/null
+++ b/src/drivers/i2c/pcf8523/Kconfig
@@ -0,0 +1,18 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright 2016 Siemens AG
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+
+config DRIVERS_I2C_PCF8523
+	bool
+	default n
diff --git a/src/drivers/i2c/pcf8523/Makefile.inc b/src/drivers/i2c/pcf8523/Makefile.inc
new file mode 100644
index 0000000..c4e9a1e
--- /dev/null
+++ b/src/drivers/i2c/pcf8523/Makefile.inc
@@ -0,0 +1,16 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright 2016 Siemens AG
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+
+ramstage-$(CONFIG_DRIVERS_RTC_PCF8523) += pcf8523.c
diff --git a/src/drivers/i2c/pcf8523/chip.h b/src/drivers/i2c/pcf8523/chip.h
new file mode 100644
index 0000000..292d460
--- /dev/null
+++ b/src/drivers/i2c/pcf8523/chip.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2016 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "pcf8523.h"
+
+struct drivers_i2c_pcf8523_config {
+	unsigned char cap_sel;		/* Internal capacitor selection */
+	unsigned char second_int_en;	/* Enable IRQ for seconds */
+	unsigned char alarm_int_en;	/* Enable IRQ for alarm */
+	unsigned char correction_int_en;/* Enable IRQ for corrections */
+	unsigned char wdt_int_en;	/* Enable IRQ for watchdog */
+	unsigned char tmrA_int_en;	/* Enable IRQ for timer A */
+	unsigned char tmrB_int_en;	/* Enable IRQ for timer B */
+	unsigned char power_mode;	/* Set up power mode */
+	unsigned char bat_switch_int_en;/* Enable IRQ for battery switch */
+	unsigned char bat_low_int_en;	/* Enable IRQ for low battery */
+	unsigned char offset_mode;	/* Set up mode how to handle offset */
+	unsigned char offset_val;	/* Value for offset adjustment */
+	unsigned char tmrA_mode;	/* Operation mode of timer A */
+	unsigned char tmrA_int_mode;	/* IRQ mode for timer A */
+	unsigned char tmrB_mode;	/* Operation mode for timer B */
+	unsigned char tmrB_int_mode;	/* IRQ mode for timer B */
+	unsigned char cof_selection;	/* Set up for "clock out" frequency */
+	unsigned char tmrA_prescaler;	/* Prescaler for timer A */
+	unsigned char tmrB_prescaler;	/* Prescaler for timer B */
+	unsigned char tmrB_pulse_cfg;	/* Pulse width config for timer B */
+	unsigned char set_user_date;	/* Use user date from devicetree */
+	unsigned char user_year;	/* User year to set */
+	unsigned char user_month;	/* User month to set */
+	unsigned char user_day;		/* User day to set */
+	unsigned char user_weekday;	/* User weekday to set */
+};
diff --git a/src/drivers/i2c/pcf8523/pcf8523.c b/src/drivers/i2c/pcf8523/pcf8523.c
new file mode 100644
index 0000000..0332306
--- /dev/null
+++ b/src/drivers/i2c/pcf8523/pcf8523.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2016 Siemens AG.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <device/smbus.h>
+#include <version.h>
+#include <console/console.h>
+#include <bcd.h>
+#include "chip.h"
+
+/* Set RTC date from coreboot build date. */
+static void pcf8523_set_build_date (struct device *dev)
+{
+	smbus_write_byte(dev, YEAR_REG, coreboot_build_date.year);
+	smbus_write_byte(dev, MONTH_REG, coreboot_build_date.month);
+	smbus_write_byte(dev, WEEKDAY_REG, coreboot_build_date.weekday);
+	smbus_write_byte(dev, DAY_REG, coreboot_build_date.day);
+}
+
+/* Set RTC date from user defined date (available in e.g. devicetree). */
+static void pcf8523_set_user_date (struct device *dev)
+{
+	struct drivers_i2c_pcf8523_config *config = dev->chip_info;
+	smbus_write_byte(dev, YEAR_REG, bin2bcd(config->user_year));
+	smbus_write_byte(dev, MONTH_REG, bin2bcd(config->user_month));
+	smbus_write_byte(dev, DAY_REG, bin2bcd(config->user_day));
+	smbus_write_byte(dev, WEEKDAY_REG, bin2bcd(config->user_weekday));
+}
+
+static void pcf8523_final(struct device *dev)
+{
+	/* Read back current RTC date and time and print it to the console. */
+	printk(BIOS_INFO, "%s: Current date %02d.%02d.%02d %02d:%02d:%02d\n",
+		dev->chip_ops->name,
+		bcd2bin(smbus_read_byte(dev, MONTH_REG)),
+		bcd2bin(smbus_read_byte(dev, DAY_REG)),
+		bcd2bin(smbus_read_byte(dev, YEAR_REG)),
+		bcd2bin(smbus_read_byte(dev, HOUR_REG)),
+		bcd2bin(smbus_read_byte(dev, MINUTE_REG)),
+		bcd2bin(smbus_read_byte(dev, SECOND_REG)) & ~OS_BIT);
+}
+
+static void pcf8523_init(struct device *dev)
+{
+	struct drivers_i2c_pcf8523_config *config = dev->chip_info;
+	uint8_t reg = 0;
+
+	if (!(smbus_read_byte(dev, SECOND_REG) & OS_BIT)) {
+		/* Set control registers to a known good value even if no
+		 * power loss event was recognized. There were issues with
+		 * this RTC in the past where control registers were
+		 * corrupted and OS bit was not set. */
+		reg = smbus_read_byte(dev, CTRL_REG_1);
+		reg &= ~(STOP_BIT | CAP_SEL);
+		reg |= config->cap_sel;
+		smbus_write_byte(dev, CTRL_REG_1, reg);
+		reg = smbus_read_byte(dev, CTRL_REG_3);
+		reg &= ~PM_MASK;
+		reg |= config->power_mode;
+		smbus_write_byte(dev, CTRL_REG_3, reg);
+		reg = smbus_read_byte(dev, TMR_CLKOUT_REG);
+		reg &= ~COF_MASK;
+		reg |= config->cof_selection;
+		smbus_write_byte(dev, TMR_CLKOUT_REG, reg);
+		return;
+	}
+
+	/* Initialize the RTC fully only if a power-loss event was recognized.
+	 * In this case RTC will set up with default date and time. */
+	smbus_write_byte(dev, CTRL_REG_1, ((!!config->cap_sel) << 7) |
+					  ((!!config->second_int_en) << 2) |
+					  ((!!config->alarm_int_en) << 1) |
+					  (!!config->correction_int_en));
+
+	smbus_write_byte(dev, CTRL_REG_2, ((!!config->wdt_int_en) << 2) |
+					  ((!!config->tmrA_int_en) << 1) |
+					  (!!config->tmrB_int_en));
+
+	smbus_write_byte(dev, CTRL_REG_3, ((config->power_mode & 0x03) << 5) |
+					  ((!!config->bat_switch_int_en) << 1) |
+					  (!!config->bat_low_int_en));
+
+	smbus_write_byte(dev, OFFSET_REG, ((!!config->offset_mode) << 7) |
+					  (config->offset_val & 0x7f));
+
+	smbus_write_byte(dev, TMR_CLKOUT_REG, ((!!config->tmrA_int_mode) << 7) |
+					((!!config->tmrB_int_mode) << 6) |
+					((config->cof_selection & 0x38) << 3) |
+					((config->tmrA_mode & 0x03) << 1) |
+					(!!config->tmrB_mode));
+
+	smbus_write_byte(dev, TMR_A_FREQ_REG, (config->tmrA_prescaler & 0x7));
+
+	smbus_write_byte(dev, TMR_B_FREQ_REG,  (config->tmrB_prescaler & 0x7) |
+					((config->tmrB_pulse_cfg & 0x7) << 4));
+
+	/* Before setting the clock stop oscillator. */
+	reg = smbus_read_byte(dev, CTRL_REG_1);
+	reg |= STOP_BIT;
+	smbus_write_byte(dev, CTRL_REG_1, reg);
+	if (config->set_user_date) {
+		/* Set user date defined in devicetree. */
+		printk(BIOS_DEBUG, "%s: Set to user date\n",
+			dev->chip_ops->name);
+		pcf8523_set_user_date(dev);
+	} else {
+		/* Set date from coreboot build. */
+		printk(BIOS_DEBUG, "%s: Set to coreboot build date\n",
+			dev->chip_ops->name);
+		pcf8523_set_build_date(dev);
+	}
+	/* Set time to 01:00:00 */
+	smbus_write_byte(dev, HOUR_REG, 1);
+	smbus_write_byte(dev, MINUTE_REG, 0);
+	smbus_write_byte(dev, SECOND_REG, 0);
+	/* Start oscillator again as the clock is set up now */
+	reg &= ~STOP_BIT;
+	smbus_write_byte(dev, CTRL_REG_1, reg);
+}
+
+static struct device_operations pcf8523c_ops = {
+	.read_resources		= DEVICE_NOOP,
+	.set_resources		= DEVICE_NOOP,
+	.enable_resources	= DEVICE_NOOP,
+	.init			= pcf8523_init,
+	.final			= pcf8523_final
+};
+
+static void pcf8523_enable(struct device *dev)
+{
+	dev->ops = &pcf8523c_ops;
+}
+
+struct chip_operations drivers_i2c_pcf8523_ops = {
+	CHIP_NAME("PCF8523")
+	.enable_dev = pcf8523_enable
+};
diff --git a/src/drivers/i2c/pcf8523/pcf8523.h b/src/drivers/i2c/pcf8523/pcf8523.h
new file mode 100644
index 0000000..3d86384
--- /dev/null
+++ b/src/drivers/i2c/pcf8523/pcf8523.h
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _I2C_PCF8523_H_
+#define _I2C_PCF8523_H_
+
+/* The address of this RTC is fixed. */
+#define PCF8523_SLAVE_ADR		0x68
+
+/* Register layout */
+#define CTRL_REG_1			0x00
+#define  STOP_BIT			(1 << 5)
+#define  CAP_SEL			(1 << 7)
+#define CTRL_REG_2			0x01
+#define CTRL_REG_3			0x02
+#define  PM_MASK			(7 << 5)
+#define SECOND_REG			0x03
+#define  OS_BIT				(1 << 7)
+#define MINUTE_REG			0x04
+#define HOUR_REG			0x05
+#define DAY_REG				0x06
+#define WEEKDAY_REG			0x07
+#define MONTH_REG			0x08
+#define YEAR_REG			0x09
+#define ALARM_MINUTE_REG		0x0A
+#define ALARM_HOUR_REG			0x0B
+#define ALARM_DAY_REG			0x0C
+#define ALARM_WEEKDAY_REG		0x0D
+#define OFFSET_REG			0x0E
+#define TMR_CLKOUT_REG			0x0F
+#define  COF_MASK			0x38
+#define TMR_A_FREQ_REG			0x10
+#define TMR_A_REG			0x11
+#define TMR_B_FREQ_REG			0x12
+#define TMR_B_REG			0x13
+
+/* Define used capacitor modes */
+/* Valid for parameter cap_sel */
+#define CAP_SEL_7_PF			0x00
+#define CAP_SEL_12_PF			0x01
+
+/* Define supported power modes */
+/* Valid for parameter power_mode */
+#define PM_BAT_SW_STD_LOW_DETECT	0x00
+#define PM_BAT_SW_DIRECT_LOW_DETECT	0x01
+#define PM_BAT_SW_OFF_LOW_DETECT	0x02
+#define PM_BAT_SW_STD_LOW_DETECT_OFF	0x04
+#define PM_BAT_SW_DIRECT_LOW_DETECT_OFF	0x05
+#define PM_BAT_SW_OFF_LOW_DETECT_OFF	0x07
+
+/* Define CLKOUT frequency divider values */
+/* Valid for parameter cof_selection */
+#define COF_32768_HZ			0x00
+#define COF_16384_HZ			0x01
+#define COF_8192_HZ			0x02
+#define COF_4096_HZ			0x03
+#define COF_1024_HZ			0x04
+#define COF_32_HZ			0x05
+#define COF_1_HZ			0x06
+#define COF_OFF				0x07
+
+/* Define timer A & B set up values */
+/* Valid for parameter tmrA_prescaler and tmrB_prescaler */
+#define TMR_CLK_4096_HZ			0x00
+#define TMR_CLK_64_HZ			0x01
+#define TMR_CLK_1_HZ			0x02
+#define TMR_CLK_1_60_HZ			0x03
+#define TMR_CLK_1_3600_HZ		0x07
+
+/* Valid for parameter tmrA_mode and tmrB_mode */
+#define TMR_DISABLED			0x00
+#define TMR_A_MODE_COUNTDOWN		0x01
+#define TMR_A_MODE_WATCHDOG		0x02
+#define TMR_B_MODE_ENABLED		0x01
+
+/* Valid for parameter tmrB_pulse_cfg */
+#define TMR_B_PULSE_WIDTH_46_MS		0x00
+#define TMR_B_PULSE_WIDTH_62_MS		0x01
+#define TMR_B_PULSE_WIDTH_78_MS		0x02
+#define TMR_B_PULSE_WIDTH_93_MS		0x03
+#define TMR_B_PULSE_WIDTH_125_MS	0x04
+#define TMR_B_PULSE_WIDTH_156_MS	0x05
+#define TMR_B_PULSE_WIDTH_187_MS	0x06
+#define TMR_B_PULSE_WIDTH_218_MS	0x07
+
+#endif /* _I2C_PCF8523_H_ */



More information about the coreboot-gerrit mailing list