merge of '0b604857bbf871639fdb43ee8380222e8ef64bb7'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0003-Core-MFD-support.patch
1 From a07910753f9965842b6647f0561db125b538f5ed Mon Sep 17 00:00:00 2001
2 From: Ian Molton <spyro@f2s.com>
3 Date: Fri, 4 Jan 2008 18:32:44 +0000
4 Subject: [PATCH 03/64] Core MFD support
5
6 This patch provides a common subdevice registration system for MFD type
7 chips, using platfrom device.
8
9 It also provides a new resource type for IRQs such that a subdevices IRQ may
10 be computed based on the MFD cores IRQ handler, since many MFDs provide an IRQ
11 multiplex.
12 ---
13  drivers/mfd/Kconfig      |    4 ++
14  drivers/mfd/Makefile     |    2 +
15  drivers/mfd/mfd-core.c   |  116 ++++++++++++++++++++++++++++++++++++++++++++++
16  include/linux/ioport.h   |    1 +
17  include/linux/mfd-core.h |   51 ++++++++++++++++++++
18  5 files changed, 174 insertions(+), 0 deletions(-)
19  create mode 100644 drivers/mfd/mfd-core.c
20  create mode 100644 include/linux/mfd-core.h
21
22 diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
23 index 2571619..1205c89 100644
24 --- a/drivers/mfd/Kconfig
25 +++ b/drivers/mfd/Kconfig
26 @@ -5,6 +5,10 @@
27  menu "Multifunction device drivers"
28         depends on HAS_IOMEM
29  
30 +config MFD_CORE
31 +       tristate
32 +       default n
33 +
34  config MFD_SM501
35         tristate "Support for Silicon Motion SM501"
36          ---help---
37 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
38 index 5143209..6c20064 100644
39 --- a/drivers/mfd/Makefile
40 +++ b/drivers/mfd/Makefile
41 @@ -4,6 +4,8 @@
42  
43  obj-$(CONFIG_MFD_SM501)                += sm501.o
44  
45 +obj-$(CONFIG_MFD_CORE)         += mfd-core.o
46 +
47  obj-$(CONFIG_MCP)              += mcp-core.o
48  obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
49  obj-$(CONFIG_MCP_UCB1200)      += ucb1x00-core.o
50 diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
51 new file mode 100644
52 index 0000000..88874e1
53 --- /dev/null
54 +++ b/drivers/mfd/mfd-core.c
55 @@ -0,0 +1,116 @@
56 +/*
57 + * drivers/mfd/mfd-core.c
58 + *
59 + * core MFD support
60 + * Copyright (c) 2006 Ian Molton
61 + * Copyright (c) 2007 Dmitry Baryshkov
62 + *
63 + * This program is free software; you can redistribute it and/or modify
64 + * it under the terms of the GNU General Public License version 2 as
65 + * published by the Free Software Foundation.
66 + *
67 + */
68 +
69 +#include <linux/kernel.h>
70 +#include <linux/platform_device.h>
71 +#include <linux/mfd-core.h>
72 +
73 +#define SIGNED_SHIFT(val, shift) ((shift) >= 0 ?       \
74 +                       ((val) << (shift)) :            \
75 +                       ((val) >> -(shift)))
76 +
77 +int mfd_add_devices(
78 +               struct platform_device *parent,
79 +               const struct mfd_cell *cells, int n_devs,
80 +               struct resource *mem,
81 +               int relative_addr_shift,
82 +               int irq_base)
83 +{
84 +       int i;
85 +
86 +       for (i = 0; i < n_devs; i++) {
87 +               struct resource *res = NULL;
88 +               const struct mfd_cell *cell = cells + i;
89 +               struct platform_device *pdev;
90 +               int ret = -ENOMEM;
91 +               int r;
92 +
93 +               pdev = platform_device_alloc(cell->name, -1);
94 +               if (!pdev)
95 +                       goto fail_alloc;
96 +
97 +               pdev->dev.uevent_suppress = 0;
98 +               pdev->dev.parent = &parent->dev;
99 +
100 +               ret = platform_device_add_data(pdev, &cell, sizeof(struct mfd_cell *));
101 +               if (ret)
102 +                       goto fail_device;
103 +
104 +               res = kzalloc(cell->num_resources * sizeof(struct resource),
105 +                                                       GFP_KERNEL);
106 +               if (!res)
107 +                       goto fail_device;
108 +
109 +               for (r = 0; r < cell->num_resources; r++) {
110 +                       res[r].name = cell->resources[r].name;
111 +
112 +                       /* Find out base to use */
113 +                       if (cell->resources[r].flags & IORESOURCE_MEM) {
114 +                               res[r].parent = mem;
115 +                               res[r].start = mem->start +
116 +                                       SIGNED_SHIFT(cell->resources[r].start,
117 +                                                       relative_addr_shift);
118 +                               res[r].end   = mem->start +
119 +                                       SIGNED_SHIFT(cell->resources[r].end,
120 +                                                       relative_addr_shift);
121 +                       } else if ((cell->resources[r].flags & IORESOURCE_IRQ) &&
122 +                               (cell->resources[r].flags & IORESOURCE_IRQ_MFD_SUBDEVICE)) {
123 +                               res[r].start = irq_base +
124 +                                       cell->resources[r].start;
125 +                               res[r].end   = irq_base +
126 +                                       cell->resources[r].end;
127 +                       } else {
128 +                               res[r].start = cell->resources[r].start;
129 +                               res[r].end   = cell->resources[r].end;
130 +                       }
131 +
132 +                       res[r].flags = cell->resources[r].flags;
133 +               }
134 +
135 +               ret = platform_device_add_resources(pdev,
136 +                               res,
137 +                               cell->num_resources);
138 +               kfree(res);
139 +
140 +               if (ret)
141 +                       goto fail_device;
142 +
143 +               ret = platform_device_add(pdev);
144 +
145 +               if (ret) {
146 +                       platform_device_del(pdev);
147 +fail_device:
148 +                       platform_device_put(pdev);
149 +fail_alloc:
150 +                       mfd_remove_devices(parent);
151 +                       return ret;
152 +               }
153 +       }
154 +       return 0;
155 +}
156 +EXPORT_SYMBOL(mfd_add_devices);
157 +
158 +static int mfd_remove_devices_fn(struct device *dev, void *unused)
159 +{
160 +       platform_device_unregister(container_of(dev, struct platform_device, dev));
161 +       return 0;
162 +}
163 +
164 +void mfd_remove_devices(struct platform_device *parent)
165 +{
166 +       device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn);
167 +}
168 +EXPORT_SYMBOL(mfd_remove_devices);
169 +
170 +MODULE_LICENSE("GPL");
171 +MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
172 diff --git a/include/linux/ioport.h b/include/linux/ioport.h
173 index 6187a85..0348c71 100644
174 --- a/include/linux/ioport.h
175 +++ b/include/linux/ioport.h
176 @@ -56,6 +56,7 @@ struct resource_list {
177  #define IORESOURCE_IRQ_HIGHLEVEL       (1<<2)
178  #define IORESOURCE_IRQ_LOWLEVEL                (1<<3)
179  #define IORESOURCE_IRQ_SHAREABLE       (1<<4)
180 +#define IORESOURCE_IRQ_MFD_SUBDEVICE   (1<<5)
181  
182  /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
183  #define IORESOURCE_DMA_TYPE_MASK       (3<<0)
184 diff --git a/include/linux/mfd-core.h b/include/linux/mfd-core.h
185 new file mode 100644
186 index 0000000..0e9de78
187 --- /dev/null
188 +++ b/include/linux/mfd-core.h
189 @@ -0,0 +1,51 @@
190 +#ifndef MFD_CORE_H
191 +#define MFD_CORE_H
192 +/*
193 + * drivers/mfd/mfd-core.h
194 + *
195 + * core MFD support
196 + * Copyright (c) 2006 Ian Molton
197 + * Copyright (c) 2007 Dmitry Baryshkov
198 + *
199 + * This program is free software; you can redistribute it and/or modify
200 + * it under the terms of the GNU General Public License version 2 as
201 + * published by the Free Software Foundation.
202 + *
203 + */
204 +
205 +#include <linux/platform_device.h>
206 +
207 +struct mfd_cell {
208 +       const char              *name;
209 +
210 +       int                     (*enable)(struct platform_device *dev);
211 +       int                     (*disable)(struct platform_device *dev);
212 +       int                     (*suspend)(struct platform_device *dev);
213 +       int                     (*resume)(struct platform_device *dev);
214 +
215 +       void                    *driver_data; /* data passed to drivers */
216 +
217 +       /*
218 +        * This resources can be specified relatievly to the parent device.
219 +        * For accessing device you should use resources from device
220 +        */
221 +       int                     num_resources;
222 +       const struct resource   *resources;
223 +};
224 +
225 +static inline __maybe_unused struct mfd_cell *
226 +mfd_get_cell(struct platform_device *pdev)
227 +{
228 +       return *((struct mfd_cell **)(pdev->dev.platform_data));
229 +}
230 +
231 +extern int mfd_add_devices(
232 +               struct platform_device *parent,
233 +               const struct mfd_cell *cells, int n_devs,
234 +               struct resource *mem,
235 +               int relative_addr_shift,
236 +               int irq_base);
237 +
238 +extern void mfd_remove_devices(struct platform_device *parent);
239 +
240 +#endif
241 -- 
242 1.5.3.8
243