diff options
Diffstat (limited to 'board/samsung')
-rw-r--r-- | board/samsung/e850-96/Makefile | 2 | ||||
-rw-r--r-- | board/samsung/e850-96/acpm.c | 169 | ||||
-rw-r--r-- | board/samsung/e850-96/acpm.h | 27 | ||||
-rw-r--r-- | board/samsung/e850-96/e850-96.c | 97 | ||||
-rw-r--r-- | board/samsung/e850-96/e850-96.env | 2 | ||||
-rw-r--r-- | board/samsung/e850-96/fw.c | 45 | ||||
-rw-r--r-- | board/samsung/e850-96/fw.h | 4 | ||||
-rw-r--r-- | board/samsung/e850-96/pmic.c | 144 | ||||
-rw-r--r-- | board/samsung/e850-96/pmic.h | 14 |
9 files changed, 473 insertions, 31 deletions
diff --git a/board/samsung/e850-96/Makefile b/board/samsung/e850-96/Makefile index 71d46ea3d2b..76b8d47994e 100644 --- a/board/samsung/e850-96/Makefile +++ b/board/samsung/e850-96/Makefile @@ -3,4 +3,4 @@ # Copyright (C) 2024, Linaro Limited # Sam Protsenko <semen.protsenko@linaro.org> -obj-y := e850-96.o fw.o +obj-y := e850-96.o fw.o acpm.o pmic.o diff --git a/board/samsung/e850-96/acpm.c b/board/samsung/e850-96/acpm.c new file mode 100644 index 00000000000..1cc5c6d0e4a --- /dev/null +++ b/board/samsung/e850-96/acpm.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Linaro Ltd. + * Author: Sam Protsenko <semen.protsenko@linaro.org> + * + * ACPM (Active Clock and Power Management) is an IPC protocol for communicating + * with APM (Active Power Management) core. The message exchange between AP + * (Application Processor) and APM is happening by using shared memory in SRAM + * (iRAM) and generating interrupts using Mailbox block. By using this IPC + * interface it's possible to offload power management tasks to APM core, which + * acts as a supervisor for CPU. One of the main tasks of APM is controlling + * PMIC chip over I3C bus. So in order to access PMIC chip registers it's + * recommended to do so by sending corresponding commands to APM via ACPM IPC + * protocol. The IPC interaction sequence looks like this: + * + * AP (CPU) <-> ACPM IPC (Mailbox + SRAM) <-> APM <-> I3C <-> PMIC + * + * This file contains functions for accessing I3C bus via APM block using + * ACPM IPC. + */ + +#include <linux/iopoll.h> +#include <linux/time.h> +#include <asm/io.h> +#include "acpm.h" + +/* Mailbox registers */ +#define MBOX_INTGR0 0x8 /* Interrupt Generation */ +#define MBOX_INTCR1 0x20 /* Interrupt Clear */ +#define MBOX_INTSR1 0x28 /* Interrupt Status */ +#define MBOX_INTGR_OFFSET 16 +#define MBOX_TIMEOUT (1 * USEC_PER_SEC) + +/* APM shared memory registers */ +#define SHMEM_SR0 0x0 +#define SHMEM_SR1 0x4 +#define SHMEM_SR2 0x8 +#define SHMEM_SR3 0xc + +/* IPC functions */ +#define IPC_FUNC_READ 0x0 +#define IPC_FUNC_WRITE 0x1 +/* Command 0 shifts and masks */ +#define IPC_REG_SHIFT 0 +#define IPC_REG_MASK 0xff +#define IPC_TYPE_SHIFT 8 +#define IPC_TYPE_MASK 0xf +#define IPC_CHANNEL_SHIFT 12 +#define IPC_CHANNEL_MASK 0xf +/* Command 1 shifts and masks */ +#define IPC_FUNC_SHIFT 0 +#define IPC_FUNC_MASK 0xff +#define IPC_WRITE_VAL_SHIFT 8 +#define IPC_WRITE_VAL_MASK 0xff +/* Command 3 shifts and masks */ +#define IPC_DEST_SHIFT 8 +#define IPC_DEST_MASK 0xff +#define IPC_RETURN_SHIFT 24 +#define IPC_RETURN_MASK 0xff + +/** + * acpm_ipc_send_data_async() - Send data to I3C block over ACPM IPC + * @acpm: ACPM data + * @cmd0: Command 0 value to send + * @cmd1: Command 1 value to send + */ +static void acpm_ipc_send_data_async(struct acpm *acpm, u32 cmd0, u32 cmd1) +{ + u32 irq_bit = 1 << acpm->ipc_ch; + u32 intgr = irq_bit << MBOX_INTGR_OFFSET; + + /* Write data to the shared memory */ + writel(cmd0, acpm->sram_base + SHMEM_SR0); + writel(cmd1, acpm->sram_base + SHMEM_SR1); + dsb(); + + /* Generate interrupt for I3C block */ + writel(intgr, acpm->mbox_base + MBOX_INTGR0); +} + +/** + * acpm_ipc_wait_resp() - Read response data from I3C block over ACPM IPC + * @acpm: ACPM data + * @cmd2: Will contain read value for command 2 + * @cmd3: Will contain read value for command 3 + * + * Return: 0 on success or negative value on error. + */ +static int acpm_ipc_wait_resp(struct acpm *acpm, u32 *cmd2, u32 *cmd3) +{ + u32 irq_bit = 1 << acpm->ipc_ch; + u32 reg; + int ret; + + /* Wait for the interrupt from I3C block */ + ret = readl_poll_timeout(acpm->mbox_base + MBOX_INTSR1, reg, + reg & irq_bit, MBOX_TIMEOUT); + if (ret < 0) + return ret; + + /* Clear the interrupt */ + writel(irq_bit, acpm->mbox_base + MBOX_INTCR1); + + /* Read data from the shared memory */ + *cmd2 = readl(acpm->sram_base + SHMEM_SR2); + *cmd3 = readl(acpm->sram_base + SHMEM_SR3); + + return 0; +} + +/** + * acpm_i3c_read() - Read an I3C register of some I3C slave device + * @acpm: ACPM data + * @ch: I3C channel (bus) number (0-15) + * @addr: I3C address of slave device (0-15) + * @reg: Address of I3C register in the slave device to read from + * @val: Will contain the read value + * + * Return: 0 on success or non-zero code on error (may be positive). + */ +int acpm_i3c_read(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 *val) +{ + u32 cmd[4] = { 0 }; + u8 ret; + + cmd[0] = (ch & IPC_CHANNEL_MASK) << IPC_CHANNEL_SHIFT | + (addr & IPC_TYPE_MASK) << IPC_TYPE_SHIFT | + (reg & IPC_REG_MASK) << IPC_REG_SHIFT; + cmd[1] = IPC_FUNC_READ << IPC_FUNC_SHIFT; + + acpm_ipc_send_data_async(acpm, cmd[0], cmd[1]); + ret = acpm_ipc_wait_resp(acpm, &cmd[2], &cmd[3]); + if (ret) + return ret; + + *val = (cmd[3] >> IPC_DEST_SHIFT) & IPC_DEST_MASK; + ret = (cmd[3] >> IPC_RETURN_SHIFT) & IPC_RETURN_MASK; + return ret; +} + +/** + * acpm_i3c_write() - Write an I3C register of some I3C slave device + * @acpm: ACPM data + * @ch: I3C channel (bus) number (0-15) + * @addr: I3C address of slave device (0-15) + * @reg: Address of I3C register in the slave device to write into + * @val: Value to write + * + * Return: 0 on success or non-zero code on error (may be positive). + */ +int acpm_i3c_write(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 val) +{ + u32 cmd[4] = { 0 }; + u8 ret; + + cmd[0] = (ch & IPC_CHANNEL_MASK) << IPC_CHANNEL_SHIFT | + (addr & IPC_TYPE_MASK) << IPC_TYPE_SHIFT | + (reg & IPC_REG_MASK) << IPC_REG_SHIFT; + cmd[1] = IPC_FUNC_WRITE << IPC_FUNC_SHIFT | + (val & IPC_WRITE_VAL_MASK) << IPC_WRITE_VAL_SHIFT; + + acpm_ipc_send_data_async(acpm, cmd[0], cmd[1]); + ret = acpm_ipc_wait_resp(acpm, &cmd[2], &cmd[3]); + if (ret) + return ret; + + ret = (cmd[3] >> IPC_RETURN_SHIFT) & IPC_RETURN_MASK; + return ret; +} diff --git a/board/samsung/e850-96/acpm.h b/board/samsung/e850-96/acpm.h new file mode 100644 index 00000000000..9373969209f --- /dev/null +++ b/board/samsung/e850-96/acpm.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 Linaro Ltd. + * Sam Protsenko <semen.protsenko@linaro.org> + */ + +#ifndef __E850_96_ACPM_H +#define __E850_96_ACPM_H + +#include <linux/types.h> + +/** + * struct acpm - Data for I3C communication over ACPM IPC protocol + * @mbox_base: Base address of APM mailbox block + * @sram_base: Base address of shared memory used for APM messages + * @ipc_ch: Mailbox channel number used for communication with I3C block (0-15) + */ +struct acpm { + void __iomem *mbox_base; + void __iomem *sram_base; + u8 ipc_ch; +}; + +int acpm_i3c_read(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 *val); +int acpm_i3c_write(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 val); + +#endif /* __E850_96_ACPM_H */ diff --git a/board/samsung/e850-96/e850-96.c b/board/samsung/e850-96/e850-96.c index a6c264d1248..3df241edde2 100644 --- a/board/samsung/e850-96/e850-96.c +++ b/board/samsung/e850-96/e850-96.c @@ -8,13 +8,28 @@ #include <env.h> #include <init.h> #include <mapmem.h> +#include <net.h> +#include <usb.h> #include <asm/io.h> #include "fw.h" +#include "pmic.h" /* OTP Controller base address and register offsets */ -#define EXYNOS850_OTP_BASE 0x10000000 -#define OTP_CHIPID0 0x4 -#define OTP_CHIPID1 0x8 +#define EXYNOS850_OTP_BASE 0x10000000 +#define OTP_CHIPID0 0x4 +#define OTP_CHIPID1 0x8 + +/* ACPM and PMIC definitions */ +#define EXYNOS850_MBOX_APM2AP_BASE 0x11900000 +#define EXYNOS850_APM_SRAM_BASE 0x02039000 /* in iRAM */ +#define EXYNOS850_APM_SHMEM_OFFSET 0x3200 +#define EXYNOS850_IPC_AP_I3C 10 + +/* LDFW firmware definitions */ +#define LDFW_NWD_ADDR 0x88000000 +#define EMMC_IFNAME "mmc" +#define EMMC_DEV_NUM 0 +#define EMMC_ESP_PART 1 struct efi_fw_image fw_images[] = { { @@ -55,6 +70,13 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; +static struct acpm acpm = { + .mbox_base = (void __iomem *)EXYNOS850_MBOX_APM2AP_BASE, + .sram_base = (void __iomem *)(EXYNOS850_APM_SRAM_BASE + + EXYNOS850_APM_SHMEM_OFFSET), + .ipc_ch = EXYNOS850_IPC_AP_I3C, +}; + int dram_init(void) { return fdtdec_setup_mem_size_base(); @@ -92,19 +114,74 @@ static void setup_serial(void) env_set("serial#", serial_str); } -int board_late_init(void) +static void setup_ethaddr(void) +{ + u64 serial_num; + u32 mac_hi, mac_lo; + u8 mac_addr[6]; + + if (env_get("ethaddr")) + return; + + serial_num = get_chip_id(); + mac_lo = (u32)serial_num; /* OTP_CHIPID0 */ + mac_hi = (u32)(serial_num >> 32UL); /* OTP_CHIPID1 */ + mac_addr[0] = (mac_hi >> 8) & 0xff; + mac_addr[1] = mac_hi & 0xff; + mac_addr[2] = (mac_lo >> 24) & 0xff; + mac_addr[3] = (mac_lo >> 16) & 0xff; + mac_addr[4] = (mac_lo >> 8) & 0xff; + mac_addr[5] = mac_lo & 0xff; + mac_addr[0] &= ~0x1; /* make sure it's not a multicast address */ + if (is_valid_ethaddr(mac_addr)) + eth_env_set_enetaddr("ethaddr", mac_addr); +} + +/* + * Call this in board_late_init() to avoid probing block devices before + * efi_init_early(). + */ +void load_firmware(void) { + const char *ifname; + ulong dev, part; int err; + ifname = env_get("bootdev"); + if (!ifname) + ifname = EMMC_IFNAME; + dev = env_get_ulong("bootdevnum", 10, EMMC_DEV_NUM); + part = env_get_ulong("bootdevpart", 10, EMMC_ESP_PART); + + if (!strcmp(ifname, "usb")) { + printf("Starting USB (bootdev=usb)...\n"); + err = usb_init(); + if (err) + return; + } + + printf("Loading LDFW firmware (from %s %ld)...\n", ifname, dev); + err = load_ldfw(ifname, dev, part, LDFW_NWD_ADDR); + if (err) + printf("ERROR: LDFW loading failed (%d)\n", err); +} + +int board_late_init(void) +{ setup_serial(); + setup_ethaddr(); + load_firmware(); - /* - * Do this in board_late_init() to make sure MMC is not probed before - * efi_init_early(). - */ - err = load_ldfw(); + return 0; +} + +int power_init_board(void) +{ + int err; + + err = pmic_init(&acpm); if (err) - printf("ERROR: LDFW loading failed (%d)\n", err); + printf("ERROR: Failed to configure PMIC (%d)\n", err); return 0; } diff --git a/board/samsung/e850-96/e850-96.env b/board/samsung/e850-96/e850-96.env index aed7a71046d..992318b0ab2 100644 --- a/board/samsung/e850-96/e850-96.env +++ b/board/samsung/e850-96/e850-96.env @@ -5,7 +5,7 @@ fdt_addr_r=0x8c000000 scriptaddr=0x8c100000 pxefile_addr_r=0x8c200000 ramdisk_addr_r=0x8c300000 -fdtfile=CONFIG_DEFAULT_FDT_FILE +fdtfile=exynos/exynos850-e850-96.dtb dfu_alt_info= rawemmc raw 0 0x747c000 mmcpart 1; diff --git a/board/samsung/e850-96/fw.c b/board/samsung/e850-96/fw.c index 8f64e759b43..64235c01a25 100644 --- a/board/samsung/e850-96/fw.c +++ b/board/samsung/e850-96/fw.c @@ -11,13 +11,9 @@ #include <linux/arm-smccc.h> #include "fw.h" -#define EMMC_IFACE "mmc" -#define EMMC_DEV_NUM 0 #define LDFW_RAW_PART "ldfw" -#define LDFW_FAT_PART "esp" #define LDFW_FAT_PATH "/EFI/firmware/ldfw.bin" -#define LDFW_NWD_ADDR 0x88000000 #define LDFW_MAGIC 0x10adab1e #define SMC_CMD_LOAD_LDFW -0x500 #define SDM_HW_RESET_STATUS 0x1230 @@ -39,19 +35,23 @@ struct ldfw_header { }; /* Load LDFW binary as a file from FAT partition */ -static int read_fw_from_fat(const char *part_name, const char *path, void *buf) +static int read_fw_from_fat(const char *ifname, int dev, int part, + const char *path, void *buf) { - char dev_part_str[8]; + struct blk_desc *blk_desc; loff_t len_read; int err; - snprintf(dev_part_str, sizeof(dev_part_str), "%d#%s", EMMC_DEV_NUM, - LDFW_FAT_PART); + blk_desc = blk_get_dev(ifname, dev); + if (!blk_desc) { + debug("%s: Can't get block device\n", __func__); + return -ENODEV; + } - err = fs_set_blk_dev(EMMC_IFACE, dev_part_str, FS_TYPE_FAT); + err = fs_set_blk_dev_with_part(blk_desc, part); if (err) { - debug("%s: Can't set block device\n", __func__); - return -ENODEV; + debug("%s: Can't set partition\n", __func__); + return -ENOENT; } err = fs_read(path, (ulong)buf, 0, 0, &len_read); @@ -64,16 +64,17 @@ static int read_fw_from_fat(const char *part_name, const char *path, void *buf) } /* Load LDFW binary from raw partition on block device into RAM buffer */ -static int read_fw_from_raw(const char *part_name, void *buf) +static int read_fw_from_raw(const char *ifname, int dev, const char *part_name, + void *buf) { struct blk_desc *blk_desc; struct disk_partition part; unsigned long cnt; int part_num; - blk_desc = blk_get_dev(EMMC_IFACE, EMMC_DEV_NUM); + blk_desc = blk_get_dev(ifname, dev); if (!blk_desc) { - debug("%s: Can't get eMMC device\n", __func__); + debug("%s: Can't get block device\n", __func__); return -ENODEV; } @@ -92,9 +93,17 @@ static int read_fw_from_raw(const char *part_name, void *buf) return 0; } -int load_ldfw(void) +/** + * load_ldfw - Load the loadable firmware (LDFW) + * @ifname: Interface name of the block device to load the firmware from + * @dev: Device number + * @part: Partition number + * @addr: Temporary memory (Normal World) to use for loading the firmware + * + * Return: 0 on success or a negative value on error. + */ +int load_ldfw(const char *ifname, int dev, int part, phys_addr_t addr) { - const phys_addr_t addr = (phys_addr_t)LDFW_NWD_ADDR; struct ldfw_header *hdr; struct arm_smccc_res res; void *buf = (void *)addr; @@ -102,9 +111,9 @@ int load_ldfw(void) int err, i; /* First try to read LDFW from EFI partition, then from the raw one */ - err = read_fw_from_fat(LDFW_FAT_PART, LDFW_FAT_PATH, buf); + err = read_fw_from_fat(ifname, dev, part, LDFW_FAT_PATH, buf); if (err) { - err = read_fw_from_raw(LDFW_RAW_PART, buf); + err = read_fw_from_raw(ifname, dev, LDFW_RAW_PART, buf); if (err) return err; } diff --git a/board/samsung/e850-96/fw.h b/board/samsung/e850-96/fw.h index 472664e4ed2..73d9615d4a9 100644 --- a/board/samsung/e850-96/fw.h +++ b/board/samsung/e850-96/fw.h @@ -7,6 +7,8 @@ #ifndef __E850_96_FW_H #define __E850_96_FW_H -int load_ldfw(void); +#include <asm/types.h> + +int load_ldfw(const char *ifname, int dev, int part, phys_addr_t addr); #endif /* __E850_96_FW_H */ 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; +} diff --git a/board/samsung/e850-96/pmic.h b/board/samsung/e850-96/pmic.h new file mode 100644 index 00000000000..46624c2ebd4 --- /dev/null +++ b/board/samsung/e850-96/pmic.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 Linaro Ltd. + * Sam Protsenko <semen.protsenko@linaro.org> + */ + +#ifndef __E850_96_PMIC_H +#define __E850_96_PMIC_H + +#include "acpm.h" + +int pmic_init(struct acpm *acpm); + +#endif /* __E850_96_PMIC_H */ |