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