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 211f2b4b06SSimon Glass #if CONFIG_IS_ENABLED(PMIC_CHILDREN) 22*7a869e6cSSimon Glass int pmic_bind_children(struct udevice *pmic, ofnode parent, 234d9057e8SPrzemyslaw Marczak const struct pmic_child_info *child_info) 244d9057e8SPrzemyslaw Marczak { 254d9057e8SPrzemyslaw Marczak const struct pmic_child_info *info; 264d9057e8SPrzemyslaw Marczak struct driver *drv; 274d9057e8SPrzemyslaw Marczak struct udevice *child; 284d9057e8SPrzemyslaw Marczak const char *node_name; 294d9057e8SPrzemyslaw Marczak int bind_count = 0; 30*7a869e6cSSimon Glass ofnode node; 314d9057e8SPrzemyslaw Marczak int prefix_len; 324d9057e8SPrzemyslaw Marczak int ret; 334d9057e8SPrzemyslaw Marczak 344d9057e8SPrzemyslaw Marczak debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, 35e160f7d4SSimon Glass dev_of_offset(pmic)); 364d9057e8SPrzemyslaw Marczak 37*7a869e6cSSimon Glass for (node = ofnode_first_subnode(parent); 38*7a869e6cSSimon Glass ofnode_valid(node); 39*7a869e6cSSimon Glass node = ofnode_next_subnode(node)) { 40*7a869e6cSSimon Glass node_name = ofnode_get_name(node); 414d9057e8SPrzemyslaw Marczak 42*7a869e6cSSimon Glass debug("* Found child node: '%s'\n", node_name); 434d9057e8SPrzemyslaw Marczak 444d9057e8SPrzemyslaw Marczak child = NULL; 45f415a3ecSPrzemyslaw Marczak for (info = child_info; info->prefix && info->driver; info++) { 46e15bb3e6SSimon Glass debug(" - compatible prefix: '%s'\n", info->prefix); 47e15bb3e6SSimon Glass 484d9057e8SPrzemyslaw Marczak prefix_len = strlen(info->prefix); 4923ec2b57SSimon Glass if (strncmp(info->prefix, node_name, prefix_len)) 504d9057e8SPrzemyslaw Marczak continue; 514d9057e8SPrzemyslaw Marczak 524d9057e8SPrzemyslaw Marczak drv = lists_driver_lookup_name(info->driver); 534d9057e8SPrzemyslaw Marczak if (!drv) { 544d9057e8SPrzemyslaw Marczak debug(" - driver: '%s' not found!\n", 554d9057e8SPrzemyslaw Marczak info->driver); 564d9057e8SPrzemyslaw Marczak continue; 574d9057e8SPrzemyslaw Marczak } 584d9057e8SPrzemyslaw Marczak 594d9057e8SPrzemyslaw Marczak debug(" - found child driver: '%s'\n", drv->name); 604d9057e8SPrzemyslaw Marczak 61*7a869e6cSSimon Glass ret = device_bind_with_driver_data(pmic, drv, node_name, 62*7a869e6cSSimon Glass 0, node, &child); 634d9057e8SPrzemyslaw Marczak if (ret) { 644d9057e8SPrzemyslaw Marczak debug(" - child binding error: %d\n", ret); 654d9057e8SPrzemyslaw Marczak continue; 664d9057e8SPrzemyslaw Marczak } 674d9057e8SPrzemyslaw Marczak 684d9057e8SPrzemyslaw Marczak debug(" - bound child device: '%s'\n", child->name); 694d9057e8SPrzemyslaw Marczak 70e15bb3e6SSimon Glass child->driver_data = trailing_strtol(node_name); 714d9057e8SPrzemyslaw Marczak 724d9057e8SPrzemyslaw Marczak debug(" - set 'child->driver_data': %lu\n", 734d9057e8SPrzemyslaw Marczak child->driver_data); 744d9057e8SPrzemyslaw Marczak break; 754d9057e8SPrzemyslaw Marczak } 764d9057e8SPrzemyslaw Marczak 774d9057e8SPrzemyslaw Marczak if (child) 784d9057e8SPrzemyslaw Marczak bind_count++; 794d9057e8SPrzemyslaw Marczak else 804d9057e8SPrzemyslaw Marczak debug(" - compatible prefix not found\n"); 814d9057e8SPrzemyslaw Marczak } 824d9057e8SPrzemyslaw Marczak 83*7a869e6cSSimon Glass debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); 844d9057e8SPrzemyslaw Marczak return bind_count; 854d9057e8SPrzemyslaw Marczak } 861f2b4b06SSimon Glass #endif 874d9057e8SPrzemyslaw Marczak 884d9057e8SPrzemyslaw Marczak int pmic_get(const char *name, struct udevice **devp) 894d9057e8SPrzemyslaw Marczak { 904d9057e8SPrzemyslaw Marczak return uclass_get_device_by_name(UCLASS_PMIC, name, devp); 914d9057e8SPrzemyslaw Marczak } 924d9057e8SPrzemyslaw Marczak 934d9057e8SPrzemyslaw Marczak int pmic_reg_count(struct udevice *dev) 944d9057e8SPrzemyslaw Marczak { 954d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 96f415a3ecSPrzemyslaw Marczak 97f415a3ecSPrzemyslaw Marczak if (!ops || !ops->reg_count) 984d9057e8SPrzemyslaw Marczak return -ENOSYS; 994d9057e8SPrzemyslaw Marczak 100f415a3ecSPrzemyslaw Marczak return ops->reg_count(dev); 1014d9057e8SPrzemyslaw Marczak } 1024d9057e8SPrzemyslaw Marczak 1034d9057e8SPrzemyslaw Marczak int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) 1044d9057e8SPrzemyslaw Marczak { 1054d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1064d9057e8SPrzemyslaw Marczak 1074d9057e8SPrzemyslaw Marczak if (!buffer) 1084d9057e8SPrzemyslaw Marczak return -EFAULT; 1094d9057e8SPrzemyslaw Marczak 1104d9057e8SPrzemyslaw Marczak if (!ops || !ops->read) 1114d9057e8SPrzemyslaw Marczak return -ENOSYS; 1124d9057e8SPrzemyslaw Marczak 113f415a3ecSPrzemyslaw Marczak return ops->read(dev, reg, buffer, len); 1144d9057e8SPrzemyslaw Marczak } 1154d9057e8SPrzemyslaw Marczak 1164d9057e8SPrzemyslaw Marczak int pmic_write(struct udevice *dev, uint reg, const 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->write) 1244d9057e8SPrzemyslaw Marczak return -ENOSYS; 1254d9057e8SPrzemyslaw Marczak 126f415a3ecSPrzemyslaw Marczak return ops->write(dev, reg, buffer, len); 1274d9057e8SPrzemyslaw Marczak } 1284d9057e8SPrzemyslaw Marczak 1296c69c7fbSSimon Glass int pmic_reg_read(struct udevice *dev, uint reg) 1306c69c7fbSSimon Glass { 1316c69c7fbSSimon Glass u8 byte; 1326c69c7fbSSimon Glass int ret; 1336c69c7fbSSimon Glass 1347d577999SSimon Glass debug("%s: reg=%x", __func__, reg); 1356c69c7fbSSimon Glass ret = pmic_read(dev, reg, &byte, 1); 1367d577999SSimon Glass debug(", value=%x, ret=%d\n", byte, ret); 1376c69c7fbSSimon Glass 1386c69c7fbSSimon Glass return ret ? ret : byte; 1396c69c7fbSSimon Glass } 1406c69c7fbSSimon Glass 1416c69c7fbSSimon Glass int pmic_reg_write(struct udevice *dev, uint reg, uint value) 1426c69c7fbSSimon Glass { 1436c69c7fbSSimon Glass u8 byte = value; 1447d577999SSimon Glass int ret; 1456c69c7fbSSimon Glass 1467d577999SSimon Glass debug("%s: reg=%x, value=%x", __func__, reg, value); 1477d577999SSimon Glass ret = pmic_write(dev, reg, &byte, 1); 1487d577999SSimon Glass debug(", ret=%d\n", ret); 1497d577999SSimon Glass 1507d577999SSimon Glass return ret; 1516c69c7fbSSimon Glass } 1526c69c7fbSSimon Glass 1536c69c7fbSSimon Glass int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) 1546c69c7fbSSimon Glass { 1556c69c7fbSSimon Glass u8 byte; 1566c69c7fbSSimon Glass int ret; 1576c69c7fbSSimon Glass 1586c69c7fbSSimon Glass ret = pmic_reg_read(dev, reg); 1596c69c7fbSSimon Glass if (ret < 0) 1606c69c7fbSSimon Glass return ret; 1616c69c7fbSSimon Glass byte = (ret & ~clr) | set; 1626c69c7fbSSimon Glass 1636c69c7fbSSimon Glass return pmic_reg_write(dev, reg, byte); 1646c69c7fbSSimon Glass } 1656c69c7fbSSimon Glass 1664d9057e8SPrzemyslaw Marczak UCLASS_DRIVER(pmic) = { 1674d9057e8SPrzemyslaw Marczak .id = UCLASS_PMIC, 1684d9057e8SPrzemyslaw Marczak .name = "pmic", 1694d9057e8SPrzemyslaw Marczak }; 170