pmic: rockchip: Split the driver in rk805 and rk808

This make the base driver cleaner and the subclassed driver only have
related code.

Kernel config wise this is still only handled by rk805.

No functional changes intended.
This commit is contained in:
Emmanuel Vadot 2021-11-14 11:59:55 +01:00
parent cb3c3e0a42
commit 98c60dc31f
7 changed files with 508 additions and 361 deletions

View File

@ -540,7 +540,9 @@ arm64/rockchip/rk3399_emmcphy.c optional fdt rk_emmcphy soc_rockchip_rk3399
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.c optional fdt rk805 soc_rockchip_rk3328 | fdt rk805 soc_rockchip_rk3399
dev/iicbus/pmic/rockchip/rk805.c optional fdt rk805 soc_rockchip_rk3328
dev/iicbus/pmic/rockchip/rk808.c optional fdt rk805 soc_rockchip_rk3399
dev/iicbus/pmic/rockchip/rk8xx_clocks.c optional fdt rk805 soc_rockchip_rk3328 | fdt rk805 soc_rockchip_rk3399
dev/iicbus/pmic/rockchip/rk8xx_regulators.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

View File

@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
* Copyright (c) 2018-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
@ -46,17 +46,10 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#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"
MALLOC_DEFINE(M_RK805_REG, "RK805 regulator", "RK805 power regulator");
static struct ofw_compat_data compat_data[] = {
{"rockchip,rk805", RK805},
{"rockchip,rk808", RK808},
{NULL, 0}
};
@ -141,182 +134,8 @@ static struct rk8xx_regdef rk805_regdefs[] = {
},
};
static struct rk8xx_regdef rk808_regdefs[] = {
{
.id = RK808_BUCK1,
.name = "DCDC_REG1",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x1,
.voltage_reg = RK808_BUCK1_ON_VSEL,
.voltage_mask = 0x3F,
.voltage_min = 712500,
.voltage_max = 1500000,
.voltage_step = 12500,
.voltage_nstep = 64,
},
{
.id = RK808_BUCK2,
.name = "DCDC_REG2",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x2,
.voltage_reg = RK808_BUCK2_ON_VSEL,
.voltage_mask = 0x3F,
.voltage_min = 712500,
.voltage_max = 1500000,
.voltage_step = 12500,
.voltage_nstep = 64,
},
{
/* BUCK3 voltage is calculated based on external resistor */
.id = RK808_BUCK3,
.name = "DCDC_REG3",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x4,
},
{
.id = RK808_BUCK4,
.name = "DCDC_REG4",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x8,
.voltage_reg = RK808_BUCK4_ON_VSEL,
.voltage_mask = 0xF,
.voltage_min = 1800000,
.voltage_max = 3300000,
.voltage_step = 100000,
.voltage_nstep = 16,
},
{
.id = RK808_LDO1,
.name = "LDO_REG1",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x1,
.voltage_reg = RK808_LDO1_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO2,
.name = "LDO_REG2",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x2,
.voltage_reg = RK808_LDO2_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO3,
.name = "LDO_REG3",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x4,
.voltage_reg = RK808_LDO3_ON_VSEL,
.voltage_mask = 0xF,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO4,
.name = "LDO_REG4",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x8,
.voltage_reg = RK808_LDO4_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO5,
.name = "LDO_REG5",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x10,
.voltage_reg = RK808_LDO5_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO6,
.name = "LDO_REG6",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x20,
.voltage_reg = RK808_LDO6_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO7,
.name = "LDO_REG7",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x40,
.voltage_reg = RK808_LDO7_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO8,
.name = "LDO_REG8",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x80,
.voltage_reg = RK808_LDO8_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_SWITCH1,
.name = "SWITCH_REG1",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x20,
.voltage_min = 3000000,
.voltage_max = 3000000,
},
{
.id = RK808_SWITCH2,
.name = "SWITCH_REG2",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x40,
.voltage_min = 3000000,
.voltage_max = 3000000,
},
};
int
rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
int err;
err = iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT);
return (err);
}
int
rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
return (iicdev_writeto(dev, reg, data, size, IIC_INTRWAIT));
}
static int
rk8xx_probe(device_t dev)
rk805_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
@ -324,188 +143,56 @@ rk8xx_probe(device_t dev)
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "RockChip RK8XX PMIC");
device_set_desc(dev, "RockChip RK805 PMIC");
return (BUS_PROBE_DEFAULT);
}
static void
rk8xx_start(void *pdev)
static int
rk805_attach(device_t dev)
{
struct rk8xx_softc *sc;
device_t dev;
uint8_t data[2];
int err;
dev = pdev;
sc = device_get_softc(dev);
sc->dev = dev;
/* No version register in RK808 */
if (bootverbose && sc->type == RK805) {
err = rk8xx_read(dev, RK805_CHIP_NAME, data, 1);
if (err != 0) {
device_printf(dev, "Cannot read chip name reg\n");
return;
}
err = rk8xx_read(dev, RK805_CHIP_VER, data + 1, 1);
if (err != 0) {
device_printf(dev, "Cannot read chip version reg\n");
return;
}
device_printf(dev, "Chip Name: %x\n",
data[0] << 4 | ((data[1] >> 4) & 0xf));
device_printf(dev, "Chip Version: %x\n", data[1] & 0xf);
}
/* Register this as a 1Hz clock */
clock_register(dev, 1000000);
config_intrhook_disestablish(&sc->intr_hook);
}
static int
rk8xx_attach(device_t dev)
{
struct rk8xx_softc *sc;
struct rk8xx_reg_sc *reg;
struct rk8xx_regdef *regdefs;
struct reg_list *regp;
phandle_t rnode, child;
int error, i;
sc = device_get_softc(dev);
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
error = rk8xx_export_clocks(dev);
if (error != 0)
return (error);
sc->intr_hook.ich_func = rk8xx_start;
sc->intr_hook.ich_arg = dev;
if (config_intrhook_establish(&sc->intr_hook) != 0)
return (ENOMEM);
sc->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;
switch (sc->type) {
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);
return (ENXIO);
}
TAILQ_INIT(&sc->regs);
rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators");
if (rnode > 0) {
for (i = 0; i < sc->nregs; i++) {
child = ofw_bus_find_child(rnode,
regdefs[i].name);
if (child == 0)
continue;
if (OF_hasprop(child, "regulator-name") != 1)
continue;
reg = rk8xx_reg_attach(dev, child, &regdefs[i]);
if (reg == NULL) {
device_printf(dev,
"cannot attach regulator %s\n",
regdefs[i].name);
continue;
}
regp = malloc(sizeof(*regp), M_DEVBUF, M_WAITOK | M_ZERO);
regp->reg = reg;
TAILQ_INSERT_TAIL(&sc->regs, regp, next);
if (bootverbose)
device_printf(dev, "Regulator %s attached\n",
regdefs[i].name);
}
}
if (OF_hasprop(ofw_bus_get_node(dev),
"rockchip,system-power-controller")) {
/*
* The priority is chosen to override PSCI and EFI shutdown
* methods as those two just hang without powering off on Rock64
* at least.
*/
EVENTHANDLER_REGISTER(shutdown_final, rk805_poweroff, dev,
SHUTDOWN_PRI_LAST - 2);
}
return (0);
return (rk8xx_attach(sc));
}
static int
rk8xx_detach(device_t dev)
{
/* We cannot detach regulators */
return (EBUSY);
}
static device_method_t rk8xx_methods[] = {
DEVMETHOD(device_probe, rk8xx_probe),
DEVMETHOD(device_attach, rk8xx_attach),
DEVMETHOD(device_detach, rk8xx_detach),
/* regdev interface */
DEVMETHOD(regdev_map, rk8xx_map),
/* Clock interface */
DEVMETHOD(clock_gettime, rk8xx_gettime),
DEVMETHOD(clock_settime, rk8xx_settime),
static device_method_t rk805_methods[] = {
DEVMETHOD(device_probe, rk805_probe),
DEVMETHOD(device_attach, rk805_attach),
DEVMETHOD_END
};
static driver_t rk8xx_driver = {
"rk8xx_pmu",
rk8xx_methods,
sizeof(struct rk8xx_softc),
};
DEFINE_CLASS_1(iichb, rk805_driver, rk805_methods,
sizeof(struct rk8xx_softc), rk8xx_driver);
static devclass_t rk8xx_devclass;
static devclass_t rk805_devclass;
EARLY_DRIVER_MODULE(rk8xx, iicbus, rk8xx_driver, rk8xx_devclass, 0, 0,
EARLY_DRIVER_MODULE(rk805, iicbus, rk805_driver, rk805_devclass, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
MODULE_DEPEND(rk8xx, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
MODULE_VERSION(rk8xx, 1);
MODULE_DEPEND(rk805, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
MODULE_VERSION(rk805, 1);

View File

@ -0,0 +1,273 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2018-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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/iicbus/pmic/rockchip/rk808reg.h>
#include <dev/iicbus/pmic/rockchip/rk8xx.h>
static struct ofw_compat_data compat_data[] = {
{"rockchip,rk808", RK808},
{NULL, 0}
};
static struct rk8xx_regdef rk808_regdefs[] = {
{
.id = RK808_BUCK1,
.name = "DCDC_REG1",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x1,
.voltage_reg = RK808_BUCK1_ON_VSEL,
.voltage_mask = 0x3F,
.voltage_min = 712500,
.voltage_max = 1500000,
.voltage_step = 12500,
.voltage_nstep = 64,
},
{
.id = RK808_BUCK2,
.name = "DCDC_REG2",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x2,
.voltage_reg = RK808_BUCK2_ON_VSEL,
.voltage_mask = 0x3F,
.voltage_min = 712500,
.voltage_max = 1500000,
.voltage_step = 12500,
.voltage_nstep = 64,
},
{
/* BUCK3 voltage is calculated based on external resistor */
.id = RK808_BUCK3,
.name = "DCDC_REG3",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x4,
},
{
.id = RK808_BUCK4,
.name = "DCDC_REG4",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x8,
.voltage_reg = RK808_BUCK4_ON_VSEL,
.voltage_mask = 0xF,
.voltage_min = 1800000,
.voltage_max = 3300000,
.voltage_step = 100000,
.voltage_nstep = 16,
},
{
.id = RK808_LDO1,
.name = "LDO_REG1",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x1,
.voltage_reg = RK808_LDO1_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO2,
.name = "LDO_REG2",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x2,
.voltage_reg = RK808_LDO2_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO3,
.name = "LDO_REG3",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x4,
.voltage_reg = RK808_LDO3_ON_VSEL,
.voltage_mask = 0xF,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO4,
.name = "LDO_REG4",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x8,
.voltage_reg = RK808_LDO4_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO5,
.name = "LDO_REG5",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x10,
.voltage_reg = RK808_LDO5_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_LDO6,
.name = "LDO_REG6",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x20,
.voltage_reg = RK808_LDO6_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO7,
.name = "LDO_REG7",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x40,
.voltage_reg = RK808_LDO7_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 800000,
.voltage_max = 2500000,
.voltage_step = 100000,
.voltage_nstep = 18,
},
{
.id = RK808_LDO8,
.name = "LDO_REG8",
.enable_reg = RK808_LDO_EN,
.enable_mask = 0x80,
.voltage_reg = RK808_LDO8_ON_VSEL,
.voltage_mask = 0x1F,
.voltage_min = 1800000,
.voltage_max = 3400000,
.voltage_step = 100000,
.voltage_nstep = 17,
},
{
.id = RK808_SWITCH1,
.name = "SWITCH_REG1",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x20,
.voltage_min = 3000000,
.voltage_max = 3000000,
},
{
.id = RK808_SWITCH2,
.name = "SWITCH_REG2",
.enable_reg = RK808_DCDC_EN,
.enable_mask = 0x40,
.voltage_min = 3000000,
.voltage_max = 3000000,
},
};
static int
rk808_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
device_set_desc(dev, "RockChip RK808 PMIC");
return (BUS_PROBE_DEFAULT);
}
static int
rk808_attach(device_t dev)
{
struct rk8xx_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
sc->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;
return (rk8xx_attach(sc));
}
static device_method_t rk808_methods[] = {
DEVMETHOD(device_probe, rk808_probe),
DEVMETHOD(device_attach, rk808_attach),
DEVMETHOD_END
};
DEFINE_CLASS_1(iichb, rk808_driver, rk808_methods,
sizeof(struct rk8xx_softc), rk8xx_driver);
static devclass_t rk808_devclass;
EARLY_DRIVER_MODULE(rk808, iicbus, rk808_driver, rk808_devclass, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
MODULE_DEPEND(rk808, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
MODULE_VERSION(rk808, 1);

View File

@ -0,0 +1,145 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2018-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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#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"
int
rk8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
int err;
err = iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT);
return (err);
}
int
rk8xx_write(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
return (iicdev_writeto(dev, reg, data, size, IIC_INTRWAIT));
}
static void
rk8xx_start(void *pdev)
{
struct rk8xx_softc *sc;
device_t dev;
uint8_t data[2];
int err;
dev = pdev;
sc = device_get_softc(dev);
sc->dev = dev;
/* No version register in RK808 */
if (bootverbose && sc->type == RK805) {
err = rk8xx_read(dev, RK805_CHIP_NAME, data, 1);
if (err != 0) {
device_printf(dev, "Cannot read chip name reg\n");
return;
}
err = rk8xx_read(dev, RK805_CHIP_VER, data + 1, 1);
if (err != 0) {
device_printf(dev, "Cannot read chip version reg\n");
return;
}
device_printf(dev, "Chip Name: %x\n",
data[0] << 4 | ((data[1] >> 4) & 0xf));
device_printf(dev, "Chip Version: %x\n", data[1] & 0xf);
}
/* Register this as a 1Hz clock */
clock_register(dev, 1000000);
config_intrhook_disestablish(&sc->intr_hook);
}
int
rk8xx_attach(struct rk8xx_softc *sc)
{
int error;
error = rk8xx_attach_clocks(sc);
if (error != 0)
return (error);
sc->intr_hook.ich_func = rk8xx_start;
sc->intr_hook.ich_arg = sc->dev;
if (config_intrhook_establish(&sc->intr_hook) != 0)
return (ENOMEM);
rk8xx_attach_regulators(sc);
return (0);
}
static int
rk8xx_detach(device_t dev)
{
/* We cannot detach regulators */
return (EBUSY);
}
static device_method_t rk8xx_methods[] = {
DEVMETHOD(device_detach, rk8xx_detach),
/* regdev interface */
DEVMETHOD(regdev_map, rk8xx_map),
/* Clock interface */
DEVMETHOD(clock_gettime, rk8xx_gettime),
DEVMETHOD(clock_settime, rk8xx_settime),
DEVMETHOD_END
};
DEFINE_CLASS_0(rk8xx, rk8xx_driver, rk8xx_methods,
sizeof(struct rk8xx_softc));

View File

@ -93,7 +93,8 @@ struct rk8xx_softc {
struct intr_config_hook intr_hook;
enum rk_pmic_type type;
TAILQ_HEAD(, reg_list) regs;
struct rk8xx_regdef *regdefs;
TAILQ_HEAD(, reg_list) regs;
int nregs;
struct rk8xx_rtc_reg rtc_regs;
@ -102,12 +103,15 @@ struct rk8xx_softc {
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);
DECLARE_CLASS(rk8xx_driver);
int rk8xx_attach(struct rk8xx_softc *sc);
/* rk8xx_clocks.c */
int rk8xx_export_clocks(device_t dev);
int rk8xx_attach_clocks(struct rk8xx_softc *sc);
/* rk8xx_regulators.c */
struct rk8xx_reg_sc *rk8xx_reg_attach(device_t dev, phandle_t node,
struct rk8xx_regdef *def);
void rk8xx_attach_regulators(struct rk8xx_softc *sc);
int rk8xx_map(device_t dev, phandle_t xref, int ncells,
pcell_t *cells, intptr_t *id);

View File

@ -94,7 +94,7 @@ DEFINE_CLASS_1(rk8xx_clk_clknode_1, rk8xx_clk_clknode_class_1,
rk8xx_clk_clknode_class_0);
int
rk8xx_export_clocks(device_t dev)
rk8xx_attach_clocks(struct rk8xx_softc *sc)
{
struct clkdom *clkdom;
struct clknode_init_def clkidef;
@ -104,24 +104,24 @@ rk8xx_export_clocks(device_t dev)
phandle_t node;
int nclks, rv;
node = ofw_bus_get_node(dev);
node = ofw_bus_get_node(sc->dev);
/* clock-output-names are optional. Could use them for clkidef.name. */
nclks = ofw_bus_string_list_to_array(node, "clock-output-names",
&clknames);
clkdom = clkdom_create(dev);
clkdom = clkdom_create(sc->dev);
memset(&clkidef, 0, sizeof(clkidef));
clkidef.id = 0;
clkidef.name = (nclks = 2) ? clknames[0] : "clk32kout1";
clk = clknode_create(clkdom, &rk8xx_clk_clknode_class_0, &clkidef);
if (clk == NULL) {
device_printf(dev, "Cannot create '%s'.\n", clkidef.name);
device_printf(sc->dev, "Cannot create '%s'.\n", clkidef.name);
return (ENXIO);
}
clksc = clknode_get_softc(clk);
clksc->base_dev = dev;
clksc->base_dev = sc->dev;
clknode_register(clkdom, clk);
memset(&clkidef, 0, sizeof(clkidef));
@ -129,16 +129,16 @@ rk8xx_export_clocks(device_t dev)
clkidef.name = (nclks = 2) ? clknames[1] : "clk32kout2";
clk = clknode_create(clkdom, &rk8xx_clk_clknode_class_1, &clkidef);
if (clk == NULL) {
device_printf(dev, "Cannot create '%s'.\n", clkidef.name);
device_printf(sc->dev, "Cannot create '%s'.\n", clkidef.name);
return (ENXIO);
}
clksc = clknode_get_softc(clk);
clksc->base_dev = dev;
clksc->base_dev = sc->dev;
clknode_register(clkdom, clk);
rv = clkdom_finit(clkdom);
if (rv != 0) {
device_printf(dev, "Cannot finalize clkdom initialization: "
device_printf(sc->dev, "Cannot finalize clkdom initialization: "
"%d\n", rv);
return (ENXIO);
}

View File

@ -232,7 +232,7 @@ static regnode_method_t rk8xx_regnode_methods[] = {
DEFINE_CLASS_1(rk8xx_regnode, rk8xx_regnode_class, rk8xx_regnode_methods,
sizeof(struct rk8xx_reg_sc), regnode_class);
struct rk8xx_reg_sc *
static struct rk8xx_reg_sc *
rk8xx_reg_attach(device_t dev, phandle_t node,
struct rk8xx_regdef *def)
{
@ -270,6 +270,42 @@ rk8xx_reg_attach(device_t dev, phandle_t node,
return (reg_sc);
}
void
rk8xx_attach_regulators(struct rk8xx_softc *sc)
{
struct rk8xx_reg_sc *reg;
struct reg_list *regp;
phandle_t rnode, child;
int i;
TAILQ_INIT(&sc->regs);
rnode = ofw_bus_find_child(ofw_bus_get_node(sc->dev), "regulators");
if (rnode > 0) {
for (i = 0; i < sc->nregs; i++) {
child = ofw_bus_find_child(rnode,
sc->regdefs[i].name);
if (child == 0)
continue;
if (OF_hasprop(child, "regulator-name") != 1)
continue;
reg = rk8xx_reg_attach(sc->dev, child, &sc->regdefs[i]);
if (reg == NULL) {
device_printf(sc->dev,
"cannot attach regulator %s\n",
sc->regdefs[i].name);
continue;
}
regp = malloc(sizeof(*regp), M_DEVBUF, M_WAITOK | M_ZERO);
regp->reg = reg;
TAILQ_INSERT_TAIL(&sc->regs, regp, next);
if (bootverbose)
device_printf(sc->dev, "Regulator %s attached\n",
sc->regdefs[i].name);
}
}
}
int
rk8xx_map(device_t dev, phandle_t xref, int ncells,
pcell_t *cells, intptr_t *id)