diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 04:41:31 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 04:41:31 +0300 |
commit | 02c3de1105228e367320e7fdeffbf511904f398c (patch) | |
tree | d0861ed0752806c6c85e72749734dad9914a8cd9 /drivers/devfreq/event/exynos-ppmu.c | |
parent | 7aa7d608112baf63a0b1278955f9619427373807 (diff) | |
parent | eee77a8a0d268b936b1641fd7d55efaa17c351d6 (diff) | |
download | linux-02c3de1105228e367320e7fdeffbf511904f398c.tar.xz |
Merge tag 'pm-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki:
"The majority of changes go into the Operating Performance Points (OPP)
framework and cpufreq this time, followed by devfreq and some
scattered updates all over.
The OPP changes are mostly related to switching over from RCU-based
synchronization, that turned out to be overly complicated and
problematic, to reference counting using krefs.
In the cpufreq land there are core cleanups, documentation updates, a
new driver for Broadcom BMIPS SoCs, a new cpufreq-dt sub-driver for TI
SoCs that require special handling, ARM64 SoCs support for the qoriq
driver, intel_pstate updates, powernv driver update and assorted
fixes.
The devfreq changes are mostly fixes related to the sysfs interface
and some Exynos drivers updates.
Apart from that, the cpuidle menu governor will support per-CPU PM QoS
constraints for the wakeup latency now, some bugs in the wakeup IRQs
framework are fixed, the generic power domains framework should handle
asynchronous invocations of *noirq suspend/resume callbacks from now
on, the analyze_suspend.py script is updated and there is a new tool
for intel_pstate diagnostics.
Specifics:
- Operating Performance Points (OPP) framework fixes, cleanups and
switch over from RCU-based synchronization to reference counting
using krefs (Viresh Kumar, Wei Yongjun, Dave Gerlach)
- cpufreq core cleanups and documentation updates (Viresh Kumar,
Rafael Wysocki)
- New cpufreq driver for Broadcom BMIPS SoCs (Markus Mayer)
- New cpufreq-dt sub-driver for TI SoCs requiring special handling,
like in the AM335x, AM437x, DRA7x, and AM57x families, along with
new DT bindings for it (Dave Gerlach, Paul Gortmaker)
- ARM64 SoCs support for the qoriq cpufreq driver (Tang Yuantian)
- intel_pstate driver updates including a new sysfs knob to control
the driver's operation mode and fixes related to the no_turbo sysfs
knob and the hardware-managed P-states feature support (Rafael
Wysocki, Srinivas Pandruvada)
- New interface to export ultra-turbo frequencies for the powernv
cpufreq driver (Shilpasri Bhat)
- Assorted fixes for cpufreq drivers (Arnd Bergmann, Dan Carpenter,
Wei Yongjun)
- devfreq core fixes, mostly related to the sysfs interface exported
by it (Chanwoo Choi, Chris Diamand)
- Updates of the exynos-bus and exynos-ppmu devfreq drivers (Chanwoo
Choi)
- Device PM QoS extension to support CPUs and support for per-CPU
wakeup (device resume) latency constraints in the cpuidle menu
governor (Alex Shi)
- Wakeup IRQs framework fixes (Grygorii Strashko)
- Generic power domains framework update including a fix to make it
handle asynchronous invocations of *noirq suspend/resume callbacks
correctly (Ulf Hansson, Geert Uytterhoeven)
- Assorted fixes and cleanups in the core suspend/hibernate code, PM
QoS framework and x86 ACPI idle support code (Corentin Labbe, Geert
Uytterhoeven, Geliang Tang, John Keeping, Nick Desaulniers)
- Update of the analyze_suspend.py script is updated to version 4.5
offering multiple improvements (Todd Brandt)
- New tool for intel_pstate diagnostics using the pstate_sample
tracepoint (Doug Smythies)"
* tag 'pm-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (85 commits)
MAINTAINERS: cpufreq: add bmips-cpufreq.c
PM / QoS: Fix memory leak on resume_latency.notifiers
PM / Documentation: Spelling s/wrtie/write/
PM / sleep: Fix test_suspend after sleep state rework
cpufreq: CPPC: add ACPI_PROCESSOR dependency
cpufreq: make ti-cpufreq explicitly non-modular
cpufreq: Do not clear real_cpus mask on policy init
tools/power/x86: Debug utility for intel_pstate driver
AnalyzeSuspend: fix drag and zoom bug in javascript
PM / wakeirq: report a wakeup_event on dedicated wekup irq
PM / wakeirq: Fix spurious wake-up events for dedicated wakeirqs
PM / wakeirq: Enable dedicated wakeirq for suspend
cpufreq: dt: Don't use generic platdev driver for ti-cpufreq platforms
cpufreq: ti: Add cpufreq driver to determine available OPPs at runtime
Documentation: dt: add bindings for ti-cpufreq
PM / OPP: Expose _of_get_opp_desc_node as dev_pm_opp API
cpufreq: qoriq: Don't look at clock implementation details
cpufreq: qoriq: add ARM64 SoCs support
PM / Domains: Provide dummy governors if CONFIG_PM_GENERIC_DOMAINS=n
cpufreq: brcmstb-avs-cpufreq: remove unnecessary platform_set_drvdata()
...
Diffstat (limited to 'drivers/devfreq/event/exynos-ppmu.c')
-rw-r--r-- | drivers/devfreq/event/exynos-ppmu.c | 329 |
1 files changed, 240 insertions, 89 deletions
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 107eb91a9415..9b7350935b73 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -17,13 +17,13 @@ #include <linux/module.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/suspend.h> #include <linux/devfreq-event.h> #include "exynos-ppmu.h" struct exynos_ppmu_data { - void __iomem *base; struct clk *clk; }; @@ -33,6 +33,7 @@ struct exynos_ppmu { unsigned int num_events; struct device *dev; + struct regmap *regmap; struct exynos_ppmu_data ppmu; }; @@ -107,20 +108,28 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) static int exynos_ppmu_disable(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int ret; u32 pmnc; /* Disable all counters */ - __raw_writel(PPMU_CCNT_MASK | - PPMU_PMCNT0_MASK | - PPMU_PMCNT1_MASK | - PPMU_PMCNT2_MASK | - PPMU_PMCNT3_MASK, - info->ppmu.base + PPMU_CNTENC); + ret = regmap_write(info->regmap, PPMU_CNTENC, + PPMU_CCNT_MASK | + PPMU_PMCNT0_MASK | + PPMU_PMCNT1_MASK | + PPMU_PMCNT2_MASK | + PPMU_PMCNT3_MASK); + if (ret < 0) + return ret; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -129,29 +138,42 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); + int ret; u32 pmnc, cntens; if (id < 0) return id; /* Enable specific counter */ - cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); + ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens); + if (ret < 0) + return ret; + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); + ret = regmap_write(info->regmap, PPMU_CNTENS, cntens); + if (ret < 0) + return ret; /* Set the event of Read/Write data count */ - __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, - info->ppmu.base + PPMU_BEVTxSEL(id)); + ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id), + PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT); + if (ret < 0) + return ret; /* Reset cycle counter/performance counter and enable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~(PPMU_PMNC_ENABLE_MASK | PPMU_PMNC_COUNTER_RESET_MASK | PPMU_PMNC_CC_RESET_MASK); pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -161,40 +183,64 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntenc; + unsigned int total_count, load_count; + unsigned int pmcnt3_high, pmcnt3_low; + unsigned int pmnc, cntenc; + int ret; if (id < 0) return -EINVAL; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; /* Read cycle count */ - edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); + ret = regmap_read(info->regmap, PPMU_CCNT, &total_count); + if (ret < 0) + return ret; + edata->total_count = total_count; /* Read performance count */ switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - edata->load_count - = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); + ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count); + if (ret < 0) + return ret; + edata->load_count = load_count; break; case PPMU_PMNCNT3: - edata->load_count = - ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) - | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); + ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high); + if (ret < 0) + return ret; + + ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low); + if (ret < 0) + return ret; + + edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low); break; default: return -EINVAL; } /* Disable specific counter */ - cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); + ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc); + if (ret < 0) + return ret; + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); + ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc); + if (ret < 0) + return ret; dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, edata->load_count, edata->total_count); @@ -214,36 +260,93 @@ static const struct devfreq_event_ops exynos_ppmu_ops = { static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int ret; u32 pmnc, clear; /* Disable all counters */ clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); + ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0); + if (ret < 0) + return ret; - __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); - __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); - __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); - __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); - - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); + ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0); + if (ret < 0) + return ret; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -251,30 +354,43 @@ static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + unsigned int pmnc, cntens; int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntens; + int ret; /* Enable all counters */ - cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); + ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens); + if (ret < 0) + return ret; + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); + ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens); + if (ret < 0) + return ret; /* Set the event of Read/Write data count */ switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, - info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), + PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT); + if (ret < 0) + return ret; break; case PPMU_PMNCNT3: - __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, - info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), + PPMU_V2_EVT3_RW_DATA_CNT); + if (ret < 0) + return ret; break; } /* Reset cycle counter/performance counter and enable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~(PPMU_PMNC_ENABLE_MASK | PPMU_PMNC_COUNTER_RESET_MASK | PPMU_PMNC_CC_RESET_MASK @@ -284,7 +400,10 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -294,37 +413,61 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntenc; - u32 pmcnt_high, pmcnt_low; - u64 load_count = 0; + int ret; + unsigned int pmnc, cntenc; + unsigned int pmcnt_high, pmcnt_low; + unsigned int total_count, count; + unsigned long load_count = 0; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; /* Read cycle count and performance count */ - edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); + ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count); + if (ret < 0) + return ret; + edata->total_count = total_count; switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); + ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count); + if (ret < 0) + return ret; + load_count = count; break; case PPMU_PMNCNT3: - pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); - pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); - load_count = ((u64)((pmcnt_high & 0xff)) << 32) - + (u64)pmcnt_low; + ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH, + &pmcnt_high); + if (ret < 0) + return ret; + + ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low); + if (ret < 0) + return ret; + + load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low; break; } edata->load_count = load_count; /* Disable all counters */ - cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); + ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc); + if (ret < 0) + return 0; + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); + ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc); + if (ret < 0) + return ret; dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, edata->load_count, edata->total_count); @@ -411,10 +554,19 @@ static int of_get_devfreq_events(struct device_node *np, return 0; } -static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) +static struct regmap_config exynos_ppmu_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int exynos_ppmu_parse_dt(struct platform_device *pdev, + struct exynos_ppmu *info) { struct device *dev = info->dev; struct device_node *np = dev->of_node; + struct resource *res; + void __iomem *base; int ret = 0; if (!np) { @@ -423,10 +575,17 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) } /* Maps the memory mapped IO to control PPMU register */ - info->ppmu.base = of_iomap(np, 0); - if (IS_ERR_OR_NULL(info->ppmu.base)) { - dev_err(dev, "failed to map memory region\n"); - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + exynos_ppmu_regmap_config.max_register = resource_size(res) - 4; + info->regmap = devm_regmap_init_mmio(dev, base, + &exynos_ppmu_regmap_config); + if (IS_ERR(info->regmap)) { + dev_err(dev, "failed to initialize regmap\n"); + return PTR_ERR(info->regmap); } info->ppmu.clk = devm_clk_get(dev, "ppmu"); @@ -438,15 +597,10 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) ret = of_get_devfreq_events(np, info); if (ret < 0) { dev_err(dev, "failed to parse exynos ppmu dt node\n"); - goto err; + return ret; } return 0; - -err: - iounmap(info->ppmu.base); - - return ret; } static int exynos_ppmu_probe(struct platform_device *pdev) @@ -463,7 +617,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) info->dev = &pdev->dev; /* Parse dt data to get resource */ - ret = exynos_ppmu_parse_dt(info); + ret = exynos_ppmu_parse_dt(pdev, info); if (ret < 0) { dev_err(&pdev->dev, "failed to parse devicetree for resource\n"); @@ -476,8 +630,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) if (!info->edev) { dev_err(&pdev->dev, "failed to allocate memory devfreq-event devices\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } edev = info->edev; platform_set_drvdata(pdev, info); @@ -488,17 +641,16 @@ static int exynos_ppmu_probe(struct platform_device *pdev) ret = PTR_ERR(edev[i]); dev_err(&pdev->dev, "failed to add devfreq-event device\n"); - goto err; + return PTR_ERR(edev[i]); } + + pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n", + dev_name(&pdev->dev), desc[i].name); } clk_prepare_enable(info->ppmu.clk); return 0; -err: - iounmap(info->ppmu.base); - - return ret; } static int exynos_ppmu_remove(struct platform_device *pdev) @@ -506,7 +658,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev) struct exynos_ppmu *info = platform_get_drvdata(pdev); clk_disable_unprepare(info->ppmu.clk); - iounmap(info->ppmu.base); return 0; } |