Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / soc / versatile / soc-integrator.c
1 /*
2  * Copyright (C) 2014 Linaro Ltd.
3  *
4  * Author: Linus Walleij <linus.walleij@linaro.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2, as
8  * published by the Free Software Foundation.
9  *
10  */
11 #include <linux/init.h>
12 #include <linux/io.h>
13 #include <linux/slab.h>
14 #include <linux/sys_soc.h>
15 #include <linux/platform_device.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/regmap.h>
18 #include <linux/of.h>
19
20 #define INTEGRATOR_HDR_ID_OFFSET        0x00
21
22 static u32 integrator_coreid;
23
24 static const struct of_device_id integrator_cm_match[] = {
25         { .compatible = "arm,core-module-integrator", },
26         { }
27 };
28
29 static const char *integrator_arch_str(u32 id)
30 {
31         switch ((id >> 16) & 0xff) {
32         case 0x00:
33                 return "ASB little-endian";
34         case 0x01:
35                 return "AHB little-endian";
36         case 0x03:
37                 return "AHB-Lite system bus, bi-endian";
38         case 0x04:
39                 return "AHB";
40         case 0x08:
41                 return "AHB system bus, ASB processor bus";
42         default:
43                 return "Unknown";
44         }
45 }
46
47 static const char *integrator_fpga_str(u32 id)
48 {
49         switch ((id >> 12) & 0xf) {
50         case 0x01:
51                 return "XC4062";
52         case 0x02:
53                 return "XC4085";
54         case 0x03:
55                 return "XVC600";
56         case 0x04:
57                 return "EPM7256AE (Altera PLD)";
58         default:
59                 return "Unknown";
60         }
61 }
62
63 static ssize_t integrator_get_manf(struct device *dev,
64                               struct device_attribute *attr,
65                               char *buf)
66 {
67         return sprintf(buf, "%02x\n", integrator_coreid >> 24);
68 }
69
70 static struct device_attribute integrator_manf_attr =
71         __ATTR(manufacturer,  S_IRUGO, integrator_get_manf,  NULL);
72
73 static ssize_t integrator_get_arch(struct device *dev,
74                               struct device_attribute *attr,
75                               char *buf)
76 {
77         return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid));
78 }
79
80 static struct device_attribute integrator_arch_attr =
81         __ATTR(arch,  S_IRUGO, integrator_get_arch,  NULL);
82
83 static ssize_t integrator_get_fpga(struct device *dev,
84                               struct device_attribute *attr,
85                               char *buf)
86 {
87         return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid));
88 }
89
90 static struct device_attribute integrator_fpga_attr =
91         __ATTR(fpga,  S_IRUGO, integrator_get_fpga,  NULL);
92
93 static ssize_t integrator_get_build(struct device *dev,
94                                struct device_attribute *attr,
95                                char *buf)
96 {
97         return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF);
98 }
99
100 static struct device_attribute integrator_build_attr =
101         __ATTR(build,  S_IRUGO, integrator_get_build,  NULL);
102
103 static int __init integrator_soc_init(void)
104 {
105         static struct regmap *syscon_regmap;
106         struct soc_device *soc_dev;
107         struct soc_device_attribute *soc_dev_attr;
108         struct device_node *np;
109         struct device *dev;
110         u32 val;
111         int ret;
112
113         np = of_find_matching_node(NULL, integrator_cm_match);
114         if (!np)
115                 return -ENODEV;
116
117         syscon_regmap = syscon_node_to_regmap(np);
118         if (IS_ERR(syscon_regmap))
119                 return PTR_ERR(syscon_regmap);
120
121         ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET,
122                           &val);
123         if (ret)
124                 return -ENODEV;
125         integrator_coreid = val;
126
127         soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
128         if (!soc_dev_attr)
129                 return -ENOMEM;
130
131         soc_dev_attr->soc_id = "Integrator";
132         soc_dev_attr->machine = "Integrator";
133         soc_dev_attr->family = "Versatile";
134         soc_dev = soc_device_register(soc_dev_attr);
135         if (IS_ERR(soc_dev)) {
136                 kfree(soc_dev_attr);
137                 return -ENODEV;
138         }
139         dev = soc_device_to_device(soc_dev);
140
141         device_create_file(dev, &integrator_manf_attr);
142         device_create_file(dev, &integrator_arch_attr);
143         device_create_file(dev, &integrator_fpga_attr);
144         device_create_file(dev, &integrator_build_attr);
145
146         dev_info(dev, "Detected ARM core module:\n");
147         dev_info(dev, "    Manufacturer: %02x\n", (val >> 24));
148         dev_info(dev, "    Architecture: %s\n", integrator_arch_str(val));
149         dev_info(dev, "    FPGA: %s\n", integrator_fpga_str(val));
150         dev_info(dev, "    Build: %02x\n", (val >> 4) & 0xFF);
151         dev_info(dev, "    Rev: %c\n", ('A' + (val & 0x03)));
152
153         return 0;
154 }
155 device_initcall(integrator_soc_init);