1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
// SPDX-License-Identifier: GPL-2.0
/*
* GXP wakelock support
*
* Copyright (C) 2022 Google LLC
*/
#include "gxp-dma.h"
#include "gxp-pm.h"
#include "gxp-wakelock.h"
int gxp_wakelock_init(struct gxp_dev *gxp)
{
struct gxp_wakelock_manager *mgr;
mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL);
if (!mgr)
return -ENOMEM;
mutex_init(&mgr->lock);
gxp->wakelock_mgr = mgr;
return 0;
}
int gxp_wakelock_acquire(struct gxp_dev *gxp)
{
struct gxp_wakelock_manager *mgr = gxp->wakelock_mgr;
int ret = 0;
mutex_lock(&mgr->lock);
if (mgr->suspended) {
/*
* Don't allow a new client to obtain a wakelock, powering up
* BLK_AUR, when the system is going to sleep.
*/
dev_warn(gxp->dev,
"Attempt to obtain wakelock while suspending.\n");
ret = -EAGAIN;
goto out;
}
if (!mgr->count++) {
ret = gxp_pm_blk_on(gxp);
if (ret) {
dev_err(gxp->dev,
"Failed to power on BLK_AUR (ret=%d, client count=%u)\n",
ret, mgr->count);
goto err_blk_on;
}
ret = gxp_dma_ssmt_program(gxp);
if (ret) {
dev_err(gxp->dev,
"Failed to program SSMTs after powering on BLK_AUR (ret=%d)\n",
ret);
goto err_ssmt_program;
}
}
out:
mutex_unlock(&mgr->lock);
return ret;
err_ssmt_program:
gxp_pm_blk_off(gxp);
err_blk_on:
mgr->count--;
mutex_unlock(&mgr->lock);
return ret;
}
void gxp_wakelock_release(struct gxp_dev *gxp)
{
struct gxp_wakelock_manager *mgr = gxp->wakelock_mgr;
int ret = 0;
mutex_lock(&mgr->lock);
if (!mgr->count) {
dev_err(gxp->dev,
"Attempt to release wakelock with none held.\n");
goto out;
}
if (!--mgr->count) {
ret = gxp_pm_blk_off(gxp);
if (ret)
dev_err(gxp->dev,
"Failed to power down BLK_AUR (ret=%d, client count=%u)\n",
ret, mgr->count);
}
out:
mutex_unlock(&mgr->lock);
}
int gxp_wakelock_suspend(struct gxp_dev *gxp)
{
struct gxp_wakelock_manager *mgr = gxp->wakelock_mgr;
int ret;
mutex_lock(&mgr->lock);
/* Can't suspend if there are any active clients */
mgr->suspended = mgr->count == 0;
ret = mgr->suspended ? 0 : -EAGAIN;
mutex_unlock(&mgr->lock);
return ret;
}
int gxp_wakelock_resume(struct gxp_dev *gxp)
{
struct gxp_wakelock_manager *mgr = gxp->wakelock_mgr;
mutex_lock(&mgr->lock);
mgr->suspended = false;
mutex_unlock(&mgr->lock);
return 0;
}
|