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) 227a869e6cSSimon 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; 307a869e6cSSimon 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*17c82fdcSSimon Glass ofnode_for_each_subnode(node, parent) { 387a869e6cSSimon Glass node_name = ofnode_get_name(node); 394d9057e8SPrzemyslaw Marczak 407a869e6cSSimon Glass debug("* Found child node: '%s'\n", node_name); 414d9057e8SPrzemyslaw Marczak 424d9057e8SPrzemyslaw Marczak child = NULL; 43f415a3ecSPrzemyslaw Marczak for (info = child_info; info->prefix && info->driver; info++) { 44e15bb3e6SSimon Glass debug(" - compatible prefix: '%s'\n", info->prefix); 45e15bb3e6SSimon Glass 464d9057e8SPrzemyslaw Marczak prefix_len = strlen(info->prefix); 4723ec2b57SSimon Glass if (strncmp(info->prefix, node_name, prefix_len)) 484d9057e8SPrzemyslaw Marczak continue; 494d9057e8SPrzemyslaw Marczak 504d9057e8SPrzemyslaw Marczak drv = lists_driver_lookup_name(info->driver); 514d9057e8SPrzemyslaw Marczak if (!drv) { 524d9057e8SPrzemyslaw Marczak debug(" - driver: '%s' not found!\n", 534d9057e8SPrzemyslaw Marczak info->driver); 544d9057e8SPrzemyslaw Marczak continue; 554d9057e8SPrzemyslaw Marczak } 564d9057e8SPrzemyslaw Marczak 574d9057e8SPrzemyslaw Marczak debug(" - found child driver: '%s'\n", drv->name); 584d9057e8SPrzemyslaw Marczak 597a869e6cSSimon Glass ret = device_bind_with_driver_data(pmic, drv, node_name, 607a869e6cSSimon Glass 0, node, &child); 614d9057e8SPrzemyslaw Marczak if (ret) { 624d9057e8SPrzemyslaw Marczak debug(" - child binding error: %d\n", ret); 634d9057e8SPrzemyslaw Marczak continue; 644d9057e8SPrzemyslaw Marczak } 654d9057e8SPrzemyslaw Marczak 664d9057e8SPrzemyslaw Marczak debug(" - bound child device: '%s'\n", child->name); 674d9057e8SPrzemyslaw Marczak 68e15bb3e6SSimon Glass child->driver_data = trailing_strtol(node_name); 694d9057e8SPrzemyslaw Marczak 704d9057e8SPrzemyslaw Marczak debug(" - set 'child->driver_data': %lu\n", 714d9057e8SPrzemyslaw Marczak child->driver_data); 724d9057e8SPrzemyslaw Marczak break; 734d9057e8SPrzemyslaw Marczak } 744d9057e8SPrzemyslaw Marczak 754d9057e8SPrzemyslaw Marczak if (child) 764d9057e8SPrzemyslaw Marczak bind_count++; 774d9057e8SPrzemyslaw Marczak else 784d9057e8SPrzemyslaw Marczak debug(" - compatible prefix not found\n"); 794d9057e8SPrzemyslaw Marczak } 804d9057e8SPrzemyslaw Marczak 817a869e6cSSimon Glass debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); 824d9057e8SPrzemyslaw Marczak return bind_count; 834d9057e8SPrzemyslaw Marczak } 841f2b4b06SSimon Glass #endif 854d9057e8SPrzemyslaw Marczak 864d9057e8SPrzemyslaw Marczak int pmic_get(const char *name, struct udevice **devp) 874d9057e8SPrzemyslaw Marczak { 884d9057e8SPrzemyslaw Marczak return uclass_get_device_by_name(UCLASS_PMIC, name, devp); 894d9057e8SPrzemyslaw Marczak } 904d9057e8SPrzemyslaw Marczak 914d9057e8SPrzemyslaw Marczak int pmic_reg_count(struct udevice *dev) 924d9057e8SPrzemyslaw Marczak { 934d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 94f415a3ecSPrzemyslaw Marczak 95f415a3ecSPrzemyslaw Marczak if (!ops || !ops->reg_count) 964d9057e8SPrzemyslaw Marczak return -ENOSYS; 974d9057e8SPrzemyslaw Marczak 98f415a3ecSPrzemyslaw Marczak return ops->reg_count(dev); 994d9057e8SPrzemyslaw Marczak } 1004d9057e8SPrzemyslaw Marczak 1014d9057e8SPrzemyslaw Marczak int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) 1024d9057e8SPrzemyslaw Marczak { 1034d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1044d9057e8SPrzemyslaw Marczak 1054d9057e8SPrzemyslaw Marczak if (!buffer) 1064d9057e8SPrzemyslaw Marczak return -EFAULT; 1074d9057e8SPrzemyslaw Marczak 1084d9057e8SPrzemyslaw Marczak if (!ops || !ops->read) 1094d9057e8SPrzemyslaw Marczak return -ENOSYS; 1104d9057e8SPrzemyslaw Marczak 111f415a3ecSPrzemyslaw Marczak return ops->read(dev, reg, buffer, len); 1124d9057e8SPrzemyslaw Marczak } 1134d9057e8SPrzemyslaw Marczak 1144d9057e8SPrzemyslaw Marczak int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) 1154d9057e8SPrzemyslaw Marczak { 1164d9057e8SPrzemyslaw Marczak const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 1174d9057e8SPrzemyslaw Marczak 1184d9057e8SPrzemyslaw Marczak if (!buffer) 1194d9057e8SPrzemyslaw Marczak return -EFAULT; 1204d9057e8SPrzemyslaw Marczak 1214d9057e8SPrzemyslaw Marczak if (!ops || !ops->write) 1224d9057e8SPrzemyslaw Marczak return -ENOSYS; 1234d9057e8SPrzemyslaw Marczak 124f415a3ecSPrzemyslaw Marczak return ops->write(dev, reg, buffer, len); 1254d9057e8SPrzemyslaw Marczak } 1264d9057e8SPrzemyslaw Marczak 1276c69c7fbSSimon Glass int pmic_reg_read(struct udevice *dev, uint reg) 1286c69c7fbSSimon Glass { 1296c69c7fbSSimon Glass u8 byte; 1306c69c7fbSSimon Glass int ret; 1316c69c7fbSSimon Glass 1327d577999SSimon Glass debug("%s: reg=%x", __func__, reg); 1336c69c7fbSSimon Glass ret = pmic_read(dev, reg, &byte, 1); 1347d577999SSimon Glass debug(", value=%x, ret=%d\n", byte, ret); 1356c69c7fbSSimon Glass 1366c69c7fbSSimon Glass return ret ? ret : byte; 1376c69c7fbSSimon Glass } 1386c69c7fbSSimon Glass 1396c69c7fbSSimon Glass int pmic_reg_write(struct udevice *dev, uint reg, uint value) 1406c69c7fbSSimon Glass { 1416c69c7fbSSimon Glass u8 byte = value; 1427d577999SSimon Glass int ret; 1436c69c7fbSSimon Glass 1447d577999SSimon Glass debug("%s: reg=%x, value=%x", __func__, reg, value); 1457d577999SSimon Glass ret = pmic_write(dev, reg, &byte, 1); 1467d577999SSimon Glass debug(", ret=%d\n", ret); 1477d577999SSimon Glass 1487d577999SSimon Glass return ret; 1496c69c7fbSSimon Glass } 1506c69c7fbSSimon Glass 1516c69c7fbSSimon Glass int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) 1526c69c7fbSSimon Glass { 1536c69c7fbSSimon Glass u8 byte; 1546c69c7fbSSimon Glass int ret; 1556c69c7fbSSimon Glass 1566c69c7fbSSimon Glass ret = pmic_reg_read(dev, reg); 1576c69c7fbSSimon Glass if (ret < 0) 1586c69c7fbSSimon Glass return ret; 1596c69c7fbSSimon Glass byte = (ret & ~clr) | set; 1606c69c7fbSSimon Glass 1616c69c7fbSSimon Glass return pmic_reg_write(dev, reg, byte); 1626c69c7fbSSimon Glass } 1636c69c7fbSSimon Glass 164c8d15c43SJoseph Chen 165c8d15c43SJoseph Chen int pmic_shutdown(struct udevice *dev) 166c8d15c43SJoseph Chen { 167c8d15c43SJoseph Chen const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); 168c8d15c43SJoseph Chen 169c8d15c43SJoseph Chen if (!ops || !ops->shutdown) 170c8d15c43SJoseph Chen return -ENOSYS; 171c8d15c43SJoseph Chen 172c8d15c43SJoseph Chen return ops->shutdown(dev); 173c8d15c43SJoseph Chen } 174c8d15c43SJoseph Chen 1754d9057e8SPrzemyslaw Marczak UCLASS_DRIVER(pmic) = { 1764d9057e8SPrzemyslaw Marczak .id = UCLASS_PMIC, 1774d9057e8SPrzemyslaw Marczak .name = "pmic", 1784d9057e8SPrzemyslaw Marczak }; 179