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