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> 12e15bb3e6SSimon Glass #include <vsprintf.h> 134d9057e8SPrzemyslaw Marczak #include <dm/lists.h> 144d9057e8SPrzemyslaw Marczak #include <dm/device-internal.h> 154d9057e8SPrzemyslaw Marczak #include <dm/uclass-internal.h> 164d9057e8SPrzemyslaw Marczak #include <power/pmic.h> 174d9057e8SPrzemyslaw Marczak #include <linux/ctype.h> 184d9057e8SPrzemyslaw Marczak 194d9057e8SPrzemyslaw Marczak DECLARE_GLOBAL_DATA_PTR; 204d9057e8SPrzemyslaw Marczak 21*1f2b4b06SSimon Glass #if CONFIG_IS_ENABLED(PMIC_CHILDREN) 22f415a3ecSPrzemyslaw Marczak int pmic_bind_children(struct udevice *pmic, int offset, 234d9057e8SPrzemyslaw Marczak const struct pmic_child_info *child_info) 244d9057e8SPrzemyslaw Marczak { 254d9057e8SPrzemyslaw Marczak const struct pmic_child_info *info; 264d9057e8SPrzemyslaw Marczak const void *blob = gd->fdt_blob; 274d9057e8SPrzemyslaw Marczak struct driver *drv; 284d9057e8SPrzemyslaw Marczak struct udevice *child; 294d9057e8SPrzemyslaw Marczak const char *node_name; 304d9057e8SPrzemyslaw Marczak int bind_count = 0; 314d9057e8SPrzemyslaw Marczak int node; 324d9057e8SPrzemyslaw Marczak int prefix_len; 334d9057e8SPrzemyslaw Marczak int ret; 344d9057e8SPrzemyslaw Marczak 354d9057e8SPrzemyslaw Marczak debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, 364d9057e8SPrzemyslaw Marczak pmic->of_offset); 374d9057e8SPrzemyslaw Marczak 384d9057e8SPrzemyslaw Marczak for (node = fdt_first_subnode(blob, offset); 394d9057e8SPrzemyslaw Marczak node > 0; 404d9057e8SPrzemyslaw Marczak node = fdt_next_subnode(blob, node)) { 41e15bb3e6SSimon Glass node_name = fdt_get_name(blob, node, NULL); 424d9057e8SPrzemyslaw Marczak 434d9057e8SPrzemyslaw Marczak debug("* Found child node: '%s' at offset:%d\n", node_name, 444d9057e8SPrzemyslaw Marczak node); 454d9057e8SPrzemyslaw Marczak 464d9057e8SPrzemyslaw Marczak child = NULL; 47f415a3ecSPrzemyslaw Marczak for (info = child_info; info->prefix && info->driver; info++) { 48e15bb3e6SSimon Glass debug(" - compatible prefix: '%s'\n", info->prefix); 49e15bb3e6SSimon Glass 504d9057e8SPrzemyslaw Marczak prefix_len = strlen(info->prefix); 5123ec2b57SSimon Glass if (strncmp(info->prefix, node_name, prefix_len)) 524d9057e8SPrzemyslaw Marczak continue; 534d9057e8SPrzemyslaw Marczak 544d9057e8SPrzemyslaw Marczak drv = lists_driver_lookup_name(info->driver); 554d9057e8SPrzemyslaw Marczak if (!drv) { 564d9057e8SPrzemyslaw Marczak debug(" - driver: '%s' not found!\n", 574d9057e8SPrzemyslaw Marczak info->driver); 584d9057e8SPrzemyslaw Marczak continue; 594d9057e8SPrzemyslaw Marczak } 604d9057e8SPrzemyslaw Marczak 614d9057e8SPrzemyslaw Marczak debug(" - found child driver: '%s'\n", drv->name); 624d9057e8SPrzemyslaw Marczak 634d9057e8SPrzemyslaw Marczak ret = device_bind(pmic, drv, node_name, NULL, 644d9057e8SPrzemyslaw Marczak node, &child); 654d9057e8SPrzemyslaw Marczak if (ret) { 664d9057e8SPrzemyslaw Marczak debug(" - child binding error: %d\n", ret); 674d9057e8SPrzemyslaw Marczak continue; 684d9057e8SPrzemyslaw Marczak } 694d9057e8SPrzemyslaw Marczak 704d9057e8SPrzemyslaw Marczak debug(" - bound child device: '%s'\n", child->name); 714d9057e8SPrzemyslaw Marczak 72e15bb3e6SSimon Glass child->driver_data = trailing_strtol(node_name); 734d9057e8SPrzemyslaw Marczak 744d9057e8SPrzemyslaw Marczak debug(" - set 'child->driver_data': %lu\n", 754d9057e8SPrzemyslaw Marczak child->driver_data); 764d9057e8SPrzemyslaw Marczak break; 774d9057e8SPrzemyslaw Marczak } 784d9057e8SPrzemyslaw Marczak 794d9057e8SPrzemyslaw Marczak if (child) 804d9057e8SPrzemyslaw Marczak bind_count++; 814d9057e8SPrzemyslaw Marczak else 824d9057e8SPrzemyslaw Marczak debug(" - compatible prefix not found\n"); 834d9057e8SPrzemyslaw Marczak } 844d9057e8SPrzemyslaw Marczak 854d9057e8SPrzemyslaw Marczak debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name); 864d9057e8SPrzemyslaw Marczak return bind_count; 874d9057e8SPrzemyslaw Marczak } 88*1f2b4b06SSimon Glass #endif 894d9057e8SPrzemyslaw Marczak 904d9057e8SPrzemyslaw Marczak int pmic_get(const char *name, struct udevice **devp) 914d9057e8SPrzemyslaw Marczak { 924d9057e8SPrzemyslaw Marczak return uclass_get_device_by_name(UCLASS_PMIC, name, devp); 934d9057e8SPrzemyslaw Marczak } 944d9057e8SPrzemyslaw Marczak 954d9057e8SPrzemyslaw Marczak int pmic_reg_count(struct udevice *dev) 964d9057e8SPrzemyslaw Marczak { 974d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 98f415a3ecSPrzemyslaw Marczak 99f415a3ecSPrzemyslaw Marczak if (!ops || !ops->reg_count) 1004d9057e8SPrzemyslaw Marczak return -ENOSYS; 1014d9057e8SPrzemyslaw Marczak 102f415a3ecSPrzemyslaw Marczak return ops->reg_count(dev); 1034d9057e8SPrzemyslaw Marczak } 1044d9057e8SPrzemyslaw Marczak 1054d9057e8SPrzemyslaw Marczak int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) 1064d9057e8SPrzemyslaw Marczak { 1074d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1084d9057e8SPrzemyslaw Marczak 1094d9057e8SPrzemyslaw Marczak if (!buffer) 1104d9057e8SPrzemyslaw Marczak return -EFAULT; 1114d9057e8SPrzemyslaw Marczak 1124d9057e8SPrzemyslaw Marczak if (!ops || !ops->read) 1134d9057e8SPrzemyslaw Marczak return -ENOSYS; 1144d9057e8SPrzemyslaw Marczak 115f415a3ecSPrzemyslaw Marczak return ops->read(dev, reg, buffer, len); 1164d9057e8SPrzemyslaw Marczak } 1174d9057e8SPrzemyslaw Marczak 1184d9057e8SPrzemyslaw Marczak int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) 1194d9057e8SPrzemyslaw Marczak { 1204d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1214d9057e8SPrzemyslaw Marczak 1224d9057e8SPrzemyslaw Marczak if (!buffer) 1234d9057e8SPrzemyslaw Marczak return -EFAULT; 1244d9057e8SPrzemyslaw Marczak 1254d9057e8SPrzemyslaw Marczak if (!ops || !ops->write) 1264d9057e8SPrzemyslaw Marczak return -ENOSYS; 1274d9057e8SPrzemyslaw Marczak 128f415a3ecSPrzemyslaw Marczak return ops->write(dev, reg, buffer, len); 1294d9057e8SPrzemyslaw Marczak } 1304d9057e8SPrzemyslaw Marczak 1316c69c7fbSSimon Glass int pmic_reg_read(struct udevice *dev, uint reg) 1326c69c7fbSSimon Glass { 1336c69c7fbSSimon Glass u8 byte; 1346c69c7fbSSimon Glass int ret; 1356c69c7fbSSimon Glass 1366c69c7fbSSimon Glass ret = pmic_read(dev, reg, &byte, 1); 1376c69c7fbSSimon Glass debug("%s: reg=%x, value=%x\n", __func__, reg, byte); 1386c69c7fbSSimon Glass 1396c69c7fbSSimon Glass return ret ? ret : byte; 1406c69c7fbSSimon Glass } 1416c69c7fbSSimon Glass 1426c69c7fbSSimon Glass int pmic_reg_write(struct udevice *dev, uint reg, uint value) 1436c69c7fbSSimon Glass { 1446c69c7fbSSimon Glass u8 byte = value; 1456c69c7fbSSimon Glass 1466c69c7fbSSimon Glass debug("%s: reg=%x, value=%x\n", __func__, reg, value); 147cd367d89SSimon Glass return pmic_write(dev, reg, &byte, 1); 1486c69c7fbSSimon Glass } 1496c69c7fbSSimon Glass 1506c69c7fbSSimon Glass int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) 1516c69c7fbSSimon Glass { 1526c69c7fbSSimon Glass u8 byte; 1536c69c7fbSSimon Glass int ret; 1546c69c7fbSSimon Glass 1556c69c7fbSSimon Glass ret = pmic_reg_read(dev, reg); 1566c69c7fbSSimon Glass if (ret < 0) 1576c69c7fbSSimon Glass return ret; 1586c69c7fbSSimon Glass byte = (ret & ~clr) | set; 1596c69c7fbSSimon Glass 1606c69c7fbSSimon Glass return pmic_reg_write(dev, reg, byte); 1616c69c7fbSSimon Glass } 1626c69c7fbSSimon Glass 1634d9057e8SPrzemyslaw Marczak UCLASS_DRIVER(pmic) = { 1644d9057e8SPrzemyslaw Marczak .id = UCLASS_PMIC, 1654d9057e8SPrzemyslaw Marczak .name = "pmic", 1664d9057e8SPrzemyslaw Marczak }; 167