2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2015-06-23 21:38:43 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Google, Inc
|
|
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
|
|
*/
|
|
|
|
|
2020-10-05 01:39:43 +00:00
|
|
|
#define LOG_CATEGORY UCLASS_SYSCON
|
|
|
|
|
2015-06-23 21:38:43 +00:00
|
|
|
#include <common.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2015-06-23 21:38:43 +00:00
|
|
|
#include <syscon.h>
|
|
|
|
#include <dm.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <regmap.h>
|
|
|
|
#include <dm/device-internal.h>
|
2020-02-03 14:36:16 +00:00
|
|
|
#include <dm/device_compat.h>
|
2015-06-23 21:38:43 +00:00
|
|
|
#include <dm/lists.h>
|
|
|
|
#include <dm/root.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
/*
|
|
|
|
* Caution:
|
2020-08-22 05:16:26 +00:00
|
|
|
* This API requires the given device has already been bound to the syscon
|
|
|
|
* driver. For example,
|
|
|
|
*
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
* compatible = "syscon", "simple-mfd";
|
2020-08-22 05:16:26 +00:00
|
|
|
*
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
* works, but
|
2020-08-22 05:16:26 +00:00
|
|
|
*
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
* compatible = "simple-mfd", "syscon";
|
2020-08-22 05:16:26 +00:00
|
|
|
*
|
|
|
|
* does not. The behavior is different from Linux.
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
*/
|
2015-06-23 21:38:43 +00:00
|
|
|
struct regmap *syscon_get_regmap(struct udevice *dev)
|
|
|
|
{
|
2015-07-06 18:54:38 +00:00
|
|
|
struct syscon_uc_info *priv;
|
2015-06-23 21:38:43 +00:00
|
|
|
|
2015-07-06 18:54:38 +00:00
|
|
|
if (device_get_uclass_id(dev) != UCLASS_SYSCON)
|
|
|
|
return ERR_PTR(-ENOEXEC);
|
|
|
|
priv = dev_get_uclass_priv(dev);
|
2015-06-23 21:38:43 +00:00
|
|
|
return priv->regmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int syscon_pre_probe(struct udevice *dev)
|
|
|
|
{
|
|
|
|
struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
|
|
|
|
|
2019-02-17 03:24:38 +00:00
|
|
|
/* Special case for PCI devices, which don't have a regmap */
|
|
|
|
if (device_get_uclass_id(dev->parent) == UCLASS_PCI)
|
|
|
|
return 0;
|
|
|
|
|
2023-03-13 00:30:46 +00:00
|
|
|
#if CONFIG_IS_ENABLED(OF_PLATDATA)
|
2016-07-04 17:58:00 +00:00
|
|
|
/*
|
|
|
|
* With OF_PLATDATA we really have no way of knowing the format of
|
|
|
|
* the device-specific platform data. So we assume that it starts with
|
2023-03-13 00:30:46 +00:00
|
|
|
* a 'reg' member that holds a single address and size. Drivers
|
|
|
|
* using OF_PLATDATA will need to ensure that this is true. In case of
|
|
|
|
* odd reg structures other then the syscon_base_plat structure
|
|
|
|
* below the regmap must be defined in the individual syscon driver.
|
2016-07-04 17:58:00 +00:00
|
|
|
*/
|
2023-03-13 00:30:46 +00:00
|
|
|
struct syscon_base_plat {
|
|
|
|
phys_addr_t reg[2];
|
|
|
|
};
|
|
|
|
|
2020-12-03 23:55:23 +00:00
|
|
|
struct syscon_base_plat *plat = dev_get_plat(dev);
|
2016-07-04 17:58:00 +00:00
|
|
|
|
2023-03-13 00:30:46 +00:00
|
|
|
/*
|
|
|
|
* Return if the regmap is already defined in the individual
|
|
|
|
* syscon driver.
|
|
|
|
*/
|
|
|
|
if (priv->regmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return regmap_init_mem_plat(dev, plat->reg, sizeof(plat->reg[0]),
|
|
|
|
ARRAY_SIZE(plat->reg) / 2, &priv->regmap);
|
2016-07-04 17:58:00 +00:00
|
|
|
#else
|
2018-04-19 03:14:03 +00:00
|
|
|
return regmap_init_mem(dev_ofnode(dev), &priv->regmap);
|
2016-07-04 17:58:00 +00:00
|
|
|
#endif
|
2015-06-23 21:38:43 +00:00
|
|
|
}
|
|
|
|
|
2019-03-07 08:57:13 +00:00
|
|
|
static int syscon_probe_by_ofnode(ofnode node, struct udevice **devp)
|
|
|
|
{
|
|
|
|
struct udevice *dev, *parent;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* found node with "syscon" compatible, not bounded to SYSCON UCLASS */
|
|
|
|
if (!ofnode_device_is_compatible(node, "syscon")) {
|
2020-09-15 14:44:37 +00:00
|
|
|
log_debug("invalid compatible for syscon device\n");
|
2019-03-07 08:57:13 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bound to driver with same ofnode or to root if not found */
|
|
|
|
if (device_find_global_by_ofnode(node, &parent))
|
|
|
|
parent = dm_root();
|
|
|
|
|
|
|
|
/* force bound to syscon class */
|
|
|
|
ret = device_bind_driver_to_node(parent, "syscon",
|
|
|
|
ofnode_get_name(node),
|
|
|
|
node, &dev);
|
|
|
|
if (ret) {
|
|
|
|
dev_dbg(dev, "unable to bound syscon device\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = device_probe(dev);
|
|
|
|
if (ret) {
|
|
|
|
dev_dbg(dev, "unable to probe syscon device\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
*devp = dev;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-29 09:57:37 +00:00
|
|
|
struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct udevice *syscon;
|
|
|
|
struct regmap *r;
|
2019-03-07 08:57:13 +00:00
|
|
|
u32 phandle;
|
|
|
|
ofnode node;
|
2018-11-29 09:57:37 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
|
|
|
|
name, &syscon);
|
|
|
|
if (err) {
|
2019-03-07 08:57:13 +00:00
|
|
|
/* found node with "syscon" compatible, not bounded to SYSCON */
|
|
|
|
err = ofnode_read_u32(dev_ofnode(dev), name, &phandle);
|
|
|
|
if (err)
|
|
|
|
return ERR_PTR(err);
|
|
|
|
|
|
|
|
node = ofnode_get_by_phandle(phandle);
|
|
|
|
if (!ofnode_valid(node)) {
|
|
|
|
dev_dbg(dev, "unable to find syscon device\n");
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
err = syscon_probe_by_ofnode(node, &syscon);
|
|
|
|
if (err)
|
|
|
|
return ERR_PTR(-ENODEV);
|
2018-11-29 09:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = syscon_get_regmap(syscon);
|
|
|
|
if (!r) {
|
|
|
|
dev_dbg(dev, "unable to find regmap\n");
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-01-17 23:11:08 +00:00
|
|
|
int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
|
2015-06-23 21:38:43 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2016-03-12 05:06:49 +00:00
|
|
|
*devp = NULL;
|
2020-02-06 16:54:51 +00:00
|
|
|
|
|
|
|
ret = uclass_first_device_drvdata(UCLASS_SYSCON, driver_data, devp);
|
2015-06-23 21:38:43 +00:00
|
|
|
if (ret)
|
2020-09-28 00:46:17 +00:00
|
|
|
return ret;
|
2015-06-23 21:38:43 +00:00
|
|
|
|
2020-02-06 16:54:51 +00:00
|
|
|
return 0;
|
2016-01-17 23:11:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
|
|
|
|
{
|
|
|
|
struct syscon_uc_info *priv;
|
|
|
|
struct udevice *dev;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = syscon_get_by_driver_data(driver_data, &dev);
|
|
|
|
if (ret)
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
|
|
|
|
return priv->regmap;
|
2015-06-23 21:38:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void *syscon_get_first_range(ulong driver_data)
|
|
|
|
{
|
|
|
|
struct regmap *map;
|
|
|
|
|
|
|
|
map = syscon_get_regmap_by_driver_data(driver_data);
|
|
|
|
if (IS_ERR(map))
|
|
|
|
return map;
|
|
|
|
return regmap_get_range(map, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
UCLASS_DRIVER(syscon) = {
|
|
|
|
.id = UCLASS_SYSCON,
|
|
|
|
.name = "syscon",
|
2020-12-03 23:55:17 +00:00
|
|
|
.per_device_auto = sizeof(struct syscon_uc_info),
|
2015-06-23 21:38:43 +00:00
|
|
|
.pre_probe = syscon_pre_probe,
|
|
|
|
};
|
2016-09-08 06:47:37 +00:00
|
|
|
|
|
|
|
static const struct udevice_id generic_syscon_ids[] = {
|
|
|
|
{ .compatible = "syscon" },
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
U_BOOT_DRIVER(generic_syscon) = {
|
|
|
|
.name = "syscon",
|
|
|
|
.id = UCLASS_SYSCON,
|
2021-08-07 13:24:04 +00:00
|
|
|
#if CONFIG_IS_ENABLED(OF_REAL)
|
2017-07-29 17:34:52 +00:00
|
|
|
.bind = dm_scan_fdt_dev,
|
|
|
|
#endif
|
2016-09-08 06:47:37 +00:00
|
|
|
.of_match = generic_syscon_ids,
|
|
|
|
};
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Linux-compatible syscon-to-regmap
|
|
|
|
* The syscon node can be bound to another driver, but still works
|
|
|
|
* as a syscon provider.
|
|
|
|
*/
|
2018-10-31 15:49:03 +00:00
|
|
|
struct regmap *syscon_node_to_regmap(ofnode node)
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
{
|
2019-03-07 08:57:13 +00:00
|
|
|
struct udevice *dev;
|
|
|
|
struct regmap *r;
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
|
2019-03-07 08:57:13 +00:00
|
|
|
if (uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
|
|
|
|
if (syscon_probe_by_ofnode(node, &dev))
|
|
|
|
return ERR_PTR(-ENODEV);
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
|
2019-03-07 08:57:13 +00:00
|
|
|
r = syscon_get_regmap(dev);
|
|
|
|
if (!r) {
|
|
|
|
dev_dbg(dev, "unable to find regmap\n");
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
}
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
|
2019-03-07 08:57:13 +00:00
|
|
|
return r;
|
syscon: add Linux-compatible syscon API
The syscon implementation in U-Boot is different from that in Linux.
Thus, DT files imported from Linux do not work for U-Boot.
In U-Boot driver model, each node is bound to a dedicated driver
that is the most compatible to it. This design gets along with the
concept of DT, and the syscon in Linux originally worked like that.
However, Linux commit bdb0066df96e ("mfd: syscon: Decouple syscon
interface from platform devices") changed the behavior because it is
useful to let a device bind to another driver, but still work as a
syscon provider.
That change had happened before U-Boot initially supported the syscon
driver by commit 6f98b7504f70 ("dm: Add support for generic system
controllers (syscon)"). So, the U-Boot's syscon works differently
from the beginning. I'd say this is mis-implementation given that
DT is not oriented to a particular project, but Linux is the canon
of DT in practice.
The problem typically arises in the combination of "syscon" and
"simple-mfd" compatibles.
In Linux, they are orthogonal, i.e., the order between "syscon" and
"simple-mfd" does not matter at all.
Assume the following compatible.
compatible = "foo,bar-syscon", "syscon", "simple-mfd";
In U-Boot, this device node is bound to the syscon driver
(driver/core/syscon-uclass.c) since the "syscon" is found to be the
most compatible. Then, syscon_get_regmap() succeeds.
However,
compatible = "foo,bar-syscon", "simple-mfd", "syscon";
does not work because this node is bound to the simple-bus driver
(drivers/core/simple-bus.c) in favor of "simple-mfd" compatible.
The compatible string "syscon" is just dismissed.
Moreover,
compatible = "foo,bar-syscon", "syscon";
works like the first case because the syscon driver populates the
child devices. This is wrong because populating children is the job
of "simple-mfd" (or "simple-bus").
This commit ports syscon_node_to_regmap() from Linux. This API
does not require the given node to be bound to a driver in any way.
Reported-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-04-19 03:14:04 +00:00
|
|
|
}
|