xref: /openbmc/linux/drivers/ssb/driver_gpio.c (revision 600485ed)
1ec43b08bSHauke Mehrtens /*
2ec43b08bSHauke Mehrtens  * Sonics Silicon Backplane
3ec43b08bSHauke Mehrtens  * GPIO driver
4ec43b08bSHauke Mehrtens  *
5ec43b08bSHauke Mehrtens  * Copyright 2011, Broadcom Corporation
6ec43b08bSHauke Mehrtens  * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
7ec43b08bSHauke Mehrtens  *
8ec43b08bSHauke Mehrtens  * Licensed under the GNU/GPL. See COPYING for details.
9ec43b08bSHauke Mehrtens  */
10ec43b08bSHauke Mehrtens 
11ec43b08bSHauke Mehrtens #include <linux/gpio.h>
12ec43b08bSHauke Mehrtens #include <linux/export.h>
13ec43b08bSHauke Mehrtens #include <linux/ssb/ssb.h>
14ec43b08bSHauke Mehrtens 
15ec43b08bSHauke Mehrtens #include "ssb_private.h"
16ec43b08bSHauke Mehrtens 
17ec43b08bSHauke Mehrtens static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip)
18ec43b08bSHauke Mehrtens {
19ec43b08bSHauke Mehrtens 	return container_of(chip, struct ssb_bus, gpio);
20ec43b08bSHauke Mehrtens }
21ec43b08bSHauke Mehrtens 
22ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
23ec43b08bSHauke Mehrtens {
24ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
25ec43b08bSHauke Mehrtens 
26ec43b08bSHauke Mehrtens 	return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
27ec43b08bSHauke Mehrtens }
28ec43b08bSHauke Mehrtens 
29ec43b08bSHauke Mehrtens static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
30ec43b08bSHauke Mehrtens 				      int value)
31ec43b08bSHauke Mehrtens {
32ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
33ec43b08bSHauke Mehrtens 
34ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
35ec43b08bSHauke Mehrtens }
36ec43b08bSHauke Mehrtens 
37ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
38ec43b08bSHauke Mehrtens 					   unsigned gpio)
39ec43b08bSHauke Mehrtens {
40ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
41ec43b08bSHauke Mehrtens 
42ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0);
43ec43b08bSHauke Mehrtens 	return 0;
44ec43b08bSHauke Mehrtens }
45ec43b08bSHauke Mehrtens 
46ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
47ec43b08bSHauke Mehrtens 					    unsigned gpio, int value)
48ec43b08bSHauke Mehrtens {
49ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
50ec43b08bSHauke Mehrtens 
51ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio);
52ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
53ec43b08bSHauke Mehrtens 	return 0;
54ec43b08bSHauke Mehrtens }
55ec43b08bSHauke Mehrtens 
56ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
57ec43b08bSHauke Mehrtens {
58ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
59ec43b08bSHauke Mehrtens 
60ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0);
61ec43b08bSHauke Mehrtens 	/* clear pulldown */
62ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pulldown(&bus->chipco, 1 << gpio, 0);
63ec43b08bSHauke Mehrtens 	/* Set pullup */
64ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 1 << gpio);
65ec43b08bSHauke Mehrtens 
66ec43b08bSHauke Mehrtens 	return 0;
67ec43b08bSHauke Mehrtens }
68ec43b08bSHauke Mehrtens 
69ec43b08bSHauke Mehrtens static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
70ec43b08bSHauke Mehrtens {
71ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
72ec43b08bSHauke Mehrtens 
73ec43b08bSHauke Mehrtens 	/* clear pullup */
74ec43b08bSHauke Mehrtens 	ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
75ec43b08bSHauke Mehrtens }
76ec43b08bSHauke Mehrtens 
77ec43b08bSHauke Mehrtens static int ssb_gpio_chipco_init(struct ssb_bus *bus)
78ec43b08bSHauke Mehrtens {
79ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
80ec43b08bSHauke Mehrtens 
81ec43b08bSHauke Mehrtens 	chip->label		= "ssb_chipco_gpio";
82ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
83ec43b08bSHauke Mehrtens 	chip->request		= ssb_gpio_chipco_request;
84ec43b08bSHauke Mehrtens 	chip->free		= ssb_gpio_chipco_free;
85ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_chipco_get_value;
86ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_chipco_set_value;
87ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_chipco_direction_input;
88ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_chipco_direction_output;
89ec43b08bSHauke Mehrtens 	chip->ngpio		= 16;
90ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
91ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
92ec43b08bSHauke Mehrtens 	 * a random base number. */
93ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
94ec43b08bSHauke Mehrtens 		chip->base		= 0;
95ec43b08bSHauke Mehrtens 	else
96ec43b08bSHauke Mehrtens 		chip->base		= -1;
97ec43b08bSHauke Mehrtens 
98ec43b08bSHauke Mehrtens 	return gpiochip_add(chip);
99ec43b08bSHauke Mehrtens }
100ec43b08bSHauke Mehrtens 
101ec43b08bSHauke Mehrtens #ifdef CONFIG_SSB_DRIVER_EXTIF
102ec43b08bSHauke Mehrtens 
103ec43b08bSHauke Mehrtens static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
104ec43b08bSHauke Mehrtens {
105ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
106ec43b08bSHauke Mehrtens 
107ec43b08bSHauke Mehrtens 	return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
108ec43b08bSHauke Mehrtens }
109ec43b08bSHauke Mehrtens 
110ec43b08bSHauke Mehrtens static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
111ec43b08bSHauke Mehrtens 				     int value)
112ec43b08bSHauke Mehrtens {
113ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
114ec43b08bSHauke Mehrtens 
115ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
116ec43b08bSHauke Mehrtens }
117ec43b08bSHauke Mehrtens 
118ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
119ec43b08bSHauke Mehrtens 					  unsigned gpio)
120ec43b08bSHauke Mehrtens {
121ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
122ec43b08bSHauke Mehrtens 
123ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
124ec43b08bSHauke Mehrtens 	return 0;
125ec43b08bSHauke Mehrtens }
126ec43b08bSHauke Mehrtens 
127ec43b08bSHauke Mehrtens static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
128ec43b08bSHauke Mehrtens 					   unsigned gpio, int value)
129ec43b08bSHauke Mehrtens {
130ec43b08bSHauke Mehrtens 	struct ssb_bus *bus = ssb_gpio_get_bus(chip);
131ec43b08bSHauke Mehrtens 
132ec43b08bSHauke Mehrtens 	ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
133ec43b08bSHauke Mehrtens 	ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
134ec43b08bSHauke Mehrtens 	return 0;
135ec43b08bSHauke Mehrtens }
136ec43b08bSHauke Mehrtens 
137ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
138ec43b08bSHauke Mehrtens {
139ec43b08bSHauke Mehrtens 	struct gpio_chip *chip = &bus->gpio;
140ec43b08bSHauke Mehrtens 
141ec43b08bSHauke Mehrtens 	chip->label		= "ssb_extif_gpio";
142ec43b08bSHauke Mehrtens 	chip->owner		= THIS_MODULE;
143ec43b08bSHauke Mehrtens 	chip->get		= ssb_gpio_extif_get_value;
144ec43b08bSHauke Mehrtens 	chip->set		= ssb_gpio_extif_set_value;
145ec43b08bSHauke Mehrtens 	chip->direction_input	= ssb_gpio_extif_direction_input;
146ec43b08bSHauke Mehrtens 	chip->direction_output	= ssb_gpio_extif_direction_output;
147ec43b08bSHauke Mehrtens 	chip->ngpio		= 5;
148ec43b08bSHauke Mehrtens 	/* There is just one SoC in one device and its GPIO addresses should be
149ec43b08bSHauke Mehrtens 	 * deterministic to address them more easily. The other buses could get
150ec43b08bSHauke Mehrtens 	 * a random base number. */
151ec43b08bSHauke Mehrtens 	if (bus->bustype == SSB_BUSTYPE_SSB)
152ec43b08bSHauke Mehrtens 		chip->base		= 0;
153ec43b08bSHauke Mehrtens 	else
154ec43b08bSHauke Mehrtens 		chip->base		= -1;
155ec43b08bSHauke Mehrtens 
156ec43b08bSHauke Mehrtens 	return gpiochip_add(chip);
157ec43b08bSHauke Mehrtens }
158ec43b08bSHauke Mehrtens 
159ec43b08bSHauke Mehrtens #else
160ec43b08bSHauke Mehrtens static int ssb_gpio_extif_init(struct ssb_bus *bus)
161ec43b08bSHauke Mehrtens {
162ec43b08bSHauke Mehrtens 	return -ENOTSUPP;
163ec43b08bSHauke Mehrtens }
164ec43b08bSHauke Mehrtens #endif
165ec43b08bSHauke Mehrtens 
166ec43b08bSHauke Mehrtens int ssb_gpio_init(struct ssb_bus *bus)
167ec43b08bSHauke Mehrtens {
168ec43b08bSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco))
169ec43b08bSHauke Mehrtens 		return ssb_gpio_chipco_init(bus);
170ec43b08bSHauke Mehrtens 	else if (ssb_extif_available(&bus->extif))
171ec43b08bSHauke Mehrtens 		return ssb_gpio_extif_init(bus);
172ec43b08bSHauke Mehrtens 	else
173ec43b08bSHauke Mehrtens 		SSB_WARN_ON(1);
174ec43b08bSHauke Mehrtens 
175ec43b08bSHauke Mehrtens 	return -1;
176ec43b08bSHauke Mehrtens }
177600485edSHauke Mehrtens 
178600485edSHauke Mehrtens int ssb_gpio_unregister(struct ssb_bus *bus)
179600485edSHauke Mehrtens {
180600485edSHauke Mehrtens 	if (ssb_chipco_available(&bus->chipco) ||
181600485edSHauke Mehrtens 	    ssb_extif_available(&bus->extif)) {
182600485edSHauke Mehrtens 		return gpiochip_remove(&bus->gpio);
183600485edSHauke Mehrtens 	} else {
184600485edSHauke Mehrtens 		SSB_WARN_ON(1);
185600485edSHauke Mehrtens 	}
186600485edSHauke Mehrtens 
187600485edSHauke Mehrtens 	return -1;
188600485edSHauke Mehrtens }
189