2 * Copyright (c) 2014, Sony Mobile Communications AB.
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.
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/of_platform.h>
19 #include <linux/interrupt.h>
20 #include <linux/memblock.h>
21 #include <linux/slab.h>
22 #include <linux/of_address.h>
23 #include <linux/of_irq.h>
24 #include <linux/hwspinlock.h>
25 #include <linux/regmap.h>
26 #include <linux/gpio.h>
27 #include <linux/mfd/syscon.h>
29 #include <linux/delay.h>
31 #include <linux/soc/qcom/smem.h>
33 #define SMSM_APPS_STATE 0
34 #define SMEM_SMSM_SHARED_STATE 85
36 #define SMSM_MAX_STATES 8
38 struct qcom_smsm_state {
40 struct gpio_chip chip;
44 struct regmap *ipc_regmap;
53 size_t shared_state_size;
55 struct qcom_smsm_state states[SMSM_MAX_STATES];
59 int qcom_smsm_change_state(struct qcom_smsm *smsm, u32 clear_mask, u32 set_mask)
63 dev_dbg(smsm->dev, "SMSM_APPS_STATE clear 0x%x set 0x%x\n", clear_mask, set_mask);
64 print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
66 state = readl(&smsm->shared_state[SMSM_APPS_STATE]);
69 writel(state, &smsm->shared_state[SMSM_APPS_STATE]);
71 print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
73 // qcom_smem_signal(-1, smsm->smem, smsm->signal_offset, smsm->signal_bit);
77 EXPORT_SYMBOL(qcom_smsm_change_state);
80 static struct qcom_smsm_state *to_smsm_state(struct gpio_chip *chip)
82 return container_of(chip, struct qcom_smsm_state, chip);
85 static struct qcom_smsm *to_smsm(struct qcom_smsm_state *state)
87 return container_of(state, struct qcom_smsm, states[state->state_id]);
90 static int smsm_gpio_direction_input(struct gpio_chip *chip,
93 struct qcom_smsm_state *state = to_smsm_state(chip);
95 if (state->state_id == SMSM_APPS_STATE)
100 static int smsm_gpio_direction_output(struct gpio_chip *chip,
104 struct qcom_smsm_state *ipc_state;
105 struct qcom_smsm_state *state = to_smsm_state(chip);
106 struct qcom_smsm *smsm = to_smsm(state);
112 /* Only SMSM_APPS_STATE supports writing */
113 if (state->state_id != SMSM_APPS_STATE)
116 offset += state->state_id * 32;
118 word = ALIGN(offset / 32, 4);
121 val = readl(smsm->shared_state + word);
126 writel(val, smsm->shared_state + word);
128 /* XXX: send out interrupts */
129 for (i = 0; i < SMSM_MAX_STATES; i++) {
130 ipc_state = &smsm->states[i];
131 if (!ipc_state->ipc_regmap)
134 regmap_write(ipc_state->ipc_regmap, ipc_state->ipc_offset, BIT(ipc_state->ipc_bit));
137 dev_err(smsm->dev, "set %d %d\n", offset, value);
142 static int smsm_gpio_get(struct gpio_chip *chip, unsigned offset)
144 struct qcom_smsm_state *state = to_smsm_state(chip);
145 struct qcom_smsm *smsm = to_smsm(state);
150 offset += state->state_id * 32;
152 word = ALIGN(offset / 32, 4);
155 val = readl(smsm->shared_state + word);
157 return !!(val & BIT(bit));
160 static void smsm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
162 smsm_gpio_direction_output(chip, offset, value);
165 static int smsm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
170 #ifdef CONFIG_DEBUG_FS
171 #include <linux/seq_file.h>
173 static void smsm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
175 struct qcom_smsm_state *state = to_smsm_state(chip);
176 struct qcom_smsm *smsm = to_smsm(state);
180 val = readl(smsm->shared_state + state->state_id * 4);
182 for (i = 0; i < 32; i++) {
188 if (i == 7 || i == 15 || i == 23)
195 #define smsm_gpio_dbg_show NULL
198 static struct gpio_chip smsm_gpio_template = {
199 .direction_input = smsm_gpio_direction_input,
200 .direction_output = smsm_gpio_direction_output,
201 .get = smsm_gpio_get,
202 .set = smsm_gpio_set,
203 .to_irq = smsm_gpio_to_irq,
204 .dbg_show = smsm_gpio_dbg_show,
205 .owner = THIS_MODULE,
208 static int qcom_smsm_probe(struct platform_device *pdev)
210 struct qcom_smsm_state *state;
211 struct device_node *syscon_np;
212 struct device_node *node;
213 struct qcom_smsm *smsm;
218 smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL);
221 smsm->dev = &pdev->dev;
223 ret = qcom_smem_alloc(-1, SMEM_SMSM_SHARED_STATE, 8 * sizeof(uint32_t));
224 if (ret < 0 && ret != -EEXIST) {
225 dev_err(&pdev->dev, "unable to allocate shared state entry\n");
229 smsm->shared_state = qcom_smem_get(-1, SMEM_SMSM_SHARED_STATE,
230 &smsm->shared_state_size);
231 if (IS_ERR(smsm->shared_state)) {
232 dev_err(&pdev->dev, "Unable to acquire shared state entry\n");
233 return PTR_ERR(smsm->shared_state);
236 dev_err(smsm->dev, "SMEM_SMSM_SHARED_STATE: %d, %zu\n", ret, smsm->shared_state_size);
237 print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
239 for_each_child_of_node(pdev->dev.of_node, node) {
241 ret = of_property_read_u32(node, key, &sid);
242 if (ret || sid >= SMSM_MAX_STATES) {
243 dev_err(&pdev->dev, "smsm state missing %s\n", key);
246 state = &smsm->states[sid];
247 state->state_id = sid;
249 state->chip = smsm_gpio_template;
250 state->chip.base = -1;
251 state->chip.dev = &pdev->dev;
252 state->chip.of_node = node;
253 state->chip.label = node->name;
254 state->chip.ngpio = 8 * sizeof(u32);
255 ret = gpiochip_add(&state->chip);
257 dev_err(&pdev->dev, "failed register gpiochip\n");
261 /* The remaining properties are only for non-apps state */
262 if (sid == SMSM_APPS_STATE)
265 state->irq = irq_of_parse_and_map(node, 0);
266 if (state->irq < 0 && state->irq != -EINVAL) {
267 dev_err(&pdev->dev, "failed to parse smsm interrupt\n");
271 syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
273 dev_err(&pdev->dev, "no qcom,ipc node\n");
277 state->ipc_regmap = syscon_node_to_regmap(syscon_np);
278 if (IS_ERR(state->ipc_regmap))
279 return PTR_ERR(state->ipc_regmap);
282 ret = of_property_read_u32_index(node, key, 1, &state->ipc_offset);
284 dev_err(&pdev->dev, "no offset in %s\n", key);
288 ret = of_property_read_u32_index(node, key, 2, &state->ipc_bit);
290 dev_err(&pdev->dev, "no bit in %s\n", key);
299 static const struct of_device_id qcom_smsm_of_match[] = {
300 { .compatible = "qcom,smsm" },
303 MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
305 static struct platform_driver qcom_smsm_driver = {
306 .probe = qcom_smsm_probe,
309 .owner = THIS_MODULE,
310 .of_match_table = qcom_smsm_of_match,
314 static int __init qcom_smsm_init(void)
316 return platform_driver_register(&qcom_smsm_driver);
318 arch_initcall(qcom_smsm_init);
320 static void __exit qcom_smsm_exit(void)
322 platform_driver_unregister(&qcom_smsm_driver);
324 module_exit(qcom_smsm_exit)
326 MODULE_DESCRIPTION("Qualcomm Shared Memory Signaling Mechanism");
327 MODULE_LICENSE("GPLv2");