blob: 28071f4a56724b94d15d5c418e8189b7cef697eb [file] [log] [blame]
Rabin Vincentd3425712015-06-06 22:30:40 +02001#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/gpio.h>
4#include <linux/of_gpio.h>
5#include <linux/io.h>
6#include <linux/platform_device.h>
7#include <linux/basic_mmio_gpio.h>
8
9#define ETRAX_FS_rw_pa_dout 0
10#define ETRAX_FS_r_pa_din 4
11#define ETRAX_FS_rw_pa_oe 8
12#define ETRAX_FS_rw_intr_cfg 12
13#define ETRAX_FS_rw_intr_mask 16
14#define ETRAX_FS_rw_ack_intr 20
15#define ETRAX_FS_r_intr 24
16#define ETRAX_FS_rw_pb_dout 32
17#define ETRAX_FS_r_pb_din 36
18#define ETRAX_FS_rw_pb_oe 40
19#define ETRAX_FS_rw_pc_dout 48
20#define ETRAX_FS_r_pc_din 52
21#define ETRAX_FS_rw_pc_oe 56
22#define ETRAX_FS_rw_pd_dout 64
23#define ETRAX_FS_r_pd_din 68
24#define ETRAX_FS_rw_pd_oe 72
25#define ETRAX_FS_rw_pe_dout 80
26#define ETRAX_FS_r_pe_din 84
27#define ETRAX_FS_rw_pe_oe 88
28
29struct etraxfs_gpio_port {
30 const char *label;
31 unsigned int oe;
32 unsigned int dout;
33 unsigned int din;
34 unsigned int ngpio;
35};
36
37struct etraxfs_gpio_info {
38 unsigned int num_ports;
39 const struct etraxfs_gpio_port *ports;
40};
41
42static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
43 {
44 .label = "A",
45 .ngpio = 8,
46 .oe = ETRAX_FS_rw_pa_oe,
47 .dout = ETRAX_FS_rw_pa_dout,
48 .din = ETRAX_FS_r_pa_din,
49 },
50 {
51 .label = "B",
52 .ngpio = 18,
53 .oe = ETRAX_FS_rw_pb_oe,
54 .dout = ETRAX_FS_rw_pb_dout,
55 .din = ETRAX_FS_r_pb_din,
56 },
57 {
58 .label = "C",
59 .ngpio = 18,
60 .oe = ETRAX_FS_rw_pc_oe,
61 .dout = ETRAX_FS_rw_pc_dout,
62 .din = ETRAX_FS_r_pc_din,
63 },
64 {
65 .label = "D",
66 .ngpio = 18,
67 .oe = ETRAX_FS_rw_pd_oe,
68 .dout = ETRAX_FS_rw_pd_dout,
69 .din = ETRAX_FS_r_pd_din,
70 },
71 {
72 .label = "E",
73 .ngpio = 18,
74 .oe = ETRAX_FS_rw_pe_oe,
75 .dout = ETRAX_FS_rw_pe_dout,
76 .din = ETRAX_FS_r_pe_din,
77 },
78};
79
80static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
81 .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
82 .ports = etraxfs_gpio_etraxfs_ports,
83};
84
85static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
86 const struct of_phandle_args *gpiospec,
87 u32 *flags)
88{
89 /*
90 * Port numbers are A to E, and the properties are integers, so we
91 * specify them as 0xA - 0xE.
92 */
93 if (gc->label[0] - 'A' + 0xA != gpiospec->args[2])
94 return -EINVAL;
95
96 return of_gpio_simple_xlate(gc, gpiospec, flags);
97}
98
99static const struct of_device_id etraxfs_gpio_of_table[] = {
100 {
101 .compatible = "axis,etraxfs-gio",
102 .data = &etraxfs_gpio_etraxfs,
103 },
104 {},
105};
106
107static int etraxfs_gpio_probe(struct platform_device *pdev)
108{
109 struct device *dev = &pdev->dev;
110 const struct etraxfs_gpio_info *info;
111 const struct of_device_id *match;
112 struct bgpio_chip *chips;
113 struct resource *res;
114 void __iomem *regs;
115 int ret;
116 int i;
117
118 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
119 regs = devm_ioremap_resource(dev, res);
120 if (!regs)
121 return -ENOMEM;
122
123 match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
124 if (!match)
125 return -EINVAL;
126
127 info = match->data;
128
129 chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
130 if (!chips)
131 return -ENOMEM;
132
133 for (i = 0; i < info->num_ports; i++) {
134 struct bgpio_chip *bgc = &chips[i];
135 const struct etraxfs_gpio_port *port = &info->ports[i];
136
137 ret = bgpio_init(bgc, dev, 4,
138 regs + port->din, /* dat */
139 regs + port->dout, /* set */
140 NULL, /* clr */
141 regs + port->oe, /* dirout */
142 NULL, /* dirin */
143 BGPIOF_UNREADABLE_REG_SET);
144 if (ret)
145 return ret;
146
147 bgc->gc.ngpio = port->ngpio;
148 bgc->gc.label = port->label;
149
150 bgc->gc.of_node = dev->of_node;
151 bgc->gc.of_gpio_n_cells = 3;
152 bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
153
154 ret = gpiochip_add(&bgc->gc);
155 if (ret)
156 dev_err(dev, "Unable to register port %s\n",
157 bgc->gc.label);
158 }
159
160 return 0;
161}
162
163static struct platform_driver etraxfs_gpio_driver = {
164 .driver = {
165 .name = "etraxfs-gpio",
166 .of_match_table = of_match_ptr(etraxfs_gpio_of_table),
167 },
168 .probe = etraxfs_gpio_probe,
169};
170
171static int __init etraxfs_gpio_init(void)
172{
173 return platform_driver_register(&etraxfs_gpio_driver);
174}
175
176device_initcall(etraxfs_gpio_init);