forked from Mirrors/opensbi

Since the FDT is not modified during driver initialization, node offsets are just as suitable as phandles for use as identifiers: they are stable and unique. With this change, it is no longer necessary to pass the phandle to the driver init functions, so these init functions now use the same prototype as other kinds of drivers. This matches what is already done for I2C adapters. Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org>
95 lines
1.9 KiB
C
95 lines
1.9 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
|
*
|
|
* Authors:
|
|
* Anup Patel <apatel@ventanamicro.com>
|
|
*/
|
|
|
|
#include <libfdt.h>
|
|
#include <sbi/sbi_error.h>
|
|
#include <sbi_utils/fdt/fdt_helper.h>
|
|
#include <sbi_utils/regmap/fdt_regmap.h>
|
|
|
|
/* List of FDT regmap drivers generated at compile time */
|
|
extern struct fdt_regmap *fdt_regmap_drivers[];
|
|
extern unsigned long fdt_regmap_drivers_size;
|
|
|
|
static int fdt_regmap_init(const void *fdt, int nodeoff)
|
|
{
|
|
int pos, rc;
|
|
struct fdt_regmap *drv;
|
|
const struct fdt_match *match;
|
|
|
|
/* Try all I2C drivers one-by-one */
|
|
for (pos = 0; pos < fdt_regmap_drivers_size; pos++) {
|
|
drv = fdt_regmap_drivers[pos];
|
|
match = fdt_match_node(fdt, nodeoff, drv->match_table);
|
|
if (match && drv->init) {
|
|
rc = drv->init(fdt, nodeoff, match);
|
|
if (rc == SBI_ENODEV)
|
|
continue;
|
|
if (rc)
|
|
return rc;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return SBI_ENOSYS;
|
|
}
|
|
|
|
static int fdt_regmap_find(const void *fdt, int nodeoff,
|
|
struct regmap **out_rmap)
|
|
{
|
|
int rc;
|
|
struct regmap *rmap = regmap_find(nodeoff);
|
|
|
|
if (!rmap) {
|
|
/* Regmap not found so initialize matching driver */
|
|
rc = fdt_regmap_init(fdt, nodeoff);
|
|
if (rc)
|
|
return rc;
|
|
|
|
/* Try to find regmap again */
|
|
rmap = regmap_find(nodeoff);
|
|
if (!rmap)
|
|
return SBI_ENOSYS;
|
|
}
|
|
|
|
if (out_rmap)
|
|
*out_rmap = rmap;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fdt_regmap_get_by_phandle(const void *fdt, u32 phandle,
|
|
struct regmap **out_rmap)
|
|
{
|
|
int pnodeoff;
|
|
|
|
if (!fdt || !out_rmap)
|
|
return SBI_EINVAL;
|
|
|
|
pnodeoff = fdt_node_offset_by_phandle(fdt, phandle);
|
|
if (pnodeoff < 0)
|
|
return pnodeoff;
|
|
|
|
return fdt_regmap_find(fdt, pnodeoff, out_rmap);
|
|
}
|
|
|
|
int fdt_regmap_get(const void *fdt, int nodeoff, struct regmap **out_rmap)
|
|
{
|
|
int len;
|
|
const fdt32_t *val;
|
|
|
|
if (!fdt || (nodeoff < 0) || !out_rmap)
|
|
return SBI_EINVAL;
|
|
|
|
val = fdt_getprop(fdt, nodeoff, "regmap", &len);
|
|
if (!val)
|
|
return SBI_ENOENT;
|
|
|
|
return fdt_regmap_get_by_phandle(fdt, fdt32_to_cpu(*val), out_rmap);
|
|
}
|