diff options
Diffstat (limited to 'board/samsung/e850-96/pmic.c')
-rw-r--r-- | board/samsung/e850-96/pmic.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/board/samsung/e850-96/pmic.c b/board/samsung/e850-96/pmic.c new file mode 100644 index 00000000000..037fd4844c5 --- /dev/null +++ b/board/samsung/e850-96/pmic.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Linaro Ltd. + * Author: Sam Protsenko <semen.protsenko@linaro.org> + * + * This file contains functions for S2MPU12 PMIC regulators configuration. + * + * Example of voltage calculation for LDO24 and LDO32: + * - V_min = 1800 mV + * - V_step = 25 mV + * - V_wanted = 3300 mV + * - register value: (V_wanted - V_min) / V_step = 60 = 0x3c + * + * NOTE: 0x3c value might mean different voltage for other LDOs. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include "pmic.h" + +/* PMIC definitions */ +#define S2MPU12_CHANNEL 0 /* I3C bus number of PMIC */ +#define S2MPU12_PM_ADDR 0x1 /* I3C slave addr of PM part */ + +/* PMIC I3C registers */ +#define S2MPU12_PM_LDO1_CTRL 0x2b +#define S2MPU12_PM_LDO_CTRL(n) (S2MPU12_PM_LDO1_CTRL + (n) - 1) + +/* LDOx_CTRL values */ +#define S2MPU12_LDO_CTRL_OUT_MASK (0x3 << 6) +#define S2MPU12_LDO_CTRL_OUT_ALWAYS_ON (0x3 << 6) + +struct pmic_ldo { + u8 num; /* LDO number */ + u8 en; /* "enable" bits value in LDOx_CTRL register */ + u8 out; /* "output voltage" bits value in LDOx_CTRL register */ +}; + +/* List of LDOs to enable only */ +static u8 pmic_ldos_en[] = { + 2, /* 1.8V/450mA: multiple lines */ + 11, /* 3.0V/150mA: AVDD33_USB20 */ + 23, /* 2.85V/800mA: VDD_EMMC_2P85 */ + 27, /* 3.0V/150mA: MIPI_SWITCH_3V3 */ + 28, /* 1.8V/150mA: HDMI_CONV_1V8 */ + 30, /* 1.8V/150mA: NPU_VDD18 */ +}; + +/* List of LDOs to enable and set output voltage */ +static struct pmic_ldo pmic_ldos_en_out[] = { + { + .num = 24, /* 3.0V/800mA: VDD_LAN (LAN9514) */ + .en = S2MPU12_LDO_CTRL_OUT_ALWAYS_ON, + .out = 0x3c, /* means 3.3V for LDO24 */ + }, { + .num = 32, /* 3.3V/300mA: CAM_VDD (RPi camera module) */ + .en = S2MPU12_LDO_CTRL_OUT_ALWAYS_ON, + .out = 0x3c, /* means 3.3V for LDO32 */ + }, +}; + +/* Enable specified LDO */ +static int pmic_ldo_set_en(struct acpm *acpm, u8 ldo) +{ + const u8 reg = S2MPU12_PM_LDO_CTRL(ldo); + u8 val; + int err; + + err = acpm_i3c_read(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, &val); + if (err) + return err; + + val &= ~S2MPU12_LDO_CTRL_OUT_MASK; + val |= S2MPU12_LDO_CTRL_OUT_ALWAYS_ON; + + return acpm_i3c_write(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, val); +} + +/* Enable specified LDO and set its voltage to 0xc0 value */ +static int pmic_ldo_set_en_out(struct acpm *acpm, struct pmic_ldo *ldo) +{ + const u8 reg = S2MPU12_PM_LDO_CTRL(ldo->num); + const u8 val = ldo->en | ldo->out; + + return acpm_i3c_write(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, val); +} + +#ifdef DEBUG +static void pmic_trace_ldo(struct acpm *acpm, u8 ldo) +{ + const u8 reg = S2MPU12_PM_LDO_CTRL(ldo); + u8 val; + int err; + + err = acpm_i3c_read(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, &val); + if (err) + printf(" S2MPU12_PM_LDO%u_CTRL: Read error!\n", ldo); + else + printf(" S2MPU12_PM_LDO%u_CTRL: 0x%x\n", ldo, val); +} + +static void pmic_trace_ldos(struct acpm *acpm) +{ + size_t i; + + printf("Tracing LDOs...\n"); + for (i = 0; i < ARRAY_SIZE(pmic_ldos_en); ++i) + pmic_trace_ldo(acpm, pmic_ldos_en[i]); + for (i = 0; i < ARRAY_SIZE(pmic_ldos_en_out); ++i) + pmic_trace_ldo(acpm, pmic_ldos_en_out[i].num); +} +#endif + +/** + * pmic_init() - Enable power regulators in S2MPU12 PMIC. + * @acpm: Data for I3C communication with PMIC over ACPM protocol + * + * Enable LDOs needed for devices used in the bootloader and kernel. + * + * Return: 0 on success or non-zero code on error. + */ +int pmic_init(struct acpm *acpm) +{ + size_t i; + int err; + + for (i = 0; i < ARRAY_SIZE(pmic_ldos_en); ++i) { + err = pmic_ldo_set_en(acpm, pmic_ldos_en[i]); + if (err) + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(pmic_ldos_en_out); ++i) { + err = pmic_ldo_set_en_out(acpm, &pmic_ldos_en_out[i]); + if (err) + return -EIO; + } + +#ifdef DEBUG + pmic_trace_ldos(acpm); +#endif + + return 0; +} |