1*bfce552dSPankaj Dubey /* 2*bfce552dSPankaj Dubey * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. 3*bfce552dSPankaj Dubey * http://www.samsung.com/ 4*bfce552dSPankaj Dubey * 5*bfce552dSPankaj Dubey * EXYNOS - CPU PMU(Power Management Unit) support 6*bfce552dSPankaj Dubey * 7*bfce552dSPankaj Dubey * This program is free software; you can redistribute it and/or modify 8*bfce552dSPankaj Dubey * it under the terms of the GNU General Public License version 2 as 9*bfce552dSPankaj Dubey * published by the Free Software Foundation. 10*bfce552dSPankaj Dubey */ 11*bfce552dSPankaj Dubey 12*bfce552dSPankaj Dubey #include <linux/of.h> 13*bfce552dSPankaj Dubey #include <linux/of_address.h> 14*bfce552dSPankaj Dubey #include <linux/platform_device.h> 15*bfce552dSPankaj Dubey #include <linux/delay.h> 16*bfce552dSPankaj Dubey 17*bfce552dSPankaj Dubey #include <linux/soc/samsung/exynos-regs-pmu.h> 18*bfce552dSPankaj Dubey #include <linux/soc/samsung/exynos-pmu.h> 19*bfce552dSPankaj Dubey 20*bfce552dSPankaj Dubey #include "exynos-pmu.h" 21*bfce552dSPankaj Dubey 22*bfce552dSPankaj Dubey struct exynos_pmu_context { 23*bfce552dSPankaj Dubey struct device *dev; 24*bfce552dSPankaj Dubey const struct exynos_pmu_data *pmu_data; 25*bfce552dSPankaj Dubey }; 26*bfce552dSPankaj Dubey 27*bfce552dSPankaj Dubey void __iomem *pmu_base_addr; 28*bfce552dSPankaj Dubey static struct exynos_pmu_context *pmu_context; 29*bfce552dSPankaj Dubey 30*bfce552dSPankaj Dubey void pmu_raw_writel(u32 val, u32 offset) 31*bfce552dSPankaj Dubey { 32*bfce552dSPankaj Dubey writel_relaxed(val, pmu_base_addr + offset); 33*bfce552dSPankaj Dubey } 34*bfce552dSPankaj Dubey 35*bfce552dSPankaj Dubey u32 pmu_raw_readl(u32 offset) 36*bfce552dSPankaj Dubey { 37*bfce552dSPankaj Dubey return readl_relaxed(pmu_base_addr + offset); 38*bfce552dSPankaj Dubey } 39*bfce552dSPankaj Dubey 40*bfce552dSPankaj Dubey void exynos_sys_powerdown_conf(enum sys_powerdown mode) 41*bfce552dSPankaj Dubey { 42*bfce552dSPankaj Dubey unsigned int i; 43*bfce552dSPankaj Dubey const struct exynos_pmu_data *pmu_data; 44*bfce552dSPankaj Dubey 45*bfce552dSPankaj Dubey if (!pmu_context) 46*bfce552dSPankaj Dubey return; 47*bfce552dSPankaj Dubey 48*bfce552dSPankaj Dubey pmu_data = pmu_context->pmu_data; 49*bfce552dSPankaj Dubey 50*bfce552dSPankaj Dubey if (pmu_data->powerdown_conf) 51*bfce552dSPankaj Dubey pmu_data->powerdown_conf(mode); 52*bfce552dSPankaj Dubey 53*bfce552dSPankaj Dubey if (pmu_data->pmu_config) { 54*bfce552dSPankaj Dubey for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) 55*bfce552dSPankaj Dubey pmu_raw_writel(pmu_data->pmu_config[i].val[mode], 56*bfce552dSPankaj Dubey pmu_data->pmu_config[i].offset); 57*bfce552dSPankaj Dubey } 58*bfce552dSPankaj Dubey 59*bfce552dSPankaj Dubey if (pmu_data->powerdown_conf_extra) 60*bfce552dSPankaj Dubey pmu_data->powerdown_conf_extra(mode); 61*bfce552dSPankaj Dubey 62*bfce552dSPankaj Dubey if (pmu_data->pmu_config_extra) { 63*bfce552dSPankaj Dubey for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) 64*bfce552dSPankaj Dubey pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], 65*bfce552dSPankaj Dubey pmu_data->pmu_config_extra[i].offset); 66*bfce552dSPankaj Dubey } 67*bfce552dSPankaj Dubey } 68*bfce552dSPankaj Dubey 69*bfce552dSPankaj Dubey /* 70*bfce552dSPankaj Dubey * PMU platform driver and devicetree bindings. 71*bfce552dSPankaj Dubey */ 72*bfce552dSPankaj Dubey static const struct of_device_id exynos_pmu_of_device_ids[] = { 73*bfce552dSPankaj Dubey { 74*bfce552dSPankaj Dubey .compatible = "samsung,exynos3250-pmu", 75*bfce552dSPankaj Dubey .data = &exynos3250_pmu_data, 76*bfce552dSPankaj Dubey }, { 77*bfce552dSPankaj Dubey .compatible = "samsung,exynos4210-pmu", 78*bfce552dSPankaj Dubey .data = &exynos4210_pmu_data, 79*bfce552dSPankaj Dubey }, { 80*bfce552dSPankaj Dubey .compatible = "samsung,exynos4212-pmu", 81*bfce552dSPankaj Dubey .data = &exynos4212_pmu_data, 82*bfce552dSPankaj Dubey }, { 83*bfce552dSPankaj Dubey .compatible = "samsung,exynos4412-pmu", 84*bfce552dSPankaj Dubey .data = &exynos4412_pmu_data, 85*bfce552dSPankaj Dubey }, { 86*bfce552dSPankaj Dubey .compatible = "samsung,exynos5250-pmu", 87*bfce552dSPankaj Dubey .data = &exynos5250_pmu_data, 88*bfce552dSPankaj Dubey }, { 89*bfce552dSPankaj Dubey .compatible = "samsung,exynos5420-pmu", 90*bfce552dSPankaj Dubey .data = &exynos5420_pmu_data, 91*bfce552dSPankaj Dubey }, 92*bfce552dSPankaj Dubey { /*sentinel*/ }, 93*bfce552dSPankaj Dubey }; 94*bfce552dSPankaj Dubey 95*bfce552dSPankaj Dubey static int exynos_pmu_probe(struct platform_device *pdev) 96*bfce552dSPankaj Dubey { 97*bfce552dSPankaj Dubey const struct of_device_id *match; 98*bfce552dSPankaj Dubey struct device *dev = &pdev->dev; 99*bfce552dSPankaj Dubey struct resource *res; 100*bfce552dSPankaj Dubey 101*bfce552dSPankaj Dubey res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 102*bfce552dSPankaj Dubey pmu_base_addr = devm_ioremap_resource(dev, res); 103*bfce552dSPankaj Dubey if (IS_ERR(pmu_base_addr)) 104*bfce552dSPankaj Dubey return PTR_ERR(pmu_base_addr); 105*bfce552dSPankaj Dubey 106*bfce552dSPankaj Dubey pmu_context = devm_kzalloc(&pdev->dev, 107*bfce552dSPankaj Dubey sizeof(struct exynos_pmu_context), 108*bfce552dSPankaj Dubey GFP_KERNEL); 109*bfce552dSPankaj Dubey if (!pmu_context) { 110*bfce552dSPankaj Dubey dev_err(dev, "Cannot allocate memory.\n"); 111*bfce552dSPankaj Dubey return -ENOMEM; 112*bfce552dSPankaj Dubey } 113*bfce552dSPankaj Dubey pmu_context->dev = dev; 114*bfce552dSPankaj Dubey 115*bfce552dSPankaj Dubey match = of_match_node(exynos_pmu_of_device_ids, dev->of_node); 116*bfce552dSPankaj Dubey 117*bfce552dSPankaj Dubey pmu_context->pmu_data = match->data; 118*bfce552dSPankaj Dubey 119*bfce552dSPankaj Dubey if (pmu_context->pmu_data->pmu_init) 120*bfce552dSPankaj Dubey pmu_context->pmu_data->pmu_init(); 121*bfce552dSPankaj Dubey 122*bfce552dSPankaj Dubey platform_set_drvdata(pdev, pmu_context); 123*bfce552dSPankaj Dubey 124*bfce552dSPankaj Dubey dev_dbg(dev, "Exynos PMU Driver probe done\n"); 125*bfce552dSPankaj Dubey return 0; 126*bfce552dSPankaj Dubey } 127*bfce552dSPankaj Dubey 128*bfce552dSPankaj Dubey static struct platform_driver exynos_pmu_driver = { 129*bfce552dSPankaj Dubey .driver = { 130*bfce552dSPankaj Dubey .name = "exynos-pmu", 131*bfce552dSPankaj Dubey .of_match_table = exynos_pmu_of_device_ids, 132*bfce552dSPankaj Dubey }, 133*bfce552dSPankaj Dubey .probe = exynos_pmu_probe, 134*bfce552dSPankaj Dubey }; 135*bfce552dSPankaj Dubey 136*bfce552dSPankaj Dubey static int __init exynos_pmu_init(void) 137*bfce552dSPankaj Dubey { 138*bfce552dSPankaj Dubey return platform_driver_register(&exynos_pmu_driver); 139*bfce552dSPankaj Dubey 140*bfce552dSPankaj Dubey } 141*bfce552dSPankaj Dubey postcore_initcall(exynos_pmu_init); 142