106512c53SKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0 206512c53SKrzysztof Kozlowski // 306512c53SKrzysztof Kozlowski // Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. 406512c53SKrzysztof Kozlowski // http://www.samsung.com/ 506512c53SKrzysztof Kozlowski // 694500540SKrzysztof Kozlowski // Exynos - CPU PMU(Power Management Unit) support 7bfce552dSPankaj Dubey 80b7c6075SPeter Griffin #include <linux/arm-smccc.h> 9bfce552dSPankaj Dubey #include <linux/of.h> 10bfce552dSPankaj Dubey #include <linux/of_address.h> 1193618e34SKrzysztof Kozlowski #include <linux/mfd/core.h> 1276640b84SMarek Szyprowski #include <linux/mfd/syscon.h> 134c445837SRob Herring #include <linux/of_platform.h> 14bfce552dSPankaj Dubey #include <linux/platform_device.h> 15bfce552dSPankaj Dubey #include <linux/delay.h> 160b7c6075SPeter Griffin #include <linux/regmap.h> 17bfce552dSPankaj Dubey 18bfce552dSPankaj Dubey #include <linux/soc/samsung/exynos-regs-pmu.h> 19bfce552dSPankaj Dubey #include <linux/soc/samsung/exynos-pmu.h> 20bfce552dSPankaj Dubey 21bfce552dSPankaj Dubey #include "exynos-pmu.h" 22bfce552dSPankaj Dubey 230b7c6075SPeter Griffin #define PMUALIVE_MASK GENMASK(13, 0) 240b7c6075SPeter Griffin #define TENSOR_SET_BITS (BIT(15) | BIT(14)) 250b7c6075SPeter Griffin #define TENSOR_CLR_BITS BIT(15) 260b7c6075SPeter Griffin #define TENSOR_SMC_PMU_SEC_REG 0x82000504 270b7c6075SPeter Griffin #define TENSOR_PMUREG_READ 0 280b7c6075SPeter Griffin #define TENSOR_PMUREG_WRITE 1 290b7c6075SPeter Griffin #define TENSOR_PMUREG_RMW 2 300b7c6075SPeter Griffin 31bfce552dSPankaj Dubey struct exynos_pmu_context { 32bfce552dSPankaj Dubey struct device *dev; 33bfce552dSPankaj Dubey const struct exynos_pmu_data *pmu_data; 340b7c6075SPeter Griffin struct regmap *pmureg; 35bfce552dSPankaj Dubey }; 36bfce552dSPankaj Dubey 37bfce552dSPankaj Dubey void __iomem *pmu_base_addr; 38bfce552dSPankaj Dubey static struct exynos_pmu_context *pmu_context; 390b7c6075SPeter Griffin /* forward declaration */ 400b7c6075SPeter Griffin static struct platform_driver exynos_pmu_driver; 410b7c6075SPeter Griffin 420b7c6075SPeter Griffin /* 430b7c6075SPeter Griffin * Tensor SoCs are configured so that PMU_ALIVE registers can only be written 440b7c6075SPeter Griffin * from EL3, but are still read accessible. As Linux needs to write some of 450b7c6075SPeter Griffin * these registers, the following functions are provided and exposed via 460b7c6075SPeter Griffin * regmap. 470b7c6075SPeter Griffin * 480b7c6075SPeter Griffin * Note: This SMC interface is known to be implemented on gs101 and derivative 490b7c6075SPeter Griffin * SoCs. 500b7c6075SPeter Griffin */ 510b7c6075SPeter Griffin 520b7c6075SPeter Griffin /* Write to a protected PMU register. */ 530b7c6075SPeter Griffin static int tensor_sec_reg_write(void *context, unsigned int reg, 540b7c6075SPeter Griffin unsigned int val) 550b7c6075SPeter Griffin { 560b7c6075SPeter Griffin struct arm_smccc_res res; 570b7c6075SPeter Griffin unsigned long pmu_base = (unsigned long)context; 580b7c6075SPeter Griffin 590b7c6075SPeter Griffin arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 600b7c6075SPeter Griffin TENSOR_PMUREG_WRITE, val, 0, 0, 0, 0, &res); 610b7c6075SPeter Griffin 620b7c6075SPeter Griffin /* returns -EINVAL if access isn't allowed or 0 */ 630b7c6075SPeter Griffin if (res.a0) 640b7c6075SPeter Griffin pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 650b7c6075SPeter Griffin 660b7c6075SPeter Griffin return (int)res.a0; 670b7c6075SPeter Griffin } 680b7c6075SPeter Griffin 690b7c6075SPeter Griffin /* Read/Modify/Write a protected PMU register. */ 700b7c6075SPeter Griffin static int tensor_sec_reg_rmw(void *context, unsigned int reg, 710b7c6075SPeter Griffin unsigned int mask, unsigned int val) 720b7c6075SPeter Griffin { 730b7c6075SPeter Griffin struct arm_smccc_res res; 740b7c6075SPeter Griffin unsigned long pmu_base = (unsigned long)context; 750b7c6075SPeter Griffin 760b7c6075SPeter Griffin arm_smccc_smc(TENSOR_SMC_PMU_SEC_REG, pmu_base + reg, 770b7c6075SPeter Griffin TENSOR_PMUREG_RMW, mask, val, 0, 0, 0, &res); 780b7c6075SPeter Griffin 790b7c6075SPeter Griffin /* returns -EINVAL if access isn't allowed or 0 */ 800b7c6075SPeter Griffin if (res.a0) 810b7c6075SPeter Griffin pr_warn("%s(): SMC failed: %d\n", __func__, (int)res.a0); 820b7c6075SPeter Griffin 830b7c6075SPeter Griffin return (int)res.a0; 840b7c6075SPeter Griffin } 850b7c6075SPeter Griffin 860b7c6075SPeter Griffin /* 870b7c6075SPeter Griffin * Read a protected PMU register. All PMU registers can be read by Linux. 880b7c6075SPeter Griffin * Note: The SMC read register is not used, as only registers that can be 890b7c6075SPeter Griffin * written are readable via SMC. 900b7c6075SPeter Griffin */ 910b7c6075SPeter Griffin static int tensor_sec_reg_read(void *context, unsigned int reg, 920b7c6075SPeter Griffin unsigned int *val) 930b7c6075SPeter Griffin { 940b7c6075SPeter Griffin *val = pmu_raw_readl(reg); 950b7c6075SPeter Griffin return 0; 960b7c6075SPeter Griffin } 970b7c6075SPeter Griffin 980b7c6075SPeter Griffin /* 990b7c6075SPeter Griffin * For SoCs that have set/clear bit hardware this function can be used when 1000b7c6075SPeter Griffin * the PMU register will be accessed by multiple masters. 1010b7c6075SPeter Griffin * 1020b7c6075SPeter Griffin * For example, to set bits 13:8 in PMU reg offset 0x3e80 1030b7c6075SPeter Griffin * tensor_set_bits_atomic(ctx, 0x3e80, 0x3f00, 0x3f00); 1040b7c6075SPeter Griffin * 1050b7c6075SPeter Griffin * Set bit 8, and clear bits 13:9 PMU reg offset 0x3e80 1060b7c6075SPeter Griffin * tensor_set_bits_atomic(0x3e80, 0x100, 0x3f00); 1070b7c6075SPeter Griffin */ 1080b7c6075SPeter Griffin static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val, 1090b7c6075SPeter Griffin u32 mask) 1100b7c6075SPeter Griffin { 1110b7c6075SPeter Griffin int ret; 1120b7c6075SPeter Griffin unsigned int i; 1130b7c6075SPeter Griffin 1140b7c6075SPeter Griffin for (i = 0; i < 32; i++) { 1150b7c6075SPeter Griffin if (!(mask & BIT(i))) 1160b7c6075SPeter Griffin continue; 1170b7c6075SPeter Griffin 1180b7c6075SPeter Griffin offset &= ~TENSOR_SET_BITS; 1190b7c6075SPeter Griffin 1200b7c6075SPeter Griffin if (val & BIT(i)) 1210b7c6075SPeter Griffin offset |= TENSOR_SET_BITS; 1220b7c6075SPeter Griffin else 1230b7c6075SPeter Griffin offset |= TENSOR_CLR_BITS; 1240b7c6075SPeter Griffin 1250b7c6075SPeter Griffin ret = tensor_sec_reg_write(ctx, offset, i); 1260b7c6075SPeter Griffin if (ret) 1270b7c6075SPeter Griffin return ret; 1280b7c6075SPeter Griffin } 1290b7c6075SPeter Griffin return ret; 1300b7c6075SPeter Griffin } 1310b7c6075SPeter Griffin 132*97c4264fSPeter Griffin static bool tensor_is_atomic(unsigned int reg) 1330b7c6075SPeter Griffin { 1340b7c6075SPeter Griffin /* 1350b7c6075SPeter Griffin * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF) 136*97c4264fSPeter Griffin * as the target registers can be accessed by multiple masters. SFRs 137*97c4264fSPeter Griffin * that don't support atomic are added to the switch statement below. 1380b7c6075SPeter Griffin */ 1390b7c6075SPeter Griffin if (reg > PMUALIVE_MASK) 140*97c4264fSPeter Griffin return false; 141*97c4264fSPeter Griffin 142*97c4264fSPeter Griffin switch (reg) { 143*97c4264fSPeter Griffin case GS101_SYSIP_DAT0: 144*97c4264fSPeter Griffin case GS101_SYSTEM_CONFIGURATION: 145*97c4264fSPeter Griffin return false; 146*97c4264fSPeter Griffin default: 147*97c4264fSPeter Griffin return true; 148*97c4264fSPeter Griffin } 149*97c4264fSPeter Griffin } 150*97c4264fSPeter Griffin 151*97c4264fSPeter Griffin static int tensor_sec_update_bits(void *ctx, unsigned int reg, 152*97c4264fSPeter Griffin unsigned int mask, unsigned int val) 153*97c4264fSPeter Griffin { 154*97c4264fSPeter Griffin 155*97c4264fSPeter Griffin if (!tensor_is_atomic(reg)) 1560b7c6075SPeter Griffin return tensor_sec_reg_rmw(ctx, reg, mask, val); 1570b7c6075SPeter Griffin 1580b7c6075SPeter Griffin return tensor_set_bits_atomic(ctx, reg, val, mask); 1590b7c6075SPeter Griffin } 160bfce552dSPankaj Dubey 161bfce552dSPankaj Dubey void pmu_raw_writel(u32 val, u32 offset) 162bfce552dSPankaj Dubey { 163bfce552dSPankaj Dubey writel_relaxed(val, pmu_base_addr + offset); 164bfce552dSPankaj Dubey } 165bfce552dSPankaj Dubey 166bfce552dSPankaj Dubey u32 pmu_raw_readl(u32 offset) 167bfce552dSPankaj Dubey { 168bfce552dSPankaj Dubey return readl_relaxed(pmu_base_addr + offset); 169bfce552dSPankaj Dubey } 170bfce552dSPankaj Dubey 171bfce552dSPankaj Dubey void exynos_sys_powerdown_conf(enum sys_powerdown mode) 172bfce552dSPankaj Dubey { 173bfce552dSPankaj Dubey unsigned int i; 174bfce552dSPankaj Dubey const struct exynos_pmu_data *pmu_data; 175bfce552dSPankaj Dubey 176fa59aa70SMarek Szyprowski if (!pmu_context || !pmu_context->pmu_data) 177bfce552dSPankaj Dubey return; 178bfce552dSPankaj Dubey 179bfce552dSPankaj Dubey pmu_data = pmu_context->pmu_data; 180bfce552dSPankaj Dubey 181bfce552dSPankaj Dubey if (pmu_data->powerdown_conf) 182bfce552dSPankaj Dubey pmu_data->powerdown_conf(mode); 183bfce552dSPankaj Dubey 184bfce552dSPankaj Dubey if (pmu_data->pmu_config) { 185bfce552dSPankaj Dubey for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) 186bfce552dSPankaj Dubey pmu_raw_writel(pmu_data->pmu_config[i].val[mode], 187bfce552dSPankaj Dubey pmu_data->pmu_config[i].offset); 188bfce552dSPankaj Dubey } 189bfce552dSPankaj Dubey 190bfce552dSPankaj Dubey if (pmu_data->powerdown_conf_extra) 191bfce552dSPankaj Dubey pmu_data->powerdown_conf_extra(mode); 192514a935fSArtur Weber 193514a935fSArtur Weber if (pmu_data->pmu_config_extra) { 194514a935fSArtur Weber for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) 195514a935fSArtur Weber pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], 196514a935fSArtur Weber pmu_data->pmu_config_extra[i].offset); 197514a935fSArtur Weber } 198bfce552dSPankaj Dubey } 199bfce552dSPankaj Dubey 200bfce552dSPankaj Dubey /* 201a0ebf662SKrzysztof Kozlowski * Split the data between ARM architectures because it is relatively big 202a0ebf662SKrzysztof Kozlowski * and useless on other arch. 203a0ebf662SKrzysztof Kozlowski */ 204a0ebf662SKrzysztof Kozlowski #ifdef CONFIG_EXYNOS_PMU_ARM_DRIVERS 205a0ebf662SKrzysztof Kozlowski #define exynos_pmu_data_arm_ptr(data) (&data) 206a0ebf662SKrzysztof Kozlowski #else 207a0ebf662SKrzysztof Kozlowski #define exynos_pmu_data_arm_ptr(data) NULL 208a0ebf662SKrzysztof Kozlowski #endif 209a0ebf662SKrzysztof Kozlowski 2100b7c6075SPeter Griffin static const struct regmap_config regmap_smccfg = { 2110b7c6075SPeter Griffin .name = "pmu_regs", 2120b7c6075SPeter Griffin .reg_bits = 32, 2130b7c6075SPeter Griffin .reg_stride = 4, 2140b7c6075SPeter Griffin .val_bits = 32, 2150b7c6075SPeter Griffin .fast_io = true, 2160b7c6075SPeter Griffin .use_single_read = true, 2170b7c6075SPeter Griffin .use_single_write = true, 2180b7c6075SPeter Griffin .reg_read = tensor_sec_reg_read, 2190b7c6075SPeter Griffin .reg_write = tensor_sec_reg_write, 2200b7c6075SPeter Griffin .reg_update_bits = tensor_sec_update_bits, 2210b7c6075SPeter Griffin }; 2220b7c6075SPeter Griffin 2230b7c6075SPeter Griffin static const struct regmap_config regmap_mmiocfg = { 2240b7c6075SPeter Griffin .name = "pmu_regs", 2250b7c6075SPeter Griffin .reg_bits = 32, 2260b7c6075SPeter Griffin .reg_stride = 4, 2270b7c6075SPeter Griffin .val_bits = 32, 2280b7c6075SPeter Griffin .fast_io = true, 2290b7c6075SPeter Griffin .use_single_read = true, 2300b7c6075SPeter Griffin .use_single_write = true, 2310b7c6075SPeter Griffin }; 2320b7c6075SPeter Griffin 2330b7c6075SPeter Griffin static const struct exynos_pmu_data gs101_pmu_data = { 2340b7c6075SPeter Griffin .pmu_secure = true 2350b7c6075SPeter Griffin }; 2360b7c6075SPeter Griffin 237a0ebf662SKrzysztof Kozlowski /* 238bfce552dSPankaj Dubey * PMU platform driver and devicetree bindings. 239bfce552dSPankaj Dubey */ 240bfce552dSPankaj Dubey static const struct of_device_id exynos_pmu_of_device_ids[] = { 241bfce552dSPankaj Dubey { 2420b7c6075SPeter Griffin .compatible = "google,gs101-pmu", 2430b7c6075SPeter Griffin .data = &gs101_pmu_data, 2440b7c6075SPeter Griffin }, { 245bfce552dSPankaj Dubey .compatible = "samsung,exynos3250-pmu", 246a0ebf662SKrzysztof Kozlowski .data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data), 247bfce552dSPankaj Dubey }, { 248bfce552dSPankaj Dubey .compatible = "samsung,exynos4210-pmu", 249a0ebf662SKrzysztof Kozlowski .data = exynos_pmu_data_arm_ptr(exynos4210_pmu_data), 250bfce552dSPankaj Dubey }, { 251514a935fSArtur Weber .compatible = "samsung,exynos4212-pmu", 252514a935fSArtur Weber .data = exynos_pmu_data_arm_ptr(exynos4212_pmu_data), 253514a935fSArtur Weber }, { 254bfce552dSPankaj Dubey .compatible = "samsung,exynos4412-pmu", 255a0ebf662SKrzysztof Kozlowski .data = exynos_pmu_data_arm_ptr(exynos4412_pmu_data), 256bfce552dSPankaj Dubey }, { 257bfce552dSPankaj Dubey .compatible = "samsung,exynos5250-pmu", 258a0ebf662SKrzysztof Kozlowski .data = exynos_pmu_data_arm_ptr(exynos5250_pmu_data), 259bfce552dSPankaj Dubey }, { 2607353c546SKrzysztof Kozlowski .compatible = "samsung,exynos5410-pmu", 2617353c546SKrzysztof Kozlowski }, { 262bfce552dSPankaj Dubey .compatible = "samsung,exynos5420-pmu", 263a0ebf662SKrzysztof Kozlowski .data = exynos_pmu_data_arm_ptr(exynos5420_pmu_data), 264fa59aa70SMarek Szyprowski }, { 265fa59aa70SMarek Szyprowski .compatible = "samsung,exynos5433-pmu", 2667353c546SKrzysztof Kozlowski }, { 2677353c546SKrzysztof Kozlowski .compatible = "samsung,exynos7-pmu", 268f5dc0140SSam Protsenko }, { 269f5dc0140SSam Protsenko .compatible = "samsung,exynos850-pmu", 270bfce552dSPankaj Dubey }, 271bfce552dSPankaj Dubey { /*sentinel*/ }, 272bfce552dSPankaj Dubey }; 273bfce552dSPankaj Dubey 27493618e34SKrzysztof Kozlowski static const struct mfd_cell exynos_pmu_devs[] = { 27593618e34SKrzysztof Kozlowski { .name = "exynos-clkout", }, 27693618e34SKrzysztof Kozlowski }; 27793618e34SKrzysztof Kozlowski 2780b7c6075SPeter Griffin /** 2790b7c6075SPeter Griffin * exynos_get_pmu_regmap() - Obtain pmureg regmap 2800b7c6075SPeter Griffin * 2810b7c6075SPeter Griffin * Find the pmureg regmap previously configured in probe() and return regmap 2820b7c6075SPeter Griffin * pointer. 2830b7c6075SPeter Griffin * 2840b7c6075SPeter Griffin * Return: A pointer to regmap if found or ERR_PTR error value. 2850b7c6075SPeter Griffin */ 28676640b84SMarek Szyprowski struct regmap *exynos_get_pmu_regmap(void) 28776640b84SMarek Szyprowski { 28876640b84SMarek Szyprowski struct device_node *np = of_find_matching_node(NULL, 28976640b84SMarek Szyprowski exynos_pmu_of_device_ids); 29076640b84SMarek Szyprowski if (np) 2910b7c6075SPeter Griffin return exynos_get_pmu_regmap_by_phandle(np, NULL); 29276640b84SMarek Szyprowski return ERR_PTR(-ENODEV); 29376640b84SMarek Szyprowski } 29476640b84SMarek Szyprowski EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap); 29576640b84SMarek Szyprowski 2960b7c6075SPeter Griffin /** 2970b7c6075SPeter Griffin * exynos_get_pmu_regmap_by_phandle() - Obtain pmureg regmap via phandle 2980b7c6075SPeter Griffin * @np: Device node holding PMU phandle property 2990b7c6075SPeter Griffin * @propname: Name of property holding phandle value 3000b7c6075SPeter Griffin * 3010b7c6075SPeter Griffin * Find the pmureg regmap previously configured in probe() and return regmap 3020b7c6075SPeter Griffin * pointer. 3030b7c6075SPeter Griffin * 3040b7c6075SPeter Griffin * Return: A pointer to regmap if found or ERR_PTR error value. 3050b7c6075SPeter Griffin */ 3060b7c6075SPeter Griffin struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np, 3070b7c6075SPeter Griffin const char *propname) 3080b7c6075SPeter Griffin { 3090b7c6075SPeter Griffin struct exynos_pmu_context *ctx; 3100b7c6075SPeter Griffin struct device_node *pmu_np; 3110b7c6075SPeter Griffin struct device *dev; 3120b7c6075SPeter Griffin 3130b7c6075SPeter Griffin if (propname) 3140b7c6075SPeter Griffin pmu_np = of_parse_phandle(np, propname, 0); 3150b7c6075SPeter Griffin else 3160b7c6075SPeter Griffin pmu_np = np; 3170b7c6075SPeter Griffin 3180b7c6075SPeter Griffin if (!pmu_np) 3190b7c6075SPeter Griffin return ERR_PTR(-ENODEV); 3200b7c6075SPeter Griffin 3210b7c6075SPeter Griffin /* 3220b7c6075SPeter Griffin * Determine if exynos-pmu device has probed and therefore regmap 3230b7c6075SPeter Griffin * has been created and can be returned to the caller. Otherwise we 3240b7c6075SPeter Griffin * return -EPROBE_DEFER. 3250b7c6075SPeter Griffin */ 3260b7c6075SPeter Griffin dev = driver_find_device_by_of_node(&exynos_pmu_driver.driver, 3270b7c6075SPeter Griffin (void *)pmu_np); 3280b7c6075SPeter Griffin 3290b7c6075SPeter Griffin if (propname) 3300b7c6075SPeter Griffin of_node_put(pmu_np); 3310b7c6075SPeter Griffin 3320b7c6075SPeter Griffin if (!dev) 3330b7c6075SPeter Griffin return ERR_PTR(-EPROBE_DEFER); 3340b7c6075SPeter Griffin 3350b7c6075SPeter Griffin ctx = dev_get_drvdata(dev); 3360b7c6075SPeter Griffin 3370b7c6075SPeter Griffin return ctx->pmureg; 3380b7c6075SPeter Griffin } 3390b7c6075SPeter Griffin EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle); 3400b7c6075SPeter Griffin 341bfce552dSPankaj Dubey static int exynos_pmu_probe(struct platform_device *pdev) 342bfce552dSPankaj Dubey { 343bfce552dSPankaj Dubey struct device *dev = &pdev->dev; 3440b7c6075SPeter Griffin struct regmap_config pmu_regmcfg; 3450b7c6075SPeter Griffin struct regmap *regmap; 3460b7c6075SPeter Griffin struct resource *res; 34793618e34SKrzysztof Kozlowski int ret; 348bfce552dSPankaj Dubey 34981a0efb7SYangtao Li pmu_base_addr = devm_platform_ioremap_resource(pdev, 0); 350bfce552dSPankaj Dubey if (IS_ERR(pmu_base_addr)) 351bfce552dSPankaj Dubey return PTR_ERR(pmu_base_addr); 352bfce552dSPankaj Dubey 353bfce552dSPankaj Dubey pmu_context = devm_kzalloc(&pdev->dev, 354bfce552dSPankaj Dubey sizeof(struct exynos_pmu_context), 355bfce552dSPankaj Dubey GFP_KERNEL); 3561da6de33SMarek Szyprowski if (!pmu_context) 357bfce552dSPankaj Dubey return -ENOMEM; 3580b7c6075SPeter Griffin 3590b7c6075SPeter Griffin res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3600b7c6075SPeter Griffin if (!res) 3610b7c6075SPeter Griffin return -ENODEV; 3620b7c6075SPeter Griffin 363ec7cc5b1SMarek Szyprowski pmu_context->pmu_data = of_device_get_match_data(dev); 364bfce552dSPankaj Dubey 3650b7c6075SPeter Griffin /* For SoCs that secure PMU register writes use custom regmap */ 3660b7c6075SPeter Griffin if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_secure) { 3670b7c6075SPeter Griffin pmu_regmcfg = regmap_smccfg; 3680b7c6075SPeter Griffin pmu_regmcfg.max_register = resource_size(res) - 3690b7c6075SPeter Griffin pmu_regmcfg.reg_stride; 3700b7c6075SPeter Griffin /* Need physical address for SMC call */ 3710b7c6075SPeter Griffin regmap = devm_regmap_init(dev, NULL, 3720b7c6075SPeter Griffin (void *)(uintptr_t)res->start, 3730b7c6075SPeter Griffin &pmu_regmcfg); 3740b7c6075SPeter Griffin } else { 3750b7c6075SPeter Griffin /* All other SoCs use a MMIO regmap */ 3760b7c6075SPeter Griffin pmu_regmcfg = regmap_mmiocfg; 3770b7c6075SPeter Griffin pmu_regmcfg.max_register = resource_size(res) - 3780b7c6075SPeter Griffin pmu_regmcfg.reg_stride; 3790b7c6075SPeter Griffin regmap = devm_regmap_init_mmio(dev, pmu_base_addr, 3800b7c6075SPeter Griffin &pmu_regmcfg); 3810b7c6075SPeter Griffin } 3820b7c6075SPeter Griffin 3830b7c6075SPeter Griffin if (IS_ERR(regmap)) 3840b7c6075SPeter Griffin return dev_err_probe(&pdev->dev, PTR_ERR(regmap), 3850b7c6075SPeter Griffin "regmap init failed\n"); 3860b7c6075SPeter Griffin 3870b7c6075SPeter Griffin pmu_context->pmureg = regmap; 3880b7c6075SPeter Griffin pmu_context->dev = dev; 3890b7c6075SPeter Griffin 390fa59aa70SMarek Szyprowski if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init) 391bfce552dSPankaj Dubey pmu_context->pmu_data->pmu_init(); 392bfce552dSPankaj Dubey 393bfce552dSPankaj Dubey platform_set_drvdata(pdev, pmu_context); 394bfce552dSPankaj Dubey 39593618e34SKrzysztof Kozlowski ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs, 39693618e34SKrzysztof Kozlowski ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL); 39793618e34SKrzysztof Kozlowski if (ret) 39893618e34SKrzysztof Kozlowski return ret; 39993618e34SKrzysztof Kozlowski 4007353c546SKrzysztof Kozlowski if (devm_of_platform_populate(dev)) 4017353c546SKrzysztof Kozlowski dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n"); 4027353c546SKrzysztof Kozlowski 403bfce552dSPankaj Dubey dev_dbg(dev, "Exynos PMU Driver probe done\n"); 404bfce552dSPankaj Dubey return 0; 405bfce552dSPankaj Dubey } 406bfce552dSPankaj Dubey 407bfce552dSPankaj Dubey static struct platform_driver exynos_pmu_driver = { 408bfce552dSPankaj Dubey .driver = { 409bfce552dSPankaj Dubey .name = "exynos-pmu", 410bfce552dSPankaj Dubey .of_match_table = exynos_pmu_of_device_ids, 411bfce552dSPankaj Dubey }, 412bfce552dSPankaj Dubey .probe = exynos_pmu_probe, 413bfce552dSPankaj Dubey }; 414bfce552dSPankaj Dubey 415bfce552dSPankaj Dubey static int __init exynos_pmu_init(void) 416bfce552dSPankaj Dubey { 417bfce552dSPankaj Dubey return platform_driver_register(&exynos_pmu_driver); 418bfce552dSPankaj Dubey 419bfce552dSPankaj Dubey } 420bfce552dSPankaj Dubey postcore_initcall(exynos_pmu_init); 421