xref: /linux/drivers/gpio/gpio-gpio-mm.c (revision e65e175b07bef5974045cc42238de99057669ca7)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * GPIO driver for the Diamond Systems GPIO-MM
4  * Copyright (C) 2016 William Breathitt Gray
5  *
6  * This driver supports the following Diamond Systems devices: GPIO-MM and
7  * GPIO-MM-12.
8  */
9 #include <linux/device.h>
10 #include <linux/errno.h>
11 #include <linux/gpio/driver.h>
12 #include <linux/io.h>
13 #include <linux/ioport.h>
14 #include <linux/isa.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 
19 #include "gpio-i8255.h"
20 
21 MODULE_IMPORT_NS(I8255);
22 
23 #define GPIOMM_EXTENT 8
24 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
25 
26 static unsigned int base[MAX_NUM_GPIOMM];
27 static unsigned int num_gpiomm;
28 module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
29 MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
30 
31 #define GPIOMM_NUM_PPI 2
32 
33 /**
34  * struct gpiomm_gpio - GPIO device private data structure
35  * @chip:		instance of the gpio_chip
36  * @ppi_state:		Programmable Peripheral Interface group states
37  * @ppi:		Programmable Peripheral Interface groups
38  */
39 struct gpiomm_gpio {
40 	struct gpio_chip chip;
41 	struct i8255_state ppi_state[GPIOMM_NUM_PPI];
42 	struct i8255 __iomem *ppi;
43 };
44 
45 static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
46 	unsigned int offset)
47 {
48 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
49 
50 	if (i8255_get_direction(gpiommgpio->ppi_state, offset))
51 		return GPIO_LINE_DIRECTION_IN;
52 
53 	return GPIO_LINE_DIRECTION_OUT;
54 }
55 
56 static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
57 	unsigned int offset)
58 {
59 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
60 
61 	i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
62 
63 	return 0;
64 }
65 
66 static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
67 	unsigned int offset, int value)
68 {
69 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
70 
71 	i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
72 			       value);
73 
74 	return 0;
75 }
76 
77 static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
78 {
79 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
80 
81 	return i8255_get(gpiommgpio->ppi, offset);
82 }
83 
84 static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
85 	unsigned long *bits)
86 {
87 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
88 
89 	i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
90 
91 	return 0;
92 }
93 
94 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
95 	int value)
96 {
97 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
98 
99 	i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
100 }
101 
102 static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
103 	unsigned long *mask, unsigned long *bits)
104 {
105 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
106 
107 	i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
108 			   chip->ngpio);
109 }
110 
111 #define GPIOMM_NGPIO 48
112 static const char *gpiomm_names[GPIOMM_NGPIO] = {
113 	"Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
114 	"Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
115 	"Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
116 	"Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
117 	"Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
118 	"Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
119 	"Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
120 	"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
121 };
122 
123 static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
124 			    struct i8255_state *const ppi_state)
125 {
126 	const unsigned long ngpio = 24;
127 	const unsigned long mask = GENMASK(ngpio - 1, 0);
128 	const unsigned long bits = 0;
129 	unsigned long i;
130 
131 	/* Initialize all GPIO to output 0 */
132 	for (i = 0; i < GPIOMM_NUM_PPI; i++) {
133 		i8255_mode0_output(&ppi[i]);
134 		i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
135 	}
136 }
137 
138 static int gpiomm_probe(struct device *dev, unsigned int id)
139 {
140 	struct gpiomm_gpio *gpiommgpio;
141 	const char *const name = dev_name(dev);
142 	int err;
143 
144 	gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
145 	if (!gpiommgpio)
146 		return -ENOMEM;
147 
148 	if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
149 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
150 			base[id], base[id] + GPIOMM_EXTENT);
151 		return -EBUSY;
152 	}
153 
154 	gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
155 	if (!gpiommgpio->ppi)
156 		return -ENOMEM;
157 
158 	gpiommgpio->chip.label = name;
159 	gpiommgpio->chip.parent = dev;
160 	gpiommgpio->chip.owner = THIS_MODULE;
161 	gpiommgpio->chip.base = -1;
162 	gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
163 	gpiommgpio->chip.names = gpiomm_names;
164 	gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
165 	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
166 	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
167 	gpiommgpio->chip.get = gpiomm_gpio_get;
168 	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
169 	gpiommgpio->chip.set = gpiomm_gpio_set;
170 	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
171 
172 	i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
173 	gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
174 
175 	err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
176 	if (err) {
177 		dev_err(dev, "GPIO registering failed (%d)\n", err);
178 		return err;
179 	}
180 
181 	return 0;
182 }
183 
184 static struct isa_driver gpiomm_driver = {
185 	.probe = gpiomm_probe,
186 	.driver = {
187 		.name = "gpio-mm"
188 	},
189 };
190 
191 module_isa_driver(gpiomm_driver, num_gpiomm);
192 
193 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
194 MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
195 MODULE_LICENSE("GPL v2");
196