diff options
author | Rabin Vincent <rabin@rab.in> | 2015-06-06 16:30:40 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-06-10 03:11:10 -0400 |
commit | d342571efea8135dcf0a96dcb9e54759adefdb27 (patch) | |
tree | a20b5523892622f19ad3c27b6089b413dabc8d6f /drivers/gpio/gpio-etraxfs.c | |
parent | e2bfba418598951733aff5822ca617efdbc06715 (diff) |
gpio: add ETRAXFS GPIO driver
Add a GPIO driver for the General I/O block on Axis ETRAX FS SoCs.
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-etraxfs.c')
-rw-r--r-- | drivers/gpio/gpio-etraxfs.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c new file mode 100644 index 000000000000..28071f4a5672 --- /dev/null +++ b/drivers/gpio/gpio-etraxfs.c | |||
@@ -0,0 +1,176 @@ | |||
1 | #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 | |||
29 | struct 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 | |||
37 | struct etraxfs_gpio_info { | ||
38 | unsigned int num_ports; | ||
39 | const struct etraxfs_gpio_port *ports; | ||
40 | }; | ||
41 | |||
42 | static 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 | |||
80 | static 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 | |||
85 | static 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 | |||
99 | static const struct of_device_id etraxfs_gpio_of_table[] = { | ||
100 | { | ||
101 | .compatible = "axis,etraxfs-gio", | ||
102 | .data = &etraxfs_gpio_etraxfs, | ||
103 | }, | ||
104 | {}, | ||
105 | }; | ||
106 | |||
107 | static 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 | |||
163 | static 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 | |||
171 | static int __init etraxfs_gpio_init(void) | ||
172 | { | ||
173 | return platform_driver_register(&etraxfs_gpio_driver); | ||
174 | } | ||
175 | |||
176 | device_initcall(etraxfs_gpio_init); | ||