staging: board: Remove calls to of_genpd_get_from_provider()
[cascardo/linux.git] / drivers / staging / board / board.c
1 /*
2  * Copyright (C) 2014 Magnus Damm
3  * Copyright (C) 2015 Glider bvba
4  *
5  * This file is subject to the terms and conditions of the GNU General Public
6  * License.  See the file "COPYING" in the main directory of this archive
7  * for more details.
8  */
9
10 #define pr_fmt(fmt)     "board_staging: "  fmt
11
12 #include <linux/clkdev.h>
13 #include <linux/init.h>
14 #include <linux/irq.h>
15 #include <linux/device.h>
16 #include <linux/kernel.h>
17 #include <linux/of.h>
18 #include <linux/of_address.h>
19 #include <linux/of_irq.h>
20 #include <linux/platform_device.h>
21 #include <linux/pm_domain.h>
22
23 #include "board.h"
24
25 static struct device_node *irqc_node __initdata;
26 static unsigned int irqc_base __initdata;
27
28 static bool find_by_address(u64 base_address)
29 {
30         struct device_node *dn = of_find_all_nodes(NULL);
31         struct resource res;
32
33         while (dn) {
34                 if (!of_address_to_resource(dn, 0, &res)) {
35                         if (res.start == base_address) {
36                                 of_node_put(dn);
37                                 return true;
38                         }
39                 }
40                 dn = of_find_all_nodes(dn);
41         }
42
43         return false;
44 }
45
46 bool __init board_staging_dt_node_available(const struct resource *resource,
47                                             unsigned int num_resources)
48 {
49         unsigned int i;
50
51         for (i = 0; i < num_resources; i++) {
52                 const struct resource *r = resource + i;
53
54                 if (resource_type(r) == IORESOURCE_MEM)
55                         if (find_by_address(r->start))
56                                 return true; /* DT node available */
57         }
58
59         return false; /* Nothing found */
60 }
61
62 int __init board_staging_gic_setup_xlate(const char *gic_match,
63                                          unsigned int base)
64 {
65         WARN_ON(irqc_node);
66
67         irqc_node = of_find_compatible_node(NULL, NULL, gic_match);
68
69         WARN_ON(!irqc_node);
70         if (!irqc_node)
71                 return -ENOENT;
72
73         irqc_base = base;
74         return 0;
75 }
76
77 static void __init gic_fixup_resource(struct resource *res)
78 {
79         struct of_phandle_args irq_data;
80         unsigned int hwirq = res->start;
81         unsigned int virq;
82
83         if (resource_type(res) != IORESOURCE_IRQ || !irqc_node)
84                 return;
85
86         irq_data.np = irqc_node;
87         irq_data.args_count = 3;
88         irq_data.args[0] = 0;
89         irq_data.args[1] = hwirq - irqc_base;
90         switch (res->flags &
91                 (IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE |
92                  IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL)) {
93         case IORESOURCE_IRQ_LOWEDGE:
94                 irq_data.args[2] = IRQ_TYPE_EDGE_FALLING;
95                 break;
96         case IORESOURCE_IRQ_HIGHEDGE:
97                 irq_data.args[2] = IRQ_TYPE_EDGE_RISING;
98                 break;
99         case IORESOURCE_IRQ_LOWLEVEL:
100                 irq_data.args[2] = IRQ_TYPE_LEVEL_LOW;
101                 break;
102         case IORESOURCE_IRQ_HIGHLEVEL:
103         default:
104                 irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH;
105                 break;
106         }
107
108         virq = irq_create_of_mapping(&irq_data);
109         if (WARN_ON(!virq))
110                 return;
111
112         pr_debug("hwirq %u -> virq %u\n", hwirq, virq);
113         res->start = virq;
114 }
115
116 void __init board_staging_gic_fixup_resources(struct resource *res,
117                                               unsigned int nres)
118 {
119         unsigned int i;
120
121         for (i = 0; i < nres; i++)
122                 gic_fixup_resource(&res[i]);
123 }
124
125 int __init board_staging_register_clock(const struct board_staging_clk *bsc)
126 {
127         int error;
128
129         pr_debug("Aliasing clock %s for con_id %s dev_id %s\n", bsc->clk,
130                  bsc->con_id, bsc->dev_id);
131         error = clk_add_alias(bsc->con_id, bsc->dev_id, bsc->clk, NULL);
132         if (error)
133                 pr_err("Failed to alias clock %s (%d)\n", bsc->clk, error);
134
135         return error;
136 }
137
138 #ifdef CONFIG_PM_GENERIC_DOMAINS_OF
139 static int board_staging_add_dev_domain(struct platform_device *pdev,
140                                         const char *domain)
141 {
142         struct of_phandle_args pd_args;
143         struct device_node *np;
144
145         np = of_find_node_by_path(domain);
146         if (!np) {
147                 pr_err("Cannot find domain node %s\n", domain);
148                 return -ENOENT;
149         }
150
151         pd_args.np = np;
152         pd_args.args_count = 0;
153
154         return of_genpd_add_device(&pd_args, &pdev->dev);
155 }
156 #else
157 static inline int board_staging_add_dev_domain(struct platform_device *pdev,
158                                                const char *domain)
159 {
160         return 0;
161 }
162 #endif
163
164 int __init board_staging_register_device(const struct board_staging_dev *dev)
165 {
166         struct platform_device *pdev = dev->pdev;
167         unsigned int i;
168         int error;
169
170         pr_debug("Trying to register device %s\n", pdev->name);
171         if (board_staging_dt_node_available(pdev->resource,
172                                             pdev->num_resources)) {
173                 pr_warn("Skipping %s, already in DT\n", pdev->name);
174                 return -EEXIST;
175         }
176
177         board_staging_gic_fixup_resources(pdev->resource, pdev->num_resources);
178
179         for (i = 0; i < dev->nclocks; i++)
180                 board_staging_register_clock(&dev->clocks[i]);
181
182         if (dev->domain)
183                 board_staging_add_dev_domain(pdev, dev->domain);
184
185         error = platform_device_register(pdev);
186         if (error) {
187                 pr_err("Failed to register device %s (%d)\n", pdev->name,
188                        error);
189                 return error;
190         }
191
192         return error;
193 }
194
195 void __init board_staging_register_devices(const struct board_staging_dev *devs,
196                                            unsigned int ndevs)
197 {
198         unsigned int i;
199
200         for (i = 0; i < ndevs; i++)
201                 board_staging_register_device(&devs[i]);
202 }