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
syscon_get_regmap(struct udevice * dev)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
syscon_pre_probe(struct udevice * dev)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
syscon_regmap_lookup_by_phandle(struct udevice * dev,const char * name)48*10427e2dSJean-Jacques Hiblot struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev,
49*10427e2dSJean-Jacques Hiblot const char *name)
50*10427e2dSJean-Jacques Hiblot {
51*10427e2dSJean-Jacques Hiblot struct udevice *syscon;
52*10427e2dSJean-Jacques Hiblot struct regmap *r;
53*10427e2dSJean-Jacques Hiblot int err;
54*10427e2dSJean-Jacques Hiblot
55*10427e2dSJean-Jacques Hiblot err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
56*10427e2dSJean-Jacques Hiblot name, &syscon);
57*10427e2dSJean-Jacques Hiblot if (err)
58*10427e2dSJean-Jacques Hiblot return ERR_PTR(err);
59*10427e2dSJean-Jacques Hiblot
60*10427e2dSJean-Jacques Hiblot r = syscon_get_regmap(syscon);
61*10427e2dSJean-Jacques Hiblot if (!r)
62*10427e2dSJean-Jacques Hiblot return ERR_PTR(-ENODEV);
63*10427e2dSJean-Jacques Hiblot
64*10427e2dSJean-Jacques Hiblot return r;
65*10427e2dSJean-Jacques Hiblot }
66*10427e2dSJean-Jacques Hiblot
syscon_get_by_driver_data(ulong driver_data,struct udevice ** devp)67ac94b7bcSSimon Glass int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
6857251285SSimon Glass {
6957251285SSimon Glass struct udevice *dev;
7057251285SSimon Glass struct uclass *uc;
7157251285SSimon Glass int ret;
7257251285SSimon Glass
73532f2435SSimon Glass *devp = NULL;
7457251285SSimon Glass ret = uclass_get(UCLASS_SYSCON, &uc);
7557251285SSimon Glass if (ret)
76ac94b7bcSSimon Glass return ret;
7757251285SSimon Glass uclass_foreach_dev(dev, uc) {
7857251285SSimon Glass if (dev->driver_data == driver_data) {
79ac94b7bcSSimon Glass *devp = dev;
80ac94b7bcSSimon Glass return device_probe(dev);
81ac94b7bcSSimon Glass }
82ac94b7bcSSimon Glass }
83ac94b7bcSSimon Glass
84ac94b7bcSSimon Glass return -ENODEV;
85ac94b7bcSSimon Glass }
86ac94b7bcSSimon Glass
syscon_get_regmap_by_driver_data(ulong driver_data)87ac94b7bcSSimon Glass struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
88ac94b7bcSSimon Glass {
8957251285SSimon Glass struct syscon_uc_info *priv;
90ac94b7bcSSimon Glass struct udevice *dev;
9157251285SSimon Glass int ret;
9257251285SSimon Glass
93ac94b7bcSSimon Glass ret = syscon_get_by_driver_data(driver_data, &dev);
9457251285SSimon Glass if (ret)
9557251285SSimon Glass return ERR_PTR(ret);
9657251285SSimon Glass priv = dev_get_uclass_priv(dev);
9757251285SSimon Glass
9857251285SSimon Glass return priv->regmap;
9957251285SSimon Glass }
10057251285SSimon Glass
syscon_get_first_range(ulong driver_data)10157251285SSimon Glass void *syscon_get_first_range(ulong driver_data)
10257251285SSimon Glass {
10357251285SSimon Glass struct regmap *map;
10457251285SSimon Glass
10557251285SSimon Glass map = syscon_get_regmap_by_driver_data(driver_data);
10657251285SSimon Glass if (IS_ERR(map))
10757251285SSimon Glass return map;
10857251285SSimon Glass return regmap_get_range(map, 0);
10957251285SSimon Glass }
11057251285SSimon Glass
11157251285SSimon Glass UCLASS_DRIVER(syscon) = {
11257251285SSimon Glass .id = UCLASS_SYSCON,
11357251285SSimon Glass .name = "syscon",
11457251285SSimon Glass .per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
11557251285SSimon Glass .pre_probe = syscon_pre_probe,
11657251285SSimon Glass };
1178291bc87SPaul Burton
1188291bc87SPaul Burton static const struct udevice_id generic_syscon_ids[] = {
1198291bc87SPaul Burton { .compatible = "syscon" },
1208291bc87SPaul Burton { }
1218291bc87SPaul Burton };
1228291bc87SPaul Burton
1238291bc87SPaul Burton U_BOOT_DRIVER(generic_syscon) = {
1248291bc87SPaul Burton .name = "syscon",
1258291bc87SPaul Burton .id = UCLASS_SYSCON,
126745fb9c2SSimon Glass #if !CONFIG_IS_ENABLED(OF_PLATDATA)
127745fb9c2SSimon Glass .bind = dm_scan_fdt_dev,
128745fb9c2SSimon Glass #endif
1298291bc87SPaul Burton .of_match = generic_syscon_ids,
1308291bc87SPaul Burton };
131