1 From bf20be14fc1b3f7e096bdac9c5ff67362b391479 Mon Sep 17 00:00:00 2001
2 From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
3 Date: Thu, 18 May 2017 17:46:24 +0900
4 Subject: [PATCH 12/15] Add rcar-gpio hibernation code
6 Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
8 drivers/pinctrl/sh-pfc/core.c | 141 +++++++++++++++++++++++++++++++++++++++---
9 drivers/pinctrl/sh-pfc/core.h | 4 ++
10 2 files changed, 138 insertions(+), 7 deletions(-)
12 diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
13 index b9e025d..c37418e 100644
14 --- a/drivers/pinctrl/sh-pfc/core.c
15 +++ b/drivers/pinctrl/sh-pfc/core.c
17 #include <linux/pinctrl/machine.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20 +#include <linux/cpu_pm.h>
24 @@ -201,19 +202,117 @@ static void sh_pfc_config_reg_helper(struct sh_pfc *pfc,
31 + unsigned long width;
37 + struct reg_record unlock_reg;
38 + struct reg_record actual_reg;
39 + struct list_head list;
42 +static struct reg_config *regs_list;
49 +static int sh_pfc_cpu_pm_notify(struct notifier_block *self,
50 + unsigned long action, void *hcpu)
52 + struct reg_config *tmp = NULL;
53 + struct sh_pfc *pfc = container_of(self, struct sh_pfc, pm_notify);
54 + /* We don't setup pinmux in kernel - store all registers */
55 + struct reg_range ranges[] = {
56 + {0x0, 0x5c}, {0x160, 0x160}, {0x90, 0x98},
57 + {0x100, 0x118}, {0x70, 0x70}, {0x60, 0x64},
58 + {0x84, 0x8c}, {0x240, 0x248},
61 + if (action == CPU_PM_ENTER) {
63 + /* No pinmux configuration, storing all registers */
66 + for (i = 0; i < ARRAY_SIZE(ranges); i++) {
68 + for (j = ranges[i].start; j <= ranges[i].end; j += sizeof(u32)) {
69 + pfc->stored_regs[store_cnt] =
70 + sh_pfc_read_raw_reg(sh_pfc_phys_to_virt(pfc, 0xe6060000 + j), 32);
71 + pr_debug("PFC: %08x => %08x\n", 0xe6060000 + j, pfc->stored_regs[store_cnt]);
73 + if (store_cnt >= ARRAY_SIZE(pfc->stored_regs)) {
74 + pr_err("read: Register store overflow\n");
80 + } else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) {
82 + /* No list, restoring all registers */
85 + for (i = 0; i < ARRAY_SIZE(ranges); i++) {
87 + for (j = ranges[i].start; j <= ranges[i].end; j += sizeof(u32)) {
88 + sh_pfc_write_raw_reg(sh_pfc_phys_to_virt(pfc, 0xe6060000 + j), 32,
89 + pfc->stored_regs[store_cnt]);
90 + pr_debug("PFC: %08x => %08x\n", 0xe6060000 + j, pfc->stored_regs[store_cnt]);
92 + if (store_cnt >= ARRAY_SIZE(pfc->stored_regs)) {
93 + pr_err("write: Register store overflow\n");
100 + list_for_each_entry(tmp , &(regs_list->list), list) {
102 + sh_pfc_write_raw_reg(tmp->unlock_reg.reg,
103 + tmp->unlock_reg.width,
104 + tmp->unlock_reg.data);
105 + sh_pfc_write_raw_reg(tmp->actual_reg.reg,
106 + tmp->actual_reg.width,
107 + tmp->actual_reg.data);
114 +static int __init sh_pfc_cpu_pm_init(struct sh_pfc *pfc)
116 + memset(&pfc->pm_notify, 0, sizeof(pfc->pm_notify));
117 + pfc->pm_notify.notifier_call = sh_pfc_cpu_pm_notify;
118 + return cpu_pm_register_notifier(&pfc->pm_notify);
121 +static int __init sh_pfc_cpu_pm_init(struct sh_pfc *pfc)
128 static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
129 const struct pinmux_cfg_reg *crp,
130 unsigned long field, unsigned long value)
132 void __iomem *mapped_reg;
133 unsigned long mask, pos, data;
135 +#ifdef CONFIG_CPU_PM
136 + struct reg_config *tmp;
138 sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos);
140 - dev_dbg(pfc->dev, "write_reg addr = %lx, value = %ld, field = %ld, "
141 - "r_width = %ld, f_width = %ld\n",
142 - crp->reg, value, field, crp->reg_width, crp->field_width);
144 mask = ~(mask << pos);
145 value = value << pos;
147 @@ -221,14 +320,39 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc,
151 - if (pfc->info->unlock_reg)
152 +#ifdef CONFIG_CPU_PM
153 + tmp = kzalloc(sizeof(struct reg_config), GFP_KERNEL);
158 + INIT_LIST_HEAD(®s_list->list);
162 + if (pfc->info->unlock_reg) {
163 +#ifdef CONFIG_CPU_PM
164 + tmp->unlock = true;
165 + tmp->unlock_reg.reg = sh_pfc_phys_to_virt(pfc,
166 + pfc->info->unlock_reg);
167 + tmp->unlock_reg.width = 32;
168 + tmp->unlock_reg.data = ~data;
170 sh_pfc_write_raw_reg(
171 sh_pfc_phys_to_virt(pfc, pfc->info->unlock_reg), 32,
175 +#ifdef CONFIG_CPU_PM
176 + tmp->actual_reg.reg = mapped_reg;
177 + tmp->actual_reg.width = crp->reg_width;
178 + tmp->actual_reg.data = data;
180 + list_add(&tmp->list, ®s_list->list);
183 sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
186 static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
187 const struct pinmux_cfg_reg **crp, int *fieldp,
189 @@ -574,6 +698,8 @@ static int sh_pfc_probe(struct platform_device *pdev)
191 platform_set_drvdata(pdev, pfc);
193 + sh_pfc_cpu_pm_init(pfc);
195 dev_info(pfc->dev, "%s support registered\n", info->name);
198 @@ -596,6 +722,7 @@ static int sh_pfc_remove(struct platform_device *pdev)
199 if (pfc->info->ops && pfc->info->ops->exit)
200 pfc->info->ops->exit(pfc);
206 diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
207 index 75ecb67..5471a6c 100644
208 --- a/drivers/pinctrl/sh-pfc/core.h
209 +++ b/drivers/pinctrl/sh-pfc/core.h
211 #include <linux/compiler.h>
212 #include <linux/spinlock.h>
213 #include <linux/types.h>
214 +#include <linux/notifier.h>
218 @@ -51,6 +52,9 @@ struct sh_pfc {
219 struct sh_pfc_chip *func;
221 struct sh_pfc_pinctrl *pinctrl;
222 + struct notifier_block pm_notify;
223 +#define STORE_REGS_COUNT 50
224 + u32 stored_regs[STORE_REGS_COUNT];
227 int sh_pfc_register_gpiochip(struct sh_pfc *pfc);