14d9057e8SPrzemyslaw Marczak /* 24d9057e8SPrzemyslaw Marczak * Copyright (C) 2014-2015 Samsung Electronics 34d9057e8SPrzemyslaw Marczak * Przemyslaw Marczak <p.marczak@samsung.com> 44d9057e8SPrzemyslaw Marczak * 54d9057e8SPrzemyslaw Marczak * SPDX-License-Identifier: GPL-2.0+ 64d9057e8SPrzemyslaw Marczak */ 74d9057e8SPrzemyslaw Marczak 84d9057e8SPrzemyslaw Marczak #include <common.h> 94d9057e8SPrzemyslaw Marczak #include <fdtdec.h> 104d9057e8SPrzemyslaw Marczak #include <errno.h> 114d9057e8SPrzemyslaw Marczak #include <dm.h> 124d9057e8SPrzemyslaw Marczak #include <dm/lists.h> 134d9057e8SPrzemyslaw Marczak #include <dm/device-internal.h> 144d9057e8SPrzemyslaw Marczak #include <dm/uclass-internal.h> 154d9057e8SPrzemyslaw Marczak #include <power/pmic.h> 164d9057e8SPrzemyslaw Marczak #include <linux/ctype.h> 174d9057e8SPrzemyslaw Marczak 184d9057e8SPrzemyslaw Marczak DECLARE_GLOBAL_DATA_PTR; 194d9057e8SPrzemyslaw Marczak 204d9057e8SPrzemyslaw Marczak static ulong str_get_num(const char *ptr, const char *maxptr) 214d9057e8SPrzemyslaw Marczak { 224d9057e8SPrzemyslaw Marczak if (!ptr || !maxptr) 234d9057e8SPrzemyslaw Marczak return 0; 244d9057e8SPrzemyslaw Marczak 254d9057e8SPrzemyslaw Marczak while (!isdigit(*ptr) && ptr++ < maxptr); 264d9057e8SPrzemyslaw Marczak 274d9057e8SPrzemyslaw Marczak return simple_strtoul(ptr, NULL, 0); 284d9057e8SPrzemyslaw Marczak } 294d9057e8SPrzemyslaw Marczak 30*f415a3ecSPrzemyslaw Marczak int pmic_bind_children(struct udevice *pmic, int offset, 314d9057e8SPrzemyslaw Marczak const struct pmic_child_info *child_info) 324d9057e8SPrzemyslaw Marczak { 334d9057e8SPrzemyslaw Marczak const struct pmic_child_info *info; 344d9057e8SPrzemyslaw Marczak const void *blob = gd->fdt_blob; 354d9057e8SPrzemyslaw Marczak struct driver *drv; 364d9057e8SPrzemyslaw Marczak struct udevice *child; 374d9057e8SPrzemyslaw Marczak const char *node_name; 384d9057e8SPrzemyslaw Marczak int node_name_len; 394d9057e8SPrzemyslaw Marczak int bind_count = 0; 404d9057e8SPrzemyslaw Marczak int node; 414d9057e8SPrzemyslaw Marczak int prefix_len; 424d9057e8SPrzemyslaw Marczak int ret; 434d9057e8SPrzemyslaw Marczak 444d9057e8SPrzemyslaw Marczak debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, 454d9057e8SPrzemyslaw Marczak pmic->of_offset); 464d9057e8SPrzemyslaw Marczak 474d9057e8SPrzemyslaw Marczak for (node = fdt_first_subnode(blob, offset); 484d9057e8SPrzemyslaw Marczak node > 0; 494d9057e8SPrzemyslaw Marczak node = fdt_next_subnode(blob, node)) { 504d9057e8SPrzemyslaw Marczak node_name = fdt_get_name(blob, node, &node_name_len); 514d9057e8SPrzemyslaw Marczak 524d9057e8SPrzemyslaw Marczak debug("* Found child node: '%s' at offset:%d\n", node_name, 534d9057e8SPrzemyslaw Marczak node); 544d9057e8SPrzemyslaw Marczak 554d9057e8SPrzemyslaw Marczak child = NULL; 56*f415a3ecSPrzemyslaw Marczak for (info = child_info; info->prefix && info->driver; info++) { 574d9057e8SPrzemyslaw Marczak prefix_len = strlen(info->prefix); 58*f415a3ecSPrzemyslaw Marczak if (strncasecmp(info->prefix, node_name, prefix_len)) 594d9057e8SPrzemyslaw Marczak continue; 604d9057e8SPrzemyslaw Marczak 614d9057e8SPrzemyslaw Marczak debug(" - compatible prefix: '%s'\n", info->prefix); 624d9057e8SPrzemyslaw Marczak 634d9057e8SPrzemyslaw Marczak drv = lists_driver_lookup_name(info->driver); 644d9057e8SPrzemyslaw Marczak if (!drv) { 654d9057e8SPrzemyslaw Marczak debug(" - driver: '%s' not found!\n", 664d9057e8SPrzemyslaw Marczak info->driver); 674d9057e8SPrzemyslaw Marczak continue; 684d9057e8SPrzemyslaw Marczak } 694d9057e8SPrzemyslaw Marczak 704d9057e8SPrzemyslaw Marczak debug(" - found child driver: '%s'\n", drv->name); 714d9057e8SPrzemyslaw Marczak 724d9057e8SPrzemyslaw Marczak ret = device_bind(pmic, drv, node_name, NULL, 734d9057e8SPrzemyslaw Marczak node, &child); 744d9057e8SPrzemyslaw Marczak if (ret) { 754d9057e8SPrzemyslaw Marczak debug(" - child binding error: %d\n", ret); 764d9057e8SPrzemyslaw Marczak continue; 774d9057e8SPrzemyslaw Marczak } 784d9057e8SPrzemyslaw Marczak 794d9057e8SPrzemyslaw Marczak debug(" - bound child device: '%s'\n", child->name); 804d9057e8SPrzemyslaw Marczak 814d9057e8SPrzemyslaw Marczak child->driver_data = str_get_num(node_name + 824d9057e8SPrzemyslaw Marczak prefix_len, 834d9057e8SPrzemyslaw Marczak node_name + 844d9057e8SPrzemyslaw Marczak node_name_len); 854d9057e8SPrzemyslaw Marczak 864d9057e8SPrzemyslaw Marczak debug(" - set 'child->driver_data': %lu\n", 874d9057e8SPrzemyslaw Marczak child->driver_data); 884d9057e8SPrzemyslaw Marczak break; 894d9057e8SPrzemyslaw Marczak } 904d9057e8SPrzemyslaw Marczak 914d9057e8SPrzemyslaw Marczak if (child) 924d9057e8SPrzemyslaw Marczak bind_count++; 934d9057e8SPrzemyslaw Marczak else 944d9057e8SPrzemyslaw Marczak debug(" - compatible prefix not found\n"); 954d9057e8SPrzemyslaw Marczak } 964d9057e8SPrzemyslaw Marczak 974d9057e8SPrzemyslaw Marczak debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name); 984d9057e8SPrzemyslaw Marczak return bind_count; 994d9057e8SPrzemyslaw Marczak } 1004d9057e8SPrzemyslaw Marczak 1014d9057e8SPrzemyslaw Marczak int pmic_get(const char *name, struct udevice **devp) 1024d9057e8SPrzemyslaw Marczak { 1034d9057e8SPrzemyslaw Marczak return uclass_get_device_by_name(UCLASS_PMIC, name, devp); 1044d9057e8SPrzemyslaw Marczak } 1054d9057e8SPrzemyslaw Marczak 1064d9057e8SPrzemyslaw Marczak int pmic_reg_count(struct udevice *dev) 1074d9057e8SPrzemyslaw Marczak { 1084d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 109*f415a3ecSPrzemyslaw Marczak 110*f415a3ecSPrzemyslaw Marczak if (!ops || !ops->reg_count) 1114d9057e8SPrzemyslaw Marczak return -ENOSYS; 1124d9057e8SPrzemyslaw Marczak 113*f415a3ecSPrzemyslaw Marczak return ops->reg_count(dev); 1144d9057e8SPrzemyslaw Marczak } 1154d9057e8SPrzemyslaw Marczak 1164d9057e8SPrzemyslaw Marczak int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) 1174d9057e8SPrzemyslaw Marczak { 1184d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1194d9057e8SPrzemyslaw Marczak 1204d9057e8SPrzemyslaw Marczak if (!buffer) 1214d9057e8SPrzemyslaw Marczak return -EFAULT; 1224d9057e8SPrzemyslaw Marczak 1234d9057e8SPrzemyslaw Marczak if (!ops || !ops->read) 1244d9057e8SPrzemyslaw Marczak return -ENOSYS; 1254d9057e8SPrzemyslaw Marczak 126*f415a3ecSPrzemyslaw Marczak return ops->read(dev, reg, buffer, len); 1274d9057e8SPrzemyslaw Marczak } 1284d9057e8SPrzemyslaw Marczak 1294d9057e8SPrzemyslaw Marczak int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) 1304d9057e8SPrzemyslaw Marczak { 1314d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1324d9057e8SPrzemyslaw Marczak 1334d9057e8SPrzemyslaw Marczak if (!buffer) 1344d9057e8SPrzemyslaw Marczak return -EFAULT; 1354d9057e8SPrzemyslaw Marczak 1364d9057e8SPrzemyslaw Marczak if (!ops || !ops->write) 1374d9057e8SPrzemyslaw Marczak return -ENOSYS; 1384d9057e8SPrzemyslaw Marczak 139*f415a3ecSPrzemyslaw Marczak return ops->write(dev, reg, buffer, len); 1404d9057e8SPrzemyslaw Marczak } 1414d9057e8SPrzemyslaw Marczak 1424d9057e8SPrzemyslaw Marczak UCLASS_DRIVER(pmic) = { 1434d9057e8SPrzemyslaw Marczak .id = UCLASS_PMIC, 1444d9057e8SPrzemyslaw Marczak .name = "pmic", 1454d9057e8SPrzemyslaw Marczak }; 146