xref: /openbmc/u-boot/drivers/core/syscon-uclass.c (revision 745fb9c2)
157251285SSimon Glass /*
257251285SSimon Glass  * Copyright (C) 2015 Google, Inc
357251285SSimon Glass  * Written by Simon Glass <sjg@chromium.org>
457251285SSimon Glass  *
557251285SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
657251285SSimon Glass  */
757251285SSimon Glass 
857251285SSimon Glass #include <common.h>
957251285SSimon Glass #include <syscon.h>
1057251285SSimon Glass #include <dm.h>
1157251285SSimon Glass #include <errno.h>
1257251285SSimon Glass #include <regmap.h>
1357251285SSimon Glass #include <dm/device-internal.h>
1457251285SSimon Glass #include <dm/lists.h>
1557251285SSimon Glass #include <dm/root.h>
1657251285SSimon Glass #include <linux/err.h>
1757251285SSimon Glass 
1857251285SSimon Glass struct regmap *syscon_get_regmap(struct udevice *dev)
1957251285SSimon Glass {
209f4629beSSimon Glass 	struct syscon_uc_info *priv;
2157251285SSimon Glass 
229f4629beSSimon Glass 	if (device_get_uclass_id(dev) != UCLASS_SYSCON)
239f4629beSSimon Glass 		return ERR_PTR(-ENOEXEC);
249f4629beSSimon Glass 	priv = dev_get_uclass_priv(dev);
2557251285SSimon Glass 	return priv->regmap;
2657251285SSimon Glass }
2757251285SSimon Glass 
2857251285SSimon Glass static int syscon_pre_probe(struct udevice *dev)
2957251285SSimon Glass {
3057251285SSimon Glass 	struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
3157251285SSimon Glass 
3204ecf36bSSimon Glass 	/*
3304ecf36bSSimon Glass 	 * With OF_PLATDATA we really have no way of knowing the format of
3404ecf36bSSimon Glass 	 * the device-specific platform data. So we assume that it starts with
3504ecf36bSSimon Glass 	 * a 'reg' member, and this holds a single address and size. Drivers
3604ecf36bSSimon Glass 	 * using OF_PLATDATA will need to ensure that this is true.
3704ecf36bSSimon Glass 	 */
3804ecf36bSSimon Glass #if CONFIG_IS_ENABLED(OF_PLATDATA)
3904ecf36bSSimon Glass 	struct syscon_base_platdata *plat = dev_get_platdata(dev);
4004ecf36bSSimon Glass 
4104ecf36bSSimon Glass 	return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg),
4204ecf36bSSimon Glass 					&priv->regmap);
4304ecf36bSSimon Glass #else
4457251285SSimon Glass 	return regmap_init_mem(dev, &priv->regmap);
4504ecf36bSSimon Glass #endif
4657251285SSimon Glass }
4757251285SSimon Glass 
48ac94b7bcSSimon Glass int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
4957251285SSimon Glass {
5057251285SSimon Glass 	struct udevice *dev;
5157251285SSimon Glass 	struct uclass *uc;
5257251285SSimon Glass 	int ret;
5357251285SSimon Glass 
54532f2435SSimon Glass 	*devp = NULL;
5557251285SSimon Glass 	ret = uclass_get(UCLASS_SYSCON, &uc);
5657251285SSimon Glass 	if (ret)
57ac94b7bcSSimon Glass 		return ret;
5857251285SSimon Glass 	uclass_foreach_dev(dev, uc) {
5957251285SSimon Glass 		if (dev->driver_data == driver_data) {
60ac94b7bcSSimon Glass 			*devp = dev;
61ac94b7bcSSimon Glass 			return device_probe(dev);
62ac94b7bcSSimon Glass 		}
63ac94b7bcSSimon Glass 	}
64ac94b7bcSSimon Glass 
65ac94b7bcSSimon Glass 	return -ENODEV;
66ac94b7bcSSimon Glass }
67ac94b7bcSSimon Glass 
68ac94b7bcSSimon Glass struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
69ac94b7bcSSimon Glass {
7057251285SSimon Glass 	struct syscon_uc_info *priv;
71ac94b7bcSSimon Glass 	struct udevice *dev;
7257251285SSimon Glass 	int ret;
7357251285SSimon Glass 
74ac94b7bcSSimon Glass 	ret = syscon_get_by_driver_data(driver_data, &dev);
7557251285SSimon Glass 	if (ret)
7657251285SSimon Glass 		return ERR_PTR(ret);
7757251285SSimon Glass 	priv = dev_get_uclass_priv(dev);
7857251285SSimon Glass 
7957251285SSimon Glass 	return priv->regmap;
8057251285SSimon Glass }
8157251285SSimon Glass 
8257251285SSimon Glass void *syscon_get_first_range(ulong driver_data)
8357251285SSimon Glass {
8457251285SSimon Glass 	struct regmap *map;
8557251285SSimon Glass 
8657251285SSimon Glass 	map = syscon_get_regmap_by_driver_data(driver_data);
8757251285SSimon Glass 	if (IS_ERR(map))
8857251285SSimon Glass 		return map;
8957251285SSimon Glass 	return regmap_get_range(map, 0);
9057251285SSimon Glass }
9157251285SSimon Glass 
9257251285SSimon Glass UCLASS_DRIVER(syscon) = {
9357251285SSimon Glass 	.id		= UCLASS_SYSCON,
9457251285SSimon Glass 	.name		= "syscon",
9557251285SSimon Glass 	.per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
9657251285SSimon Glass 	.pre_probe = syscon_pre_probe,
9757251285SSimon Glass };
988291bc87SPaul Burton 
998291bc87SPaul Burton static const struct udevice_id generic_syscon_ids[] = {
1008291bc87SPaul Burton 	{ .compatible = "syscon" },
1018291bc87SPaul Burton 	{ }
1028291bc87SPaul Burton };
1038291bc87SPaul Burton 
1048291bc87SPaul Burton U_BOOT_DRIVER(generic_syscon) = {
1058291bc87SPaul Burton 	.name	= "syscon",
1068291bc87SPaul Burton 	.id	= UCLASS_SYSCON,
107*745fb9c2SSimon Glass #if !CONFIG_IS_ENABLED(OF_PLATDATA)
108*745fb9c2SSimon Glass 	.bind           = dm_scan_fdt_dev,
109*745fb9c2SSimon Glass #endif
1108291bc87SPaul Burton 	.of_match = generic_syscon_ids,
1118291bc87SPaul Burton };
112