]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/soc/samsung/exynos-srom.c
Merge remote-tracking branch 'samsung/for-next'
[karo-tx-linux.git] / drivers / soc / samsung / exynos-srom.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *            http://www.samsung.com/
4  *
5  * EXYNOS - SROM Controller support
6  * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/io.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19
20 #include "exynos-srom.h"
21
22 static const unsigned long exynos_srom_offsets[] = {
23         /* SROM side */
24         EXYNOS_SROM_BW,
25         EXYNOS_SROM_BC0,
26         EXYNOS_SROM_BC1,
27         EXYNOS_SROM_BC2,
28         EXYNOS_SROM_BC3,
29 };
30
31 /**
32  * struct exynos_srom_reg_dump: register dump of SROM Controller registers.
33  * @offset: srom register offset from the controller base address.
34  * @value: the value of register under the offset.
35  */
36 struct exynos_srom_reg_dump {
37         u32     offset;
38         u32     value;
39 };
40
41 /**
42  * struct exynos_srom: platform data for exynos srom controller driver.
43  * @dev: platform device pointer
44  * @reg_base: srom base address
45  * @reg_offset: exynos_srom_reg_dump pointer to hold offset and its value.
46  */
47 struct exynos_srom {
48         struct device *dev;
49         void __iomem *reg_base;
50         struct exynos_srom_reg_dump *reg_offset;
51 };
52
53 static struct exynos_srom_reg_dump *exynos_srom_alloc_reg_dump(
54                 const unsigned long *rdump,
55                 unsigned long nr_rdump)
56 {
57         struct exynos_srom_reg_dump *rd;
58         unsigned int i;
59
60         rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
61         if (!rd)
62                 return NULL;
63
64         for (i = 0; i < nr_rdump; ++i)
65                 rd[i].offset = rdump[i];
66
67         return rd;
68 }
69
70 static int exynos_srom_probe(struct platform_device *pdev)
71 {
72         struct device_node *np;
73         struct exynos_srom *srom;
74         struct device *dev = &pdev->dev;
75
76         np = dev->of_node;
77         if (!np) {
78                 dev_err(&pdev->dev, "could not find device info\n");
79                 return -EINVAL;
80         }
81
82         srom = devm_kzalloc(&pdev->dev,
83                         sizeof(struct exynos_srom), GFP_KERNEL);
84         if (!srom)
85                 return -ENOMEM;
86
87         srom->dev = dev;
88         srom->reg_base = of_iomap(np, 0);
89         if (!srom->reg_base) {
90                 dev_err(&pdev->dev, "iomap of exynos srom controller failed\n");
91                 return -ENOMEM;
92         }
93
94         platform_set_drvdata(pdev, srom);
95
96         srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets,
97                         sizeof(exynos_srom_offsets));
98         if (!srom->reg_offset) {
99                 iounmap(srom->reg_base);
100                 return -ENOMEM;
101         }
102
103         return 0;
104 }
105
106 static int exynos_srom_remove(struct platform_device *pdev)
107 {
108         struct exynos_srom *srom = platform_get_drvdata(pdev);
109
110         kfree(srom->reg_offset);
111         iounmap(srom->reg_base);
112
113         return 0;
114 }
115
116 #ifdef CONFIG_PM_SLEEP
117 static void exynos_srom_save(void __iomem *base,
118                                     struct exynos_srom_reg_dump *rd,
119                                     unsigned int num_regs)
120 {
121         for (; num_regs > 0; --num_regs, ++rd)
122                 rd->value = readl(base + rd->offset);
123 }
124
125 static void exynos_srom_restore(void __iomem *base,
126                                       const struct exynos_srom_reg_dump *rd,
127                                       unsigned int num_regs)
128 {
129         for (; num_regs > 0; --num_regs, ++rd)
130                 writel(rd->value, base + rd->offset);
131 }
132
133 static int exynos_srom_suspend(struct device *dev)
134 {
135         struct exynos_srom *srom = dev_get_drvdata(dev);
136
137         exynos_srom_save(srom->reg_base, srom->reg_offset,
138                                 ARRAY_SIZE(exynos_srom_offsets));
139         return 0;
140 }
141
142 static int exynos_srom_resume(struct device *dev)
143 {
144         struct exynos_srom *srom = dev_get_drvdata(dev);
145
146         exynos_srom_restore(srom->reg_base, srom->reg_offset,
147                                 ARRAY_SIZE(exynos_srom_offsets));
148         return 0;
149 }
150 #endif
151
152 static const struct of_device_id of_exynos_srom_ids[] = {
153         {
154                 .compatible     = "samsung,exynos-srom",
155         },
156         {},
157 };
158 MODULE_DEVICE_TABLE(of, of_exynos_srom_ids);
159
160 static SIMPLE_DEV_PM_OPS(exynos_srom_pm_ops, exynos_srom_suspend, exynos_srom_resume);
161
162 static struct platform_driver exynos_srom_driver = {
163         .probe = exynos_srom_probe,
164         .remove = exynos_srom_remove,
165         .driver = {
166                 .name = "exynos-srom",
167                 .of_match_table = of_exynos_srom_ids,
168                 .pm = &exynos_srom_pm_ops,
169         },
170 };
171 module_platform_driver(exynos_srom_driver);
172
173 MODULE_AUTHOR("Pankaj Dubey <pankaj.dubey@samsung.com>");
174 MODULE_DESCRIPTION("Exynos SROM Controller Driver");
175 MODULE_LICENSE("GPL");