2 * Copyright (c) 2015, Sony Mobile Communications Inc.
3 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 #include <linux/device.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
18 #include <linux/slab.h>
19 #include <linux/soc/qcom/smem_state.h>
21 static LIST_HEAD(smem_states
);
22 static DEFINE_MUTEX(list_lock
);
25 * struct qcom_smem_state - state context
26 * @refcount: refcount for the state
27 * @orphan: boolean indicator that this state has been unregistered
28 * @list: entry in smem_states list
29 * @of_node: of_node to use for matching the state in DT
30 * @priv: implementation private data
31 * @ops: ops for the state
33 struct qcom_smem_state
{
37 struct list_head list
;
38 struct device_node
*of_node
;
42 struct qcom_smem_state_ops ops
;
46 * qcom_smem_state_update_bits() - update the masked bits in state with value
47 * @state: state handle acquired by calling qcom_smem_state_get()
48 * @mask: bit mask for the change
49 * @value: new value for the masked bits
51 * Returns 0 on success, otherwise negative errno.
53 int qcom_smem_state_update_bits(struct qcom_smem_state
*state
,
60 if (!state
->ops
.update_bits
)
63 return state
->ops
.update_bits(state
->priv
, mask
, value
);
65 EXPORT_SYMBOL_GPL(qcom_smem_state_update_bits
);
67 static struct qcom_smem_state
*of_node_to_state(struct device_node
*np
)
69 struct qcom_smem_state
*state
;
71 mutex_lock(&list_lock
);
73 list_for_each_entry(state
, &smem_states
, list
) {
74 if (state
->of_node
== np
) {
75 kref_get(&state
->refcount
);
79 state
= ERR_PTR(-EPROBE_DEFER
);
82 mutex_unlock(&list_lock
);
88 * qcom_smem_state_get() - acquire handle to a state
89 * @dev: client device pointer
90 * @con_id: name of the state to lookup
91 * @bit: flags from the state reference, indicating which bit's affected
93 * Returns handle to the state, or ERR_PTR(). qcom_smem_state_put() must be
94 * called to release the returned state handle.
96 struct qcom_smem_state
*qcom_smem_state_get(struct device
*dev
,
100 struct qcom_smem_state
*state
;
101 struct of_phandle_args args
;
106 index
= of_property_match_string(dev
->of_node
,
107 "qcom,smem-state-names",
110 dev_err(dev
, "missing qcom,smem-state-names\n");
111 return ERR_PTR(index
);
115 ret
= of_parse_phandle_with_args(dev
->of_node
,
117 "#qcom,smem-state-cells",
121 dev_err(dev
, "failed to parse qcom,smem-states property\n");
125 if (args
.args_count
!= 1) {
126 dev_err(dev
, "invalid #qcom,smem-state-cells\n");
127 return ERR_PTR(-EINVAL
);
130 state
= of_node_to_state(args
.np
);
137 of_node_put(args
.np
);
140 EXPORT_SYMBOL_GPL(qcom_smem_state_get
);
142 static void qcom_smem_state_release(struct kref
*ref
)
144 struct qcom_smem_state
*state
= container_of(ref
, struct qcom_smem_state
, refcount
);
146 list_del(&state
->list
);
151 * qcom_smem_state_put() - release state handle
152 * @state: state handle to be released
154 void qcom_smem_state_put(struct qcom_smem_state
*state
)
156 mutex_lock(&list_lock
);
157 kref_put(&state
->refcount
, qcom_smem_state_release
);
158 mutex_unlock(&list_lock
);
160 EXPORT_SYMBOL_GPL(qcom_smem_state_put
);
163 * qcom_smem_state_register() - register a new state
164 * @of_node: of_node used for matching client lookups
165 * @ops: implementation ops
166 * @priv: implementation specific private data
168 struct qcom_smem_state
*qcom_smem_state_register(struct device_node
*of_node
,
169 const struct qcom_smem_state_ops
*ops
,
172 struct qcom_smem_state
*state
;
174 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
176 return ERR_PTR(-ENOMEM
);
178 kref_init(&state
->refcount
);
180 state
->of_node
= of_node
;
184 mutex_lock(&list_lock
);
185 list_add(&state
->list
, &smem_states
);
186 mutex_unlock(&list_lock
);
190 EXPORT_SYMBOL_GPL(qcom_smem_state_register
);
193 * qcom_smem_state_unregister() - unregister a registered state
194 * @state: state handle to be unregistered
196 void qcom_smem_state_unregister(struct qcom_smem_state
*state
)
198 state
->orphan
= true;
199 qcom_smem_state_put(state
);
201 EXPORT_SYMBOL_GPL(qcom_smem_state_unregister
);