Commit | Line | Data |
---|---|---|
ddb27f3b AL |
1 | /* |
2 | * Driver for Aeroflex Gaisler GRGPIO General Purpose I/O cores. | |
3 | * | |
4 | * 2013 (c) Aeroflex Gaisler AB | |
5 | * | |
6 | * This driver supports the GRGPIO GPIO core available in the GRLIB VHDL | |
7 | * IP core library. | |
8 | * | |
9 | * Full documentation of the GRGPIO core can be found here: | |
10 | * http://www.gaisler.com/products/grlib/grip.pdf | |
11 | * | |
12 | * See "Documentation/devicetree/bindings/gpio/gpio-grgpio.txt" for | |
13 | * information on open firmware properties. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify it | |
16 | * under the terms of the GNU General Public License as published by the | |
17 | * Free Software Foundation; either version 2 of the License, or (at your | |
18 | * option) any later version. | |
19 | * | |
20 | * Contributors: Andreas Larsson <andreas@gaisler.com> | |
21 | */ | |
22 | ||
23 | #include <linux/kernel.h> | |
24 | #include <linux/module.h> | |
25 | #include <linux/init.h> | |
26 | #include <linux/spinlock.h> | |
27 | #include <linux/io.h> | |
28 | #include <linux/of.h> | |
29 | #include <linux/of_gpio.h> | |
30 | #include <linux/of_platform.h> | |
31 | #include <linux/gpio.h> | |
32 | #include <linux/slab.h> | |
33 | #include <linux/err.h> | |
34 | #include <linux/basic_mmio_gpio.h> | |
35 | ||
36 | #define GRGPIO_MAX_NGPIO 32 | |
37 | ||
38 | #define GRGPIO_DATA 0x00 | |
39 | #define GRGPIO_OUTPUT 0x04 | |
40 | #define GRGPIO_DIR 0x08 | |
41 | #define GRGPIO_IMASK 0x0c | |
42 | #define GRGPIO_IPOL 0x10 | |
43 | #define GRGPIO_IEDGE 0x14 | |
44 | #define GRGPIO_BYPASS 0x18 | |
45 | #define GRGPIO_IMAP_BASE 0x20 | |
46 | ||
47 | struct grgpio_priv { | |
48 | struct bgpio_chip bgc; | |
49 | void __iomem *regs; | |
50 | struct device *dev; | |
51 | }; | |
52 | ||
53 | static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc) | |
54 | { | |
55 | struct bgpio_chip *bgc = to_bgpio_chip(gc); | |
56 | ||
57 | return container_of(bgc, struct grgpio_priv, bgc); | |
58 | } | |
59 | ||
60 | static int grgpio_probe(struct platform_device *ofdev) | |
61 | { | |
62 | struct device_node *np = ofdev->dev.of_node; | |
63 | void __iomem *regs; | |
64 | struct gpio_chip *gc; | |
65 | struct bgpio_chip *bgc; | |
66 | struct grgpio_priv *priv; | |
67 | struct resource *res; | |
68 | int err; | |
69 | u32 prop; | |
70 | ||
71 | priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); | |
72 | if (!priv) | |
73 | return -ENOMEM; | |
74 | ||
75 | res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); | |
76 | regs = devm_ioremap_resource(&ofdev->dev, res); | |
77 | if (IS_ERR(regs)) | |
78 | return PTR_ERR(regs); | |
79 | ||
80 | bgc = &priv->bgc; | |
81 | err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA, | |
82 | regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL, | |
83 | BGPIOF_BIG_ENDIAN_BYTE_ORDER); | |
84 | if (err) { | |
85 | dev_err(&ofdev->dev, "bgpio_init() failed\n"); | |
86 | return err; | |
87 | } | |
88 | ||
89 | priv->regs = regs; | |
90 | priv->dev = &ofdev->dev; | |
91 | ||
92 | gc = &bgc->gc; | |
93 | gc->of_node = np; | |
94 | gc->owner = THIS_MODULE; | |
95 | gc->label = np->full_name; | |
96 | gc->base = -1; | |
97 | ||
98 | err = of_property_read_u32(np, "nbits", &prop); | |
99 | if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) { | |
100 | gc->ngpio = GRGPIO_MAX_NGPIO; | |
101 | dev_dbg(&ofdev->dev, | |
102 | "No or invalid nbits property: assume %d\n", gc->ngpio); | |
103 | } else { | |
104 | gc->ngpio = prop; | |
105 | } | |
106 | ||
107 | platform_set_drvdata(ofdev, priv); | |
108 | ||
109 | err = gpiochip_add(gc); | |
110 | if (err) { | |
111 | dev_err(&ofdev->dev, "Could not add gpiochip\n"); | |
112 | return err; | |
113 | } | |
114 | ||
115 | dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d\n", | |
116 | priv->regs, gc->base, gc->ngpio); | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
121 | static int grgpio_remove(struct platform_device *ofdev) | |
122 | { | |
123 | struct grgpio_priv *priv = platform_get_drvdata(ofdev); | |
124 | ||
125 | return gpiochip_remove(&priv->bgc.gc); | |
126 | } | |
127 | ||
128 | static struct of_device_id grgpio_match[] = { | |
129 | {.name = "GAISLER_GPIO"}, | |
130 | {.name = "01_01a"}, | |
131 | {}, | |
132 | }; | |
133 | ||
134 | MODULE_DEVICE_TABLE(of, grgpio_match); | |
135 | ||
136 | static struct platform_driver grgpio_driver = { | |
137 | .driver = { | |
138 | .name = "grgpio", | |
139 | .owner = THIS_MODULE, | |
140 | .of_match_table = grgpio_match, | |
141 | }, | |
142 | .probe = grgpio_probe, | |
143 | .remove = grgpio_remove, | |
144 | }; | |
145 | module_platform_driver(grgpio_driver); | |
146 | ||
147 | MODULE_AUTHOR("Aeroflex Gaisler AB."); | |
148 | MODULE_DESCRIPTION("Driver for Aeroflex Gaisler GRGPIO"); | |
149 | MODULE_LICENSE("GPL"); |