0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/of.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_device.h>
0011 #include <linux/mfd/core.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/delay.h>
0015
0016 #include <linux/soc/samsung/exynos-regs-pmu.h>
0017 #include <linux/soc/samsung/exynos-pmu.h>
0018
0019 #include "exynos-pmu.h"
0020
0021 struct exynos_pmu_context {
0022 struct device *dev;
0023 const struct exynos_pmu_data *pmu_data;
0024 };
0025
0026 void __iomem *pmu_base_addr;
0027 static struct exynos_pmu_context *pmu_context;
0028
0029 void pmu_raw_writel(u32 val, u32 offset)
0030 {
0031 writel_relaxed(val, pmu_base_addr + offset);
0032 }
0033
0034 u32 pmu_raw_readl(u32 offset)
0035 {
0036 return readl_relaxed(pmu_base_addr + offset);
0037 }
0038
0039 void exynos_sys_powerdown_conf(enum sys_powerdown mode)
0040 {
0041 unsigned int i;
0042 const struct exynos_pmu_data *pmu_data;
0043
0044 if (!pmu_context || !pmu_context->pmu_data)
0045 return;
0046
0047 pmu_data = pmu_context->pmu_data;
0048
0049 if (pmu_data->powerdown_conf)
0050 pmu_data->powerdown_conf(mode);
0051
0052 if (pmu_data->pmu_config) {
0053 for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++)
0054 pmu_raw_writel(pmu_data->pmu_config[i].val[mode],
0055 pmu_data->pmu_config[i].offset);
0056 }
0057
0058 if (pmu_data->powerdown_conf_extra)
0059 pmu_data->powerdown_conf_extra(mode);
0060 }
0061
0062
0063
0064
0065
0066 #ifdef CONFIG_EXYNOS_PMU_ARM_DRIVERS
0067 #define exynos_pmu_data_arm_ptr(data) (&data)
0068 #else
0069 #define exynos_pmu_data_arm_ptr(data) NULL
0070 #endif
0071
0072
0073
0074
0075 static const struct of_device_id exynos_pmu_of_device_ids[] = {
0076 {
0077 .compatible = "samsung,exynos3250-pmu",
0078 .data = exynos_pmu_data_arm_ptr(exynos3250_pmu_data),
0079 }, {
0080 .compatible = "samsung,exynos4210-pmu",
0081 .data = exynos_pmu_data_arm_ptr(exynos4210_pmu_data),
0082 }, {
0083 .compatible = "samsung,exynos4412-pmu",
0084 .data = exynos_pmu_data_arm_ptr(exynos4412_pmu_data),
0085 }, {
0086 .compatible = "samsung,exynos5250-pmu",
0087 .data = exynos_pmu_data_arm_ptr(exynos5250_pmu_data),
0088 }, {
0089 .compatible = "samsung,exynos5410-pmu",
0090 }, {
0091 .compatible = "samsung,exynos5420-pmu",
0092 .data = exynos_pmu_data_arm_ptr(exynos5420_pmu_data),
0093 }, {
0094 .compatible = "samsung,exynos5433-pmu",
0095 }, {
0096 .compatible = "samsung,exynos7-pmu",
0097 }, {
0098 .compatible = "samsung,exynos850-pmu",
0099 },
0100 { },
0101 };
0102
0103 static const struct mfd_cell exynos_pmu_devs[] = {
0104 { .name = "exynos-clkout", },
0105 };
0106
0107 struct regmap *exynos_get_pmu_regmap(void)
0108 {
0109 struct device_node *np = of_find_matching_node(NULL,
0110 exynos_pmu_of_device_ids);
0111 if (np)
0112 return syscon_node_to_regmap(np);
0113 return ERR_PTR(-ENODEV);
0114 }
0115 EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
0116
0117 static int exynos_pmu_probe(struct platform_device *pdev)
0118 {
0119 struct device *dev = &pdev->dev;
0120 int ret;
0121
0122 pmu_base_addr = devm_platform_ioremap_resource(pdev, 0);
0123 if (IS_ERR(pmu_base_addr))
0124 return PTR_ERR(pmu_base_addr);
0125
0126 pmu_context = devm_kzalloc(&pdev->dev,
0127 sizeof(struct exynos_pmu_context),
0128 GFP_KERNEL);
0129 if (!pmu_context)
0130 return -ENOMEM;
0131 pmu_context->dev = dev;
0132 pmu_context->pmu_data = of_device_get_match_data(dev);
0133
0134 if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
0135 pmu_context->pmu_data->pmu_init();
0136
0137 platform_set_drvdata(pdev, pmu_context);
0138
0139 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs,
0140 ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL);
0141 if (ret)
0142 return ret;
0143
0144 if (devm_of_platform_populate(dev))
0145 dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
0146
0147 dev_dbg(dev, "Exynos PMU Driver probe done\n");
0148 return 0;
0149 }
0150
0151 static struct platform_driver exynos_pmu_driver = {
0152 .driver = {
0153 .name = "exynos-pmu",
0154 .of_match_table = exynos_pmu_of_device_ids,
0155 },
0156 .probe = exynos_pmu_probe,
0157 };
0158
0159 static int __init exynos_pmu_init(void)
0160 {
0161 return platform_driver_register(&exynos_pmu_driver);
0162
0163 }
0164 postcore_initcall(exynos_pmu_init);