aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlessandro Rubini <rubini@gnudd.com>2012-04-12 04:48:44 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-05-09 09:34:28 -0400
commit35bdd29095ad614c5fb4a934bfd4f57a94dfd395 (patch)
tree26db4b35f5f05d4a160235aa02ba5cb579c5f2f9 /drivers
parentceb57d27e28a8f979cbfd6391b7da6da51484059 (diff)
mfd: Add driver for STA2X11 MFD block
This also introduces <asm/sta2x11.h> to export a function that is in the base sta2x11 support patches. The header will increase with other prototypes and constants over time. Signed-off-by: Alessandro Rubini <rubini@gnudd.com> Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com> Cc: Alan Cox <alan@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig5
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/sta2x11-mfd.c467
3 files changed, 473 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ef86a741b7e2..48eed22c65a5 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -906,6 +906,11 @@ config MFD_RC5T583
906 Additional drivers must be enabled in order to use the 906 Additional drivers must be enabled in order to use the
907 different functionality of the device. 907 different functionality of the device.
908 908
909config MFD_STA2X11
910 bool "STA2X11 multi function device support"
911 depends on STA2X11
912 select MFD_CORE
913
909config MFD_ANATOP 914config MFD_ANATOP
910 bool "Support for Freescale i.MX on-chip ANATOP controller" 915 bool "Support for Freescale i.MX on-chip ANATOP controller"
911 depends on SOC_IMX6Q 916 depends on SOC_IMX6Q
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5dd6be7aa350..0dc55cbefa09 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
15obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o 15obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
16obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o 16obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
17 17
18obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
18obj-$(CONFIG_MFD_STMPE) += stmpe.o 19obj-$(CONFIG_MFD_STMPE) += stmpe.o
19obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o 20obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
20obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o 21obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c
new file mode 100644
index 000000000000..d31fed07aefb
--- /dev/null
+++ b/drivers/mfd/sta2x11-mfd.c
@@ -0,0 +1,467 @@
1/*
2 * Copyright (c) 2009-2011 Wind River Systems, Inc.
3 * Copyright (c) 2011 ST Microelectronics (Alessandro Rubini)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/spinlock.h>
23#include <linux/errno.h>
24#include <linux/device.h>
25#include <linux/slab.h>
26#include <linux/list.h>
27#include <linux/io.h>
28#include <linux/ioport.h>
29#include <linux/pci.h>
30#include <linux/debugfs.h>
31#include <linux/seq_file.h>
32#include <linux/platform_device.h>
33#include <linux/mfd/core.h>
34#include <linux/mfd/sta2x11-mfd.h>
35
36#include <asm/sta2x11.h>
37
38/* This describes STA2X11 MFD chip for us, we may have several */
39struct sta2x11_mfd {
40 struct sta2x11_instance *instance;
41 spinlock_t lock;
42 struct list_head list;
43 void __iomem *sctl_regs;
44 void __iomem *apbreg_regs;
45};
46
47static LIST_HEAD(sta2x11_mfd_list);
48
49/* Three functions to act on the list */
50static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev)
51{
52 struct sta2x11_instance *instance;
53 struct sta2x11_mfd *mfd;
54
55 if (!pdev && !list_empty(&sta2x11_mfd_list)) {
56 pr_warning("%s: Unspecified device, "
57 "using first instance\n", __func__);
58 return list_entry(sta2x11_mfd_list.next,
59 struct sta2x11_mfd, list);
60 }
61
62 instance = sta2x11_get_instance(pdev);
63 if (!instance)
64 return NULL;
65 list_for_each_entry(mfd, &sta2x11_mfd_list, list) {
66 if (mfd->instance == instance)
67 return mfd;
68 }
69 return NULL;
70}
71
72static int __devinit sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags)
73{
74 struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
75 struct sta2x11_instance *instance;
76
77 if (mfd)
78 return -EBUSY;
79 instance = sta2x11_get_instance(pdev);
80 if (!instance)
81 return -EINVAL;
82 mfd = kzalloc(sizeof(*mfd), flags);
83 if (!mfd)
84 return -ENOMEM;
85 INIT_LIST_HEAD(&mfd->list);
86 spin_lock_init(&mfd->lock);
87 mfd->instance = instance;
88 list_add(&mfd->list, &sta2x11_mfd_list);
89 return 0;
90}
91
92static int __devexit mfd_remove(struct pci_dev *pdev)
93{
94 struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
95
96 if (!mfd)
97 return -ENODEV;
98 list_del(&mfd->list);
99 kfree(mfd);
100 return 0;
101}
102
103/* These two functions are exported and are not expected to fail */
104u32 sta2x11_sctl_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val)
105{
106 struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
107 u32 r;
108 unsigned long flags;
109
110 if (!mfd) {
111 dev_warn(&pdev->dev, ": can't access sctl regs\n");
112 return 0;
113 }
114 if (!mfd->sctl_regs) {
115 dev_warn(&pdev->dev, ": system ctl not initialized\n");
116 return 0;
117 }
118 spin_lock_irqsave(&mfd->lock, flags);
119 r = readl(mfd->sctl_regs + reg);
120 r &= ~mask;
121 r |= val;
122 if (mask)
123 writel(r, mfd->sctl_regs + reg);
124 spin_unlock_irqrestore(&mfd->lock, flags);
125 return r;
126}
127EXPORT_SYMBOL(sta2x11_sctl_mask);
128
129u32 sta2x11_apbreg_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val)
130{
131 struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
132 u32 r;
133 unsigned long flags;
134
135 if (!mfd) {
136 dev_warn(&pdev->dev, ": can't access apb regs\n");
137 return 0;
138 }
139 if (!mfd->apbreg_regs) {
140 dev_warn(&pdev->dev, ": apb bridge not initialized\n");
141 return 0;
142 }
143 spin_lock_irqsave(&mfd->lock, flags);
144 r = readl(mfd->apbreg_regs + reg);
145 r &= ~mask;
146 r |= val;
147 if (mask)
148 writel(r, mfd->apbreg_regs + reg);
149 spin_unlock_irqrestore(&mfd->lock, flags);
150 return r;
151}
152EXPORT_SYMBOL(sta2x11_apbreg_mask);
153
154/* Two debugfs files, for our registers (FIXME: one instance only) */
155#define REG(regname) {.name = #regname, .offset = SCTL_ ## regname}
156static struct debugfs_reg32 sta2x11_sctl_regs[] = {
157 REG(SCCTL), REG(ARMCFG), REG(SCPLLCTL), REG(SCPLLFCTRL),
158 REG(SCRESFRACT), REG(SCRESCTRL1), REG(SCRESXTRL2), REG(SCPEREN0),
159 REG(SCPEREN1), REG(SCPEREN2), REG(SCGRST), REG(SCPCIPMCR1),
160 REG(SCPCIPMCR2), REG(SCPCIPMSR1), REG(SCPCIPMSR2), REG(SCPCIPMSR3),
161 REG(SCINTREN), REG(SCRISR), REG(SCCLKSTAT0), REG(SCCLKSTAT1),
162 REG(SCCLKSTAT2), REG(SCRSTSTA),
163};
164#undef REG
165
166static struct debugfs_regset32 sctl_regset = {
167 .regs = sta2x11_sctl_regs,
168 .nregs = ARRAY_SIZE(sta2x11_sctl_regs),
169};
170
171#define REG(regname) {.name = #regname, .offset = regname}
172static struct debugfs_reg32 sta2x11_apbreg_regs[] = {
173 REG(APBREG_BSR), REG(APBREG_PAER), REG(APBREG_PWAC), REG(APBREG_PRAC),
174 REG(APBREG_PCG), REG(APBREG_PUR), REG(APBREG_EMU_PCG),
175};
176#undef REG
177
178static struct debugfs_regset32 apbreg_regset = {
179 .regs = sta2x11_apbreg_regs,
180 .nregs = ARRAY_SIZE(sta2x11_apbreg_regs),
181};
182
183static struct dentry *sta2x11_sctl_debugfs;
184static struct dentry *sta2x11_apbreg_debugfs;
185
186/* Probe for the two platform devices */
187static int sta2x11_sctl_probe(struct platform_device *dev)
188{
189 struct pci_dev **pdev;
190 struct sta2x11_mfd *mfd;
191 struct resource *res;
192
193 pdev = dev->dev.platform_data;
194 mfd = sta2x11_mfd_find(*pdev);
195 if (!mfd)
196 return -ENODEV;
197
198 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
199 if (!res)
200 return -ENOMEM;
201
202 if (!request_mem_region(res->start, resource_size(res),
203 "sta2x11-sctl"))
204 return -EBUSY;
205
206 mfd->sctl_regs = ioremap(res->start, resource_size(res));
207 if (!mfd->sctl_regs) {
208 release_mem_region(res->start, resource_size(res));
209 return -ENOMEM;
210 }
211 sctl_regset.base = mfd->sctl_regs;
212 sta2x11_sctl_debugfs = debugfs_create_regset32("sta2x11-sctl",
213 S_IFREG | S_IRUGO,
214 NULL, &sctl_regset);
215 return 0;
216}
217
218static int sta2x11_apbreg_probe(struct platform_device *dev)
219{
220 struct pci_dev **pdev;
221 struct sta2x11_mfd *mfd;
222 struct resource *res;
223
224 pdev = dev->dev.platform_data;
225 dev_dbg(&dev->dev, "%s: pdata is %p\n", __func__, pdev);
226 dev_dbg(&dev->dev, "%s: *pdata is %p\n", __func__, *pdev);
227
228 mfd = sta2x11_mfd_find(*pdev);
229 if (!mfd)
230 return -ENODEV;
231
232 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
233 if (!res)
234 return -ENOMEM;
235
236 if (!request_mem_region(res->start, resource_size(res),
237 "sta2x11-apbreg"))
238 return -EBUSY;
239
240 mfd->apbreg_regs = ioremap(res->start, resource_size(res));
241 if (!mfd->apbreg_regs) {
242 release_mem_region(res->start, resource_size(res));
243 return -ENOMEM;
244 }
245 dev_dbg(&dev->dev, "%s: regbase %p\n", __func__, mfd->apbreg_regs);
246
247 apbreg_regset.base = mfd->apbreg_regs;
248 sta2x11_apbreg_debugfs = debugfs_create_regset32("sta2x11-apbreg",
249 S_IFREG | S_IRUGO,
250 NULL, &apbreg_regset);
251 return 0;
252}
253
254/* The two platform drivers */
255static struct platform_driver sta2x11_sctl_platform_driver = {
256 .driver = {
257 .name = "sta2x11-sctl",
258 .owner = THIS_MODULE,
259 },
260 .probe = sta2x11_sctl_probe,
261};
262
263static int __init sta2x11_sctl_init(void)
264{
265 pr_info("%s\n", __func__);
266 return platform_driver_register(&sta2x11_sctl_platform_driver);
267}
268
269static struct platform_driver sta2x11_platform_driver = {
270 .driver = {
271 .name = "sta2x11-apbreg",
272 .owner = THIS_MODULE,
273 },
274 .probe = sta2x11_apbreg_probe,
275};
276
277static int __init sta2x11_apbreg_init(void)
278{
279 pr_info("%s\n", __func__);
280 return platform_driver_register(&sta2x11_platform_driver);
281}
282
283/*
284 * What follows is the PCI device that hosts the above two pdevs.
285 * Each logic block is 4kB and they are all consecutive: we use this info.
286 */
287
288/* Bar 0 */
289enum bar0_cells {
290 STA2X11_GPIO_0 = 0,
291 STA2X11_GPIO_1,
292 STA2X11_GPIO_2,
293 STA2X11_GPIO_3,
294 STA2X11_SCTL,
295 STA2X11_SCR,
296 STA2X11_TIME,
297};
298/* Bar 1 */
299enum bar1_cells {
300 STA2X11_APBREG = 0,
301};
302#define CELL_4K(_name, _cell) { \
303 .name = _name, \
304 .start = _cell * 4096, .end = _cell * 4096 + 4095, \
305 .flags = IORESOURCE_MEM, \
306 }
307
308static const __devinitconst struct resource gpio_resources[] = {
309 {
310 .name = "sta2x11_gpio", /* 4 consecutive cells, 1 driver */
311 .start = 0,
312 .end = (4 * 4096) - 1,
313 .flags = IORESOURCE_MEM,
314 }
315};
316static const __devinitconst struct resource sctl_resources[] = {
317 CELL_4K("sta2x11-sctl", STA2X11_SCTL),
318};
319static const __devinitconst struct resource scr_resources[] = {
320 CELL_4K("sta2x11-scr", STA2X11_SCR),
321};
322static const __devinitconst struct resource time_resources[] = {
323 CELL_4K("sta2x11-time", STA2X11_TIME),
324};
325
326static const __devinitconst struct resource apbreg_resources[] = {
327 CELL_4K("sta2x11-apbreg", STA2X11_APBREG),
328};
329
330#define DEV(_name, _r) \
331 { .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, }
332
333static __devinitdata struct mfd_cell sta2x11_mfd_bar0[] = {
334 DEV("sta2x11-gpio", gpio_resources), /* offset 0: we add pdata later */
335 DEV("sta2x11-sctl", sctl_resources),
336 DEV("sta2x11-scr", scr_resources),
337 DEV("sta2x11-time", time_resources),
338};
339
340static __devinitdata struct mfd_cell sta2x11_mfd_bar1[] = {
341 DEV("sta2x11-apbreg", apbreg_resources),
342};
343
344static int sta2x11_mfd_suspend(struct pci_dev *pdev, pm_message_t state)
345{
346 pci_save_state(pdev);
347 pci_disable_device(pdev);
348 pci_set_power_state(pdev, pci_choose_state(pdev, state));
349
350 return 0;
351}
352
353static int sta2x11_mfd_resume(struct pci_dev *pdev)
354{
355 int err;
356
357 pci_set_power_state(pdev, 0);
358 err = pci_enable_device(pdev);
359 if (err)
360 return err;
361 pci_restore_state(pdev);
362
363 return 0;
364}
365
366static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev,
367 const struct pci_device_id *pci_id)
368{
369 int err, i;
370 struct sta2x11_gpio_pdata *gpio_data;
371
372 dev_info(&pdev->dev, "%s\n", __func__);
373
374 err = pci_enable_device(pdev);
375 if (err) {
376 dev_err(&pdev->dev, "Can't enable device.\n");
377 return err;
378 }
379
380 err = pci_enable_msi(pdev);
381 if (err)
382 dev_info(&pdev->dev, "Enable msi failed\n");
383
384 /* Read gpio config data as pci device's platform data */
385 gpio_data = dev_get_platdata(&pdev->dev);
386 if (!gpio_data)
387 dev_warn(&pdev->dev, "no gpio configuration\n");
388
389 dev_dbg(&pdev->dev, "%s, gpio_data = %p (%p)\n", __func__,
390 gpio_data, &gpio_data);
391 dev_dbg(&pdev->dev, "%s, pdev = %p (%p)\n", __func__,
392 pdev, &pdev);
393
394 /* platform data is the pci device for all of them */
395 for (i = 0; i < ARRAY_SIZE(sta2x11_mfd_bar0); i++) {
396 sta2x11_mfd_bar0[i].pdata_size = sizeof(pdev);
397 sta2x11_mfd_bar0[i].platform_data = &pdev;
398 }
399 sta2x11_mfd_bar1[0].pdata_size = sizeof(pdev);
400 sta2x11_mfd_bar1[0].platform_data = &pdev;
401
402 /* Record this pdev before mfd_add_devices: their probe looks for it */
403 sta2x11_mfd_add(pdev, GFP_ATOMIC);
404
405
406 err = mfd_add_devices(&pdev->dev, -1,
407 sta2x11_mfd_bar0,
408 ARRAY_SIZE(sta2x11_mfd_bar0),
409 &pdev->resource[0],
410 0);
411 if (err) {
412 dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err);
413 goto err_disable;
414 }
415
416 err = mfd_add_devices(&pdev->dev, -1,
417 sta2x11_mfd_bar1,
418 ARRAY_SIZE(sta2x11_mfd_bar1),
419 &pdev->resource[1],
420 0);
421 if (err) {
422 dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err);
423 goto err_disable;
424 }
425
426 return 0;
427
428err_disable:
429 mfd_remove_devices(&pdev->dev);
430 pci_disable_device(pdev);
431 pci_disable_msi(pdev);
432 return err;
433}
434
435static DEFINE_PCI_DEVICE_TABLE(sta2x11_mfd_tbl) = {
436 {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_GPIO)},
437 {0,},
438};
439
440static struct pci_driver sta2x11_mfd_driver = {
441 .name = "sta2x11-mfd",
442 .id_table = sta2x11_mfd_tbl,
443 .probe = sta2x11_mfd_probe,
444 .suspend = sta2x11_mfd_suspend,
445 .resume = sta2x11_mfd_resume,
446};
447
448static int __init sta2x11_mfd_init(void)
449{
450 pr_info("%s\n", __func__);
451 return pci_register_driver(&sta2x11_mfd_driver);
452}
453
454/*
455 * All of this must be ready before "normal" devices like MMCI appear.
456 * But MFD (the pci device) can't be too early. The following choice
457 * prepares platform drivers very early and probe the PCI device later,
458 * but before other PCI devices.
459 */
460subsys_initcall(sta2x11_apbreg_init);
461subsys_initcall(sta2x11_sctl_init);
462rootfs_initcall(sta2x11_mfd_init);
463
464MODULE_LICENSE("GPL v2");
465MODULE_AUTHOR("Wind River");
466MODULE_DESCRIPTION("STA2x11 mfd for GPIO, SCTL and APBREG");
467MODULE_DEVICE_TABLE(pci, sta2x11_mfd_tbl);