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
6 This patch provides a common subdevice registration system for MFD type
7 chips, using platfrom device.
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
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
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
27 menu "Multifunction device drivers"
35 tristate "Support for Silicon Motion SM501"
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
43 obj-$(CONFIG_MFD_SM501) += sm501.o
45 +obj-$(CONFIG_MFD_CORE) += mfd-core.o
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
52 index 0000000..88874e1
54 +++ b/drivers/mfd/mfd-core.c
57 + * drivers/mfd/mfd-core.c
60 + * Copyright (c) 2006 Ian Molton
61 + * Copyright (c) 2007 Dmitry Baryshkov
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.
69 +#include <linux/kernel.h>
70 +#include <linux/platform_device.h>
71 +#include <linux/mfd-core.h>
73 +#define SIGNED_SHIFT(val, shift) ((shift) >= 0 ? \
74 + ((val) << (shift)) : \
75 + ((val) >> -(shift)))
78 + struct platform_device *parent,
79 + const struct mfd_cell *cells, int n_devs,
80 + struct resource *mem,
81 + int relative_addr_shift,
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;
93 + pdev = platform_device_alloc(cell->name, -1);
97 + pdev->dev.uevent_suppress = 0;
98 + pdev->dev.parent = &parent->dev;
100 + ret = platform_device_add_data(pdev, &cell, sizeof(struct mfd_cell *));
104 + res = kzalloc(cell->num_resources * sizeof(struct resource),
109 + for (r = 0; r < cell->num_resources; r++) {
110 + res[r].name = cell->resources[r].name;
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;
128 + res[r].start = cell->resources[r].start;
129 + res[r].end = cell->resources[r].end;
132 + res[r].flags = cell->resources[r].flags;
135 + ret = platform_device_add_resources(pdev,
137 + cell->num_resources);
143 + ret = platform_device_add(pdev);
146 + platform_device_del(pdev);
148 + platform_device_put(pdev);
150 + mfd_remove_devices(parent);
156 +EXPORT_SYMBOL(mfd_add_devices);
158 +static int mfd_remove_devices_fn(struct device *dev, void *unused)
160 + platform_device_unregister(container_of(dev, struct platform_device, dev));
164 +void mfd_remove_devices(struct platform_device *parent)
166 + device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn);
168 +EXPORT_SYMBOL(mfd_remove_devices);
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)
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
186 index 0000000..0e9de78
188 +++ b/include/linux/mfd-core.h
193 + * drivers/mfd/mfd-core.h
196 + * Copyright (c) 2006 Ian Molton
197 + * Copyright (c) 2007 Dmitry Baryshkov
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.
205 +#include <linux/platform_device.h>
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);
215 + void *driver_data; /* data passed to drivers */
218 + * This resources can be specified relatievly to the parent device.
219 + * For accessing device you should use resources from device
222 + const struct resource *resources;
225 +static inline __maybe_unused struct mfd_cell *
226 +mfd_get_cell(struct platform_device *pdev)
228 + return *((struct mfd_cell **)(pdev->dev.platform_data));
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,
238 +extern void mfd_remove_devices(struct platform_device *parent);