Commit | Line | Data |
---|---|---|
9dc367bc MW |
1 | /* |
2 | * GE PIO2 GPIO Driver | |
3 | * | |
4 | * Author: Martyn Welch <martyn.welch@ge.com> | |
5 | * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. | |
11 | */ | |
12 | ||
9dc367bc MW |
13 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | |
15 | #include <linux/types.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/device.h> | |
19 | #include <linux/platform_device.h> | |
20 | #include <linux/ctype.h> | |
21 | #include <linux/gpio.h> | |
22 | #include <linux/slab.h> | |
db3b9e99 | 23 | #include <linux/vme.h> |
9dc367bc | 24 | |
9dc367bc MW |
25 | #include "vme_pio2.h" |
26 | ||
27 | static const char driver_name[] = "pio2_gpio"; | |
28 | ||
29 | static struct pio2_card *gpio_to_pio2_card(struct gpio_chip *chip) | |
30 | { | |
31 | return container_of(chip, struct pio2_card, gc); | |
32 | } | |
33 | ||
34 | static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset) | |
35 | { | |
36 | u8 reg; | |
37 | int retval; | |
38 | struct pio2_card *card = gpio_to_pio2_card(chip); | |
39 | ||
40 | if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | | |
41 | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { | |
42 | ||
43 | dev_err(&card->vdev->dev, "Channel not available as input\n"); | |
44 | return 0; | |
45 | } | |
46 | ||
47 | retval = vme_master_read(card->window, ®, 1, | |
48 | PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]); | |
49 | if (retval < 0) { | |
50 | dev_err(&card->vdev->dev, "Unable to read from GPIO\n"); | |
51 | return 0; | |
52 | } | |
53 | ||
54 | /* | |
55 | * Remember, input on channels configured as both input and output | |
56 | * are inverted! | |
57 | */ | |
58 | if (reg & PIO2_CHANNEL_BIT[offset]) { | |
59 | if (card->bank[PIO2_CHANNEL_BANK[offset]].config != BOTH) | |
60 | return 0; | |
61 | else | |
62 | return 1; | |
63 | } else { | |
64 | if (card->bank[PIO2_CHANNEL_BANK[offset]].config != BOTH) | |
65 | return 1; | |
66 | else | |
67 | return 0; | |
68 | } | |
69 | } | |
70 | ||
71 | static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset, | |
72 | int value) | |
73 | { | |
74 | u8 reg; | |
75 | int retval; | |
76 | struct pio2_card *card = gpio_to_pio2_card(chip); | |
77 | ||
78 | if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | | |
79 | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { | |
80 | ||
73e29189 | 81 | dev_err(&card->vdev->dev, "Channel not available as output\n"); |
9dc367bc MW |
82 | return; |
83 | } | |
84 | ||
85 | if (value) | |
86 | reg = card->bank[PIO2_CHANNEL_BANK[offset]].value | | |
87 | PIO2_CHANNEL_BIT[offset]; | |
88 | else | |
89 | reg = card->bank[PIO2_CHANNEL_BANK[offset]].value & | |
90 | ~PIO2_CHANNEL_BIT[offset]; | |
91 | ||
92 | retval = vme_master_write(card->window, ®, 1, | |
93 | PIO2_REGS_DATA[PIO2_CHANNEL_BANK[offset]]); | |
94 | if (retval < 0) { | |
95 | dev_err(&card->vdev->dev, "Unable to write to GPIO\n"); | |
96 | return; | |
97 | } | |
98 | ||
99 | card->bank[PIO2_CHANNEL_BANK[offset]].value = reg; | |
100 | } | |
101 | ||
102 | /* Directionality configured at board build - send appropriate response */ | |
103 | static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset) | |
104 | { | |
105 | int data; | |
106 | struct pio2_card *card = gpio_to_pio2_card(chip); | |
107 | ||
108 | if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) | | |
109 | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { | |
110 | dev_err(&card->vdev->dev, | |
111 | "Channel directionality not configurable at runtine\n"); | |
112 | ||
113 | data = -EINVAL; | |
114 | } else { | |
115 | data = 0; | |
116 | } | |
117 | ||
118 | return data; | |
119 | } | |
120 | ||
121 | /* Directionality configured at board build - send appropriate response */ | |
122 | static int pio2_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) | |
123 | { | |
124 | int data; | |
125 | struct pio2_card *card = gpio_to_pio2_card(chip); | |
126 | ||
127 | if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | | |
128 | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { | |
129 | dev_err(&card->vdev->dev, | |
130 | "Channel directionality not configurable at runtine\n"); | |
131 | ||
132 | data = -EINVAL; | |
133 | } else { | |
134 | data = 0; | |
135 | } | |
136 | ||
137 | return data; | |
138 | } | |
139 | ||
140 | /* | |
141 | * We return whether this has been successful - this is used in the probe to | |
142 | * ensure we have a valid card. | |
143 | */ | |
144 | int pio2_gpio_reset(struct pio2_card *card) | |
145 | { | |
146 | int retval = 0; | |
147 | int i, j; | |
148 | ||
149 | u8 data = 0; | |
150 | ||
151 | /* Zero output registers */ | |
152 | for (i = 0; i < 4; i++) { | |
153 | retval = vme_master_write(card->window, &data, 1, | |
154 | PIO2_REGS_DATA[i]); | |
155 | if (retval < 0) | |
156 | return retval; | |
157 | card->bank[i].value = 0; | |
158 | } | |
159 | ||
160 | /* Set input interrupt masks */ | |
c1fcc4c9 MW |
161 | for (i = 0; i < 4; i++) { |
162 | retval = vme_master_write(card->window, &data, 1, | |
163 | PIO2_REGS_INT_MASK[i * 2]); | |
164 | if (retval < 0) | |
165 | return retval; | |
166 | ||
9dc367bc | 167 | retval = vme_master_write(card->window, &data, 1, |
c1fcc4c9 | 168 | PIO2_REGS_INT_MASK[(i * 2) + 1]); |
9dc367bc MW |
169 | if (retval < 0) |
170 | return retval; | |
171 | ||
172 | for (j = 0; j < 8; j++) | |
173 | card->bank[i].irq[j] = NONE; | |
174 | } | |
175 | ||
176 | /* Ensure all I/O interrupts are cleared */ | |
177 | for (i = 0; i < 4; i++) { | |
178 | do { | |
179 | retval = vme_master_read(card->window, &data, 1, | |
180 | PIO2_REGS_INT_STAT[i]); | |
181 | if (retval < 0) | |
182 | return retval; | |
183 | } while (data != 0); | |
184 | } | |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
bf3a85be | 189 | int __devinit pio2_gpio_init(struct pio2_card *card) |
9dc367bc MW |
190 | { |
191 | int retval = 0; | |
192 | char *label; | |
193 | ||
194 | label = kmalloc(PIO2_NUM_CHANNELS, GFP_KERNEL); | |
195 | if (label == NULL) { | |
196 | dev_err(&card->vdev->dev, "Unable to allocate GPIO label\n"); | |
197 | return -ENOMEM; | |
198 | } | |
199 | ||
200 | sprintf(label, "%s@%s", driver_name, dev_name(&card->vdev->dev)); | |
201 | card->gc.label = label; | |
202 | ||
203 | card->gc.ngpio = PIO2_NUM_CHANNELS; | |
204 | /* Dynamic allocation of base */ | |
205 | card->gc.base = -1; | |
206 | /* Setup pointers to chip functions */ | |
207 | card->gc.direction_input = pio2_gpio_dir_in; | |
208 | card->gc.direction_output = pio2_gpio_dir_out; | |
209 | card->gc.get = pio2_gpio_get; | |
210 | card->gc.set = pio2_gpio_set; | |
211 | ||
212 | /* This function adds a memory mapped GPIO chip */ | |
213 | retval = gpiochip_add(&(card->gc)); | |
214 | if (retval) { | |
215 | dev_err(&card->vdev->dev, "Unable to register GPIO\n"); | |
216 | kfree(card->gc.label); | |
217 | } | |
218 | ||
219 | return retval; | |
220 | }; | |
221 | ||
bf3a85be | 222 | void pio2_gpio_exit(struct pio2_card *card) |
9dc367bc MW |
223 | { |
224 | const char *label = card->gc.label; | |
225 | ||
226 | if (gpiochip_remove(&(card->gc))) | |
227 | dev_err(&card->vdev->dev, "Failed to remove GPIO"); | |
228 | ||
229 | kfree(label); | |
230 | } | |
231 |