Samsung SoC drivers for v6.18
1. Google GS101:
Enable CPU Idle, which needs programming C2 idle hints
via ACPM firmware (Alive Clock and Power Manager). The patch
introducing this depends on 'local-timer-stop' Devicetree property,
which was merged in v6.17.
Fix handling error codes in ACPM firmware driver when talking to
PMIC.
2. Exynos2200: Add dedicated compatible for serial engines (USI).
-----BEGIN PGP SIGNATURE-----
iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmjEJbkQHGtyemtAa2Vy
bmVsLm9yZwAKCRDBN2bmhouD1wotD/9sMtDTS2graV2Rda60ltXBYbTQmZGFCPbu
0QLoXl7spLvKGAbS/Dp7nRsf3oyZ1Hnc0uqeWKNglJNwESelgPX0gdc4/3CMTg2c
CJ8Jw7IuxAuoy09W+EJsY+/tdEnmQNO//YVltn6Ycmo3T2CixYAbAUgmQQ7f1zaA
RjK/3AYUJMcVs5H/ZBOHMWUZyUCTYlxxppBpcXfqJDoyY0E57JtPX5n2jdHSiwKt
qyNOUWWVz3gG+tWXc1vQXoqnQTUQ7QJPMgaMb3kz4khrlz6QxedRT5uy0b7c6cJs
yNLBL6pwXNtHcpmESLmRpI4dBeJPeJhEyWS9UfiXH4AduynUQkKvGQxwjC2OUSPB
xhF8G1aZ59VM+cmhPcR5Vp/RtKpls3J07EeVBB0oEbABEIoXuN48m9fxaxplUdhG
/WgwaONFBmBQEOcIUpSlASGysHOoRcVRg21+gGvOqH5gh9AwuqhIPZzw7kONhNaU
WT1mSZaf4XtdqKnE5OorQteutgU+w6GEoS+0u20SKvcnVrGQi4vb2VAzzV/JSHG1
KHqTbNGGR+TDgrz0caNTOK1vZ4Qtv4JR/ZO0GH6BVqeqWsLI6sP/N/tgIbQ4OcJ/
z48ejpR7/c/kd8Nl+5U8bg7I3LsnQwpJwvzGH8Ot5KXgjoRYGt8pBzQyhgYNbFb1
UdAUJmi4BQ==
=pOwr
-----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmjIID8ACgkQmmx57+YA
GNn9sA/+JLhonck3esYyA1F3/rdrllTDwCCLU357LqVBTuIcmXC/ePKQU0MMkBcg
KA8S9tPyeEiegl2dhHSajrdavcBoUcXs3HVDVfLafcBP5ZItQuVaNj0gnXKf+npa
cE+udnqihXBSSUeNJFPS8eO8qh77amUJxGF570zPoA62M8Z3lq1ZevI0LeA69eLO
yujIEU7tSLjkcQlPr/Yj9+MjR8X672zp8sCDHrspGNtnyXklty5cC8P9CJqnCWBv
hpbzRT+R0GeugiswdFqS5Kt0umXsdilXZRU4Azc3m+OVgzTDFZovjj38sZ0QMW1K
oktwHKt7IZ3/T9v+sQLHemiYVoGOIaveBHEN7CJ1acGMPeSZHm68Aggs2JMsofqy
/u2dCGWyMBgZB0K5ZQ532Q7mj+tW1SVvX33hJd3/MpskyRBJOecJdo8NHgor3g/q
yWhfj5nNFUoIMoxl+NuRe6gbmwwSH9DUnAI7a6LAHoBkfth9pLm26hYfMypoYBIE
R3MM2ywDdMRNUIAd0JseBmLLQ2Ka/jU+UdIH3+wd9FY5f4+ghNmRIsnxaWVy4aI/
/nSMDR9jb+8lNgmZzqTJmDPBmK18AZdCc+nnrifyfCls7uwux4w/F4zJbReYkU/W
YKVxbUWO/C0dmRC1vOOcfRsmduMjWex/5wj+kStNE20j8OVeLdY=
=4h/m
-----END PGP SIGNATURE-----
Merge tag 'samsung-drivers-6.18' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into soc/drivers
Samsung SoC drivers for v6.18
1. Google GS101:
Enable CPU Idle, which needs programming C2 idle hints
via ACPM firmware (Alive Clock and Power Manager). The patch
introducing this depends on 'local-timer-stop' Devicetree property,
which was merged in v6.17.
Fix handling error codes in ACPM firmware driver when talking to
PMIC.
2. Exynos2200: Add dedicated compatible for serial engines (USI).
* tag 'samsung-drivers-6.18' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux:
firmware: exynos-acpm: fix PMIC returned errno
dt-bindings: soc: samsung: usi: add samsung,exynos2200-usi compatible
soc: samsung: exynos-pmu: Enable CPU Idle for gs101
Link: https://lore.kernel.org/r/20250912135448.203678-2-krzysztof.kozlowski@linaro.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
pull/1354/merge
commit
7b1349bd47
|
|
@ -36,6 +36,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- google,gs101-usi
|
||||
- samsung,exynos2200-usi
|
||||
- samsung,exynosautov9-usi
|
||||
- samsung,exynosautov920-usi
|
||||
- const: samsung,exynos850-usi
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
* Copyright 2020 Google LLC.
|
||||
* Copyright 2024 Linaro Ltd.
|
||||
*/
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/types.h>
|
||||
|
|
@ -33,6 +35,19 @@ enum exynos_acpm_pmic_func {
|
|||
ACPM_PMIC_BULK_WRITE,
|
||||
};
|
||||
|
||||
static const int acpm_pmic_linux_errmap[] = {
|
||||
[0] = 0, /* ACPM_PMIC_SUCCESS */
|
||||
[1] = -EACCES, /* Read register can't be accessed or issues to access it. */
|
||||
[2] = -EACCES, /* Write register can't be accessed or issues to access it. */
|
||||
};
|
||||
|
||||
static int acpm_pmic_to_linux_err(int err)
|
||||
{
|
||||
if (err >= 0 && err < ARRAY_SIZE(acpm_pmic_linux_errmap))
|
||||
return acpm_pmic_linux_errmap[err];
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static inline u32 acpm_pmic_set_bulk(u32 data, unsigned int i)
|
||||
{
|
||||
return (data & ACPM_PMIC_BULK_MASK) << (ACPM_PMIC_BULK_SHIFT * i);
|
||||
|
|
@ -79,7 +94,7 @@ int acpm_pmic_read_reg(const struct acpm_handle *handle,
|
|||
|
||||
*buf = FIELD_GET(ACPM_PMIC_VALUE, xfer.rxd[1]);
|
||||
|
||||
return FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]);
|
||||
return acpm_pmic_to_linux_err(FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]));
|
||||
}
|
||||
|
||||
static void acpm_pmic_init_bulk_read_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
|
||||
|
|
@ -110,7 +125,7 @@ int acpm_pmic_bulk_read(const struct acpm_handle *handle,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]);
|
||||
ret = acpm_pmic_to_linux_err(FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -150,7 +165,7 @@ int acpm_pmic_write_reg(const struct acpm_handle *handle,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]);
|
||||
return acpm_pmic_to_linux_err(FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]));
|
||||
}
|
||||
|
||||
static void acpm_pmic_init_bulk_write_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
|
||||
|
|
@ -190,7 +205,7 @@ int acpm_pmic_bulk_write(const struct acpm_handle *handle,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]);
|
||||
return acpm_pmic_to_linux_err(FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]));
|
||||
}
|
||||
|
||||
static void acpm_pmic_init_update_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
|
||||
|
|
@ -220,5 +235,5 @@ int acpm_pmic_update_reg(const struct acpm_handle *handle,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]);
|
||||
return acpm_pmic_to_linux_err(FIELD_GET(ACPM_PMIC_RETURN, xfer.rxd[1]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
|
@ -15,6 +17,7 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
|
|
@ -35,6 +38,15 @@ struct exynos_pmu_context {
|
|||
const struct exynos_pmu_data *pmu_data;
|
||||
struct regmap *pmureg;
|
||||
struct regmap *pmuintrgen;
|
||||
/*
|
||||
* Serialization lock for CPU hot plug and cpuidle ACPM hint
|
||||
* programming. Also protects in_cpuhp, sys_insuspend & sys_inreboot
|
||||
* flags.
|
||||
*/
|
||||
raw_spinlock_t cpupm_lock;
|
||||
unsigned long *in_cpuhp;
|
||||
bool sys_insuspend;
|
||||
bool sys_inreboot;
|
||||
};
|
||||
|
||||
void __iomem *pmu_base_addr;
|
||||
|
|
@ -221,6 +233,15 @@ static const struct regmap_config regmap_smccfg = {
|
|||
.reg_read = tensor_sec_reg_read,
|
||||
.reg_write = tensor_sec_reg_write,
|
||||
.reg_update_bits = tensor_sec_update_bits,
|
||||
.use_raw_spinlock = true,
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_pmu_intr = {
|
||||
.name = "pmu_intr_gen",
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.use_raw_spinlock = true,
|
||||
};
|
||||
|
||||
static const struct exynos_pmu_data gs101_pmu_data = {
|
||||
|
|
@ -330,13 +351,19 @@ struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np,
|
|||
EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
|
||||
|
||||
/*
|
||||
* CPU_INFORM register hint values which are used by
|
||||
* EL3 firmware (el3mon).
|
||||
* CPU_INFORM register "hint" values are required to be programmed in addition to
|
||||
* the standard PSCI calls to have functional CPU hotplug and CPU idle states.
|
||||
* This is required to workaround limitations in the el3mon/ACPM firmware.
|
||||
*/
|
||||
#define CPU_INFORM_CLEAR 0
|
||||
#define CPU_INFORM_C2 1
|
||||
|
||||
static int gs101_cpuhp_pmu_online(unsigned int cpu)
|
||||
/*
|
||||
* __gs101_cpu_pmu_ prefix functions are common code shared by CPU PM notifiers
|
||||
* (CPUIdle) and CPU hotplug callbacks. Functions should be called with IRQs
|
||||
* disabled and cpupm_lock held.
|
||||
*/
|
||||
static int __gs101_cpu_pmu_online(unsigned int cpu)
|
||||
{
|
||||
unsigned int cpuhint = smp_processor_id();
|
||||
u32 reg, mask;
|
||||
|
|
@ -358,10 +385,48 @@ static int gs101_cpuhp_pmu_online(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gs101_cpuhp_pmu_offline(unsigned int cpu)
|
||||
/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */
|
||||
static int gs101_cpu_pmu_online(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
raw_spin_lock(&pmu_context->cpupm_lock);
|
||||
|
||||
if (pmu_context->sys_inreboot) {
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
cpu = smp_processor_id();
|
||||
__gs101_cpu_pmu_online(cpu);
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/* Called from CPU hot plug callback with IRQs enabled */
|
||||
static int gs101_cpuhp_pmu_online(unsigned int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
|
||||
|
||||
__gs101_cpu_pmu_online(cpu);
|
||||
/*
|
||||
* Mark this CPU as having finished the hotplug.
|
||||
* This means this CPU can now enter C2 idle state.
|
||||
*/
|
||||
clear_bit(cpu, pmu_context->in_cpuhp);
|
||||
raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common function shared by both CPU hot plug and CPUIdle */
|
||||
static int __gs101_cpu_pmu_offline(unsigned int cpu)
|
||||
{
|
||||
u32 reg, mask;
|
||||
unsigned int cpuhint = smp_processor_id();
|
||||
u32 reg, mask;
|
||||
|
||||
/* set cpu inform hint */
|
||||
regmap_write(pmu_context->pmureg, GS101_CPU_INFORM(cpuhint),
|
||||
|
|
@ -379,6 +444,165 @@ static int gs101_cpuhp_pmu_offline(unsigned int cpu)
|
|||
regmap_read(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_UPEND, ®);
|
||||
regmap_write(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_CLEAR,
|
||||
reg & mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */
|
||||
static int gs101_cpu_pmu_offline(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
raw_spin_lock(&pmu_context->cpupm_lock);
|
||||
cpu = smp_processor_id();
|
||||
|
||||
if (test_bit(cpu, pmu_context->in_cpuhp)) {
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
return NOTIFY_BAD;
|
||||
}
|
||||
|
||||
/* Ignore CPU_PM_ENTER event in reboot or suspend sequence. */
|
||||
if (pmu_context->sys_insuspend || pmu_context->sys_inreboot) {
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
__gs101_cpu_pmu_offline(cpu);
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/* Called from CPU hot plug callback with IRQs enabled */
|
||||
static int gs101_cpuhp_pmu_offline(unsigned int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
|
||||
/*
|
||||
* Mark this CPU as entering hotplug. So as not to confuse
|
||||
* ACPM the CPU entering hotplug should not enter C2 idle state.
|
||||
*/
|
||||
set_bit(cpu, pmu_context->in_cpuhp);
|
||||
__gs101_cpu_pmu_offline(cpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gs101_cpu_pm_notify_callback(struct notifier_block *self,
|
||||
unsigned long action, void *v)
|
||||
{
|
||||
switch (action) {
|
||||
case CPU_PM_ENTER:
|
||||
return gs101_cpu_pmu_offline();
|
||||
|
||||
case CPU_PM_EXIT:
|
||||
return gs101_cpu_pmu_online();
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block gs101_cpu_pm_notifier = {
|
||||
.notifier_call = gs101_cpu_pm_notify_callback,
|
||||
/*
|
||||
* We want to be called first, as the ACPM hint and handshake is what
|
||||
* puts the CPU into C2.
|
||||
*/
|
||||
.priority = INT_MAX
|
||||
};
|
||||
|
||||
static int exynos_cpupm_reboot_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *v)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
switch (event) {
|
||||
case SYS_POWER_OFF:
|
||||
case SYS_RESTART:
|
||||
raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags);
|
||||
pmu_context->sys_inreboot = true;
|
||||
raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block exynos_cpupm_reboot_nb = {
|
||||
.priority = INT_MAX,
|
||||
.notifier_call = exynos_cpupm_reboot_notifier,
|
||||
};
|
||||
|
||||
static int setup_cpuhp_and_cpuidle(struct device *dev)
|
||||
{
|
||||
struct device_node *intr_gen_node;
|
||||
struct resource intrgen_res;
|
||||
void __iomem *virt_addr;
|
||||
int ret, cpu;
|
||||
|
||||
intr_gen_node = of_parse_phandle(dev->of_node,
|
||||
"google,pmu-intr-gen-syscon", 0);
|
||||
if (!intr_gen_node) {
|
||||
/*
|
||||
* To maintain support for older DTs that didn't specify syscon
|
||||
* phandle just issue a warning rather than fail to probe.
|
||||
*/
|
||||
dev_warn(dev, "pmu-intr-gen syscon unavailable\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid lockdep issues (CPU PM notifiers use raw spinlocks) create
|
||||
* a mmio regmap for pmu-intr-gen that uses raw spinlocks instead of
|
||||
* syscon provided regmap.
|
||||
*/
|
||||
ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res);
|
||||
of_node_put(intr_gen_node);
|
||||
|
||||
virt_addr = devm_ioremap(dev, intrgen_res.start,
|
||||
resource_size(&intrgen_res));
|
||||
if (!virt_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
pmu_context->pmuintrgen = devm_regmap_init_mmio(dev, virt_addr,
|
||||
®map_pmu_intr);
|
||||
if (IS_ERR(pmu_context->pmuintrgen)) {
|
||||
dev_err(dev, "failed to initialize pmu-intr-gen regmap\n");
|
||||
return PTR_ERR(pmu_context->pmuintrgen);
|
||||
}
|
||||
|
||||
/* register custom mmio regmap with syscon */
|
||||
ret = of_syscon_register_regmap(intr_gen_node,
|
||||
pmu_context->pmuintrgen);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pmu_context->in_cpuhp = devm_bitmap_zalloc(dev, num_possible_cpus(),
|
||||
GFP_KERNEL);
|
||||
if (!pmu_context->in_cpuhp)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_init(&pmu_context->cpupm_lock);
|
||||
pmu_context->sys_inreboot = false;
|
||||
pmu_context->sys_insuspend = false;
|
||||
|
||||
/* set PMU to power on */
|
||||
for_each_online_cpu(cpu)
|
||||
gs101_cpuhp_pmu_online(cpu);
|
||||
|
||||
/* register CPU hotplug callbacks */
|
||||
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare",
|
||||
gs101_cpuhp_pmu_online, NULL);
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
|
||||
NULL, gs101_cpuhp_pmu_offline);
|
||||
|
||||
/* register CPU PM notifiers for cpuidle */
|
||||
cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
|
||||
register_reboot_notifier(&exynos_cpupm_reboot_nb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -435,23 +659,9 @@ static int exynos_pmu_probe(struct platform_device *pdev)
|
|||
pmu_context->dev = dev;
|
||||
|
||||
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) {
|
||||
pmu_context->pmuintrgen = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"google,pmu-intr-gen-syscon");
|
||||
if (IS_ERR(pmu_context->pmuintrgen)) {
|
||||
/*
|
||||
* To maintain support for older DTs that didn't specify syscon phandle
|
||||
* just issue a warning rather than fail to probe.
|
||||
*/
|
||||
dev_warn(&pdev->dev, "pmu-intr-gen syscon unavailable\n");
|
||||
} else {
|
||||
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN,
|
||||
"soc/exynos-pmu:prepare",
|
||||
gs101_cpuhp_pmu_online, NULL);
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
|
||||
"soc/exynos-pmu:online",
|
||||
NULL, gs101_cpuhp_pmu_offline);
|
||||
}
|
||||
ret = setup_cpuhp_and_cpuidle(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init)
|
||||
|
|
@ -471,10 +681,32 @@ static int exynos_pmu_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_cpupm_suspend_noirq(struct device *dev)
|
||||
{
|
||||
raw_spin_lock(&pmu_context->cpupm_lock);
|
||||
pmu_context->sys_insuspend = true;
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_cpupm_resume_noirq(struct device *dev)
|
||||
{
|
||||
raw_spin_lock(&pmu_context->cpupm_lock);
|
||||
pmu_context->sys_insuspend = false;
|
||||
raw_spin_unlock(&pmu_context->cpupm_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops cpupm_pm_ops = {
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_cpupm_suspend_noirq,
|
||||
exynos_cpupm_resume_noirq)
|
||||
};
|
||||
|
||||
static struct platform_driver exynos_pmu_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-pmu",
|
||||
.of_match_table = exynos_pmu_of_device_ids,
|
||||
.pm = pm_sleep_ptr(&cpupm_pm_ops),
|
||||
},
|
||||
.probe = exynos_pmu_probe,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue