pmic: rockchip: Split the rtc part in its own file

Even if for now all the RTC-related register are at the same offset don't
use some hardcoded values for them but set them based on the PMIC type.

No functional changes intended.
This commit is contained in:
Emmanuel Vadot 2021-11-11 20:41:52 +01:00
parent c9b101d241
commit 328077bb8f
4 changed files with 289 additions and 167 deletions

View file

@ -541,6 +541,7 @@ arm64/rockchip/rk_dwc3.c optional fdt rk_dwc3 soc_rockchip_rk3399
arm64/rockchip/rk_i2c.c optional fdt rk_i2c soc_rockchip_rk3328 | fdt rk_i2c soc_rockchip_rk3399
arm64/rockchip/rk_i2s.c optional fdt sound soc_rockchip_rk3328 | fdt sound soc_rockchip_rk3399
dev/iicbus/pmic/rockchip/rk805.c optional fdt rk805 soc_rockchip_rk3328 | fdt rk805 soc_rockchip_rk3399
dev/iicbus/pmic/rockchip/rk8xx_rtc.c optional fdt rk805 soc_rockchip_rk3328 | fdt rk805 soc_rockchip_rk3399
arm64/rockchip/rk_grf.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399
arm64/rockchip/rk_pinctrl.c optional fdt rk_pinctrl soc_rockchip_rk3328 | fdt rk_pinctrl soc_rockchip_rk3399
arm64/rockchip/rk_gpio.c optional fdt rk_gpio soc_rockchip_rk3328 | fdt rk_gpio soc_rockchip_rk3399

View file

@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <dev/iicbus/pmic/rockchip/rk805reg.h>
#include <dev/iicbus/pmic/rockchip/rk808reg.h>
#include <dev/iicbus/pmic/rockchip/rk8xx.h>
#include "clock_if.h"
#include "regdev_if.h"
@ -59,55 +60,12 @@ MALLOC_DEFINE(M_RK805_REG, "RK805 regulator", "RK805 power regulator");
/* #define dprintf(sc, format, arg...) device_printf(sc->base_dev, "%s: " format, __func__, arg) */
#define dprintf(sc, format, arg...)
enum rk_pmic_type {
RK805 = 1,
RK808,
};
static struct ofw_compat_data compat_data[] = {
{"rockchip,rk805", RK805},
{"rockchip,rk808", RK808},
{NULL, 0}
};
struct rk8xx_regdef {
intptr_t id;
char *name;
uint8_t enable_reg;
uint8_t enable_mask;
uint8_t voltage_reg;
uint8_t voltage_mask;
int voltage_min;
int voltage_max;
int voltage_step;
int voltage_nstep;
};
struct rk8xx_reg_sc {
struct regnode *regnode;
device_t base_dev;
struct rk8xx_regdef *def;
phandle_t xref;
struct regnode_std_param *param;
};
struct reg_list {
TAILQ_ENTRY(reg_list) next;
struct rk8xx_reg_sc *reg;
};
struct rk8xx_softc {
device_t dev;
struct mtx mtx;
struct resource * res[1];
void * intrcookie;
struct intr_config_hook intr_hook;
enum rk_pmic_type type;
TAILQ_HEAD(, reg_list) regs;
int nregs;
};
static int rk8xx_regnode_status(struct regnode *regnode, int *status);
static int rk8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
int max_uvolt, int *udelay);
@ -352,7 +310,7 @@ static struct rk8xx_regdef rk808_regdefs[] = {
},
};
static int
int
rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
int err;
@ -361,7 +319,7 @@ rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
return (err);
}
static int
int
rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
@ -748,128 +706,6 @@ rk8xx_start(void *pdev)
config_intrhook_disestablish(&sc->intr_hook);
}
static int
rk8xx_gettime(device_t dev, struct timespec *ts)
{
struct bcd_clocktime bct;
uint8_t data[7];
uint8_t ctrl;
int error;
/* Latch the RTC value into the shadow registers and set 24hr mode */
error = rk8xx_read(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= RK805_RTC_READSEL;
ctrl &= ~(RK805_RTC_AMPM_MODE | RK805_RTC_GET_TIME);
error = rk8xx_write(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= RK805_RTC_GET_TIME;
error = rk8xx_write(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
ctrl &= ~RK805_RTC_GET_TIME;
error = rk8xx_write(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
/* This works as long as RK805_RTC_SECS = 0 */
error = rk8xx_read(dev, RK805_RTC_SECS, data, 7);
if (error != 0)
return (error);
/*
* If the reported year is earlier than 2019, assume the clock is unset.
* This is both later than the reset value for the RK805 and RK808 as
* well as being prior to the current time.
*/
if (data[RK805_RTC_YEARS] < 0x19)
return (EINVAL);
memset(&bct, 0, sizeof(bct));
bct.year = data[RK805_RTC_YEARS];
bct.mon = data[RK805_RTC_MONTHS] & RK805_RTC_MONTHS_MASK;
bct.day = data[RK805_RTC_DAYS] & RK805_RTC_DAYS_MASK;
bct.hour = data[RK805_RTC_HOURS] & RK805_RTC_HOURS_MASK;
bct.min = data[RK805_RTC_MINUTES] & RK805_RTC_MINUTES_MASK;
bct.sec = data[RK805_RTC_SECS] & RK805_RTC_SECS_MASK;
bct.dow = data[RK805_RTC_WEEKS] & RK805_RTC_WEEKS_MASK;
/* The day of week is reported as 1-7 with 1 = Monday */
if (bct.dow == 7)
bct.dow = 0;
bct.ispm = 0;
if (bootverbose)
device_printf(dev, "Read RTC: %02x-%02x-%02x %02x:%02x:%02x\n",
bct.year, bct.mon, bct.day, bct.hour, bct.min, bct.sec);
return (clock_bcd_to_ts(&bct, ts, false));
}
static int
rk8xx_settime(device_t dev, struct timespec *ts)
{
struct bcd_clocktime bct;
uint8_t data[7];
int error;
uint8_t ctrl;
clock_ts_to_bcd(ts, &bct, false);
/* This works as long as RK805_RTC_SECS = 0 */
data[RK805_RTC_YEARS] = bct.year;
data[RK805_RTC_MONTHS] = bct.mon;
data[RK805_RTC_DAYS] = bct.day;
data[RK805_RTC_HOURS] = bct.hour;
data[RK805_RTC_MINUTES] = bct.min;
data[RK805_RTC_SECS] = bct.sec;
data[RK805_RTC_WEEKS] = bct.dow;
/* The day of week is reported as 1-7 with 1 = Monday */
if (data[RK805_RTC_WEEKS] == 0)
data[RK805_RTC_WEEKS] = 7;
error = rk8xx_read(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= RK805_RTC_CTRL_STOP;
ctrl &= ~RK805_RTC_AMPM_MODE;
error = rk8xx_write(dev, RK805_RTC_CTRL, &ctrl, 1);
if (error != 0)
return (error);
error = rk8xx_write(dev, RK805_RTC_SECS, data, 7);
ctrl &= ~RK805_RTC_CTRL_STOP;
rk8xx_write(dev, RK805_RTC_CTRL, &ctrl, 1);
return (error);
}
static void
rk805_poweroff(void *arg, int howto)
{
device_t dev = arg;
int error;
uint8_t val;
if ((howto & RB_POWEROFF) == 0)
return;
device_printf(dev, "Powering off...\n");
error = rk805_read(dev, RK805_DEV_CTRL, &val, 1);
if (error == 0) {
val |= RK805_DEV_CTRL_OFF;
error = rk805_write(dev, RK805_DEV_CTRL, &val, 1);
/* Wait a bit for the command to take effect. */
if (error == 0)
DELAY(100);
}
device_printf(dev, "Power off failed\n");
}
static int
rk8xx_attach(device_t dev)
{
@ -896,10 +732,44 @@ rk8xx_attach(device_t dev)
case RK805:
regdefs = rk805_regdefs;
sc->nregs = nitems(rk805_regdefs);
sc->rtc_regs.secs = RK805_RTC_SECS;
sc->rtc_regs.secs_mask = RK805_RTC_SECS_MASK;
sc->rtc_regs.minutes = RK805_RTC_MINUTES;
sc->rtc_regs.minutes_mask = RK805_RTC_MINUTES_MASK;
sc->rtc_regs.hours = RK805_RTC_HOURS;
sc->rtc_regs.hours_mask = RK805_RTC_HOURS_MASK;
sc->rtc_regs.days = RK805_RTC_DAYS;
sc->rtc_regs.days_mask = RK805_RTC_DAYS_MASK;
sc->rtc_regs.months = RK805_RTC_MONTHS;
sc->rtc_regs.months_mask = RK805_RTC_MONTHS_MASK;
sc->rtc_regs.years = RK805_RTC_YEARS;
sc->rtc_regs.weeks = RK805_RTC_WEEKS_MASK;
sc->rtc_regs.ctrl = RK805_RTC_CTRL;
sc->rtc_regs.ctrl_stop_mask = RK805_RTC_CTRL_STOP;
sc->rtc_regs.ctrl_ampm_mask = RK805_RTC_AMPM_MODE;
sc->rtc_regs.ctrl_gettime_mask = RK805_RTC_GET_TIME;
sc->rtc_regs.ctrl_readsel_mask = RK805_RTC_READSEL;
break;
case RK808:
regdefs = rk808_regdefs;
sc->nregs = nitems(rk808_regdefs);
sc->rtc_regs.secs = RK808_RTC_SECS;
sc->rtc_regs.secs_mask = RK808_RTC_SECS_MASK;
sc->rtc_regs.minutes = RK808_RTC_MINUTES;
sc->rtc_regs.minutes_mask = RK808_RTC_MINUTES_MASK;
sc->rtc_regs.hours = RK808_RTC_HOURS;
sc->rtc_regs.hours_mask = RK808_RTC_HOURS_MASK;
sc->rtc_regs.days = RK808_RTC_DAYS;
sc->rtc_regs.days_mask = RK808_RTC_DAYS_MASK;
sc->rtc_regs.months = RK808_RTC_MONTHS;
sc->rtc_regs.months_mask = RK808_RTC_MONTHS_MASK;
sc->rtc_regs.years = RK808_RTC_YEARS;
sc->rtc_regs.weeks = RK808_RTC_WEEKS_MASK;
sc->rtc_regs.ctrl = RK808_RTC_CTRL;
sc->rtc_regs.ctrl_stop_mask = RK808_RTC_CTRL_STOP;
sc->rtc_regs.ctrl_ampm_mask = RK808_RTC_AMPM_MODE;
sc->rtc_regs.ctrl_gettime_mask = RK808_RTC_GET_TIME;
sc->rtc_regs.ctrl_readsel_mask = RK808_RTC_READSEL;
break;
default:
device_printf(dev, "Unknown type %d\n", sc->type);

View file

@ -0,0 +1,109 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Emmanuel Vadot <manu@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _RK8XX_H_
#define _RK8XX_H_
#include <sys/kernel.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
enum rk_pmic_type {
RK805 = 1,
RK808,
};
struct rk8xx_regdef {
intptr_t id;
char *name;
uint8_t enable_reg;
uint8_t enable_mask;
uint8_t voltage_reg;
uint8_t voltage_mask;
int voltage_min;
int voltage_max;
int voltage_step;
int voltage_nstep;
};
struct rk8xx_reg_sc {
struct regnode *regnode;
device_t base_dev;
struct rk8xx_regdef *def;
phandle_t xref;
struct regnode_std_param *param;
};
struct reg_list {
TAILQ_ENTRY(reg_list) next;
struct rk8xx_reg_sc *reg;
};
struct rk8xx_rtc_reg {
uint8_t secs;
uint8_t secs_mask;
uint8_t minutes;
uint8_t minutes_mask;
uint8_t hours;
uint8_t hours_mask;
uint8_t days;
uint8_t days_mask;
uint8_t months;
uint8_t months_mask;
uint8_t years;
uint8_t weeks;
uint8_t weeks_mask;
uint8_t ctrl;
uint8_t ctrl_stop_mask;
uint8_t ctrl_ampm_mask;
uint8_t ctrl_gettime_mask;
uint8_t ctrl_readsel_mask;
};
struct rk8xx_softc {
device_t dev;
struct mtx mtx;
struct resource * res[1];
void * intrcookie;
struct intr_config_hook intr_hook;
enum rk_pmic_type type;
TAILQ_HEAD(, reg_list) regs;
int nregs;
struct rk8xx_rtc_reg rtc_regs;
};
int rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size);
int rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size);
/* rk8xx_rtc.c */
int rk8xx_gettime(device_t dev, struct timespec *ts);
int rk8xx_settime(device_t dev, struct timespec *ts);
#endif /* _RK8XX_H_ */

View file

@ -0,0 +1,142 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Emmanuel Vadot <manu@FreeBSD.org>
* Copyright (c) 2021 Peter Jeremy <peterj@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/systm.h>
#include <sys/clock.h>
#include <dev/iicbus/pmic/rockchip/rk8xx.h>
int
rk8xx_gettime(device_t dev, struct timespec *ts)
{
struct rk8xx_softc *sc;
struct bcd_clocktime bct;
uint8_t data[7];
uint8_t ctrl;
int error;
sc = device_get_softc(dev);
/* Latch the RTC value into the shadow registers and set 24hr mode */
error = rk8xx_read(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= sc->rtc_regs.ctrl_readsel_mask;
ctrl &= ~(sc->rtc_regs.ctrl_ampm_mask | sc->rtc_regs.ctrl_gettime_mask);
error = rk8xx_write(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= sc->rtc_regs.ctrl_gettime_mask;
error = rk8xx_write(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
ctrl &= ~sc->rtc_regs.ctrl_gettime_mask;
error = rk8xx_write(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
/* This works as long as sc->rtc_regs.secs = 0 */
error = rk8xx_read(dev, sc->rtc_regs.secs, data, 7);
if (error != 0)
return (error);
/*
* If the reported year is earlier than 2019, assume the clock is unset.
* This is both later than the reset value for the RK805 and RK808 as
* well as being prior to the current time.
*/
if (data[sc->rtc_regs.years] < 0x19)
return (EINVAL);
memset(&bct, 0, sizeof(bct));
bct.year = data[sc->rtc_regs.years];
bct.mon = data[sc->rtc_regs.months] & sc->rtc_regs.months_mask;
bct.day = data[sc->rtc_regs.days] & sc->rtc_regs.days_mask;
bct.hour = data[sc->rtc_regs.hours] & sc->rtc_regs.hours_mask;
bct.min = data[sc->rtc_regs.minutes] & sc->rtc_regs.minutes_mask;
bct.sec = data[sc->rtc_regs.secs] & sc->rtc_regs.secs_mask;
bct.dow = data[sc->rtc_regs.weeks] & sc->rtc_regs.weeks_mask;
/* The day of week is reported as 1-7 with 1 = Monday */
if (bct.dow == 7)
bct.dow = 0;
bct.ispm = 0;
if (bootverbose)
device_printf(dev, "Read RTC: %02x-%02x-%02x %02x:%02x:%02x\n",
bct.year, bct.mon, bct.day, bct.hour, bct.min, bct.sec);
return (clock_bcd_to_ts(&bct, ts, false));
}
int
rk8xx_settime(device_t dev, struct timespec *ts)
{
struct rk8xx_softc *sc;
struct bcd_clocktime bct;
uint8_t data[7];
int error;
uint8_t ctrl;
sc = device_get_softc(dev);
clock_ts_to_bcd(ts, &bct, false);
/* This works as long as RK805_RTC_SECS = 0 */
data[sc->rtc_regs.years] = bct.year;
data[sc->rtc_regs.months] = bct.mon;
data[sc->rtc_regs.days] = bct.day;
data[sc->rtc_regs.hours] = bct.hour;
data[sc->rtc_regs.minutes] = bct.min;
data[sc->rtc_regs.secs] = bct.sec;
data[sc->rtc_regs.weeks] = bct.dow;
/* The day of week is reported as 1-7 with 1 = Monday */
if (data[sc->rtc_regs.weeks] == 0)
data[sc->rtc_regs.weeks] = 7;
error = rk8xx_read(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
ctrl |= sc->rtc_regs.ctrl_stop_mask;
ctrl &= ~sc->rtc_regs.ctrl_ampm_mask;
error = rk8xx_write(dev, sc->rtc_regs.ctrl, &ctrl, 1);
if (error != 0)
return (error);
error = rk8xx_write(dev, sc->rtc_regs.secs, data, 7);
ctrl &= ~sc->rtc_regs.ctrl_stop_mask;
rk8xx_write(dev, sc->rtc_regs.ctrl, &ctrl, 1);
return (error);
}