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