xref: /openbmc/linux/drivers/gpio/gpio-gpio-mm.c (revision 949506dc)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26ea5dcdfSWilliam Breathitt Gray /*
36ea5dcdfSWilliam Breathitt Gray  * GPIO driver for the Diamond Systems GPIO-MM
46ea5dcdfSWilliam Breathitt Gray  * Copyright (C) 2016 William Breathitt Gray
56ea5dcdfSWilliam Breathitt Gray  *
66ea5dcdfSWilliam Breathitt Gray  * This driver supports the following Diamond Systems devices: GPIO-MM and
76ea5dcdfSWilliam Breathitt Gray  * GPIO-MM-12.
86ea5dcdfSWilliam Breathitt Gray  */
96ea5dcdfSWilliam Breathitt Gray #include <linux/device.h>
106ea5dcdfSWilliam Breathitt Gray #include <linux/errno.h>
116ea5dcdfSWilliam Breathitt Gray #include <linux/gpio/driver.h>
126ea5dcdfSWilliam Breathitt Gray #include <linux/io.h>
136ea5dcdfSWilliam Breathitt Gray #include <linux/ioport.h>
146ea5dcdfSWilliam Breathitt Gray #include <linux/isa.h>
156ea5dcdfSWilliam Breathitt Gray #include <linux/kernel.h>
166ea5dcdfSWilliam Breathitt Gray #include <linux/module.h>
176ea5dcdfSWilliam Breathitt Gray #include <linux/moduleparam.h>
18*949506dcSWilliam Breathitt Gray 
19*949506dcSWilliam Breathitt Gray #include "gpio-i8255.h"
20*949506dcSWilliam Breathitt Gray 
21*949506dcSWilliam Breathitt Gray MODULE_IMPORT_NS(I8255);
226ea5dcdfSWilliam Breathitt Gray 
236ea5dcdfSWilliam Breathitt Gray #define GPIOMM_EXTENT 8
246ea5dcdfSWilliam Breathitt Gray #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
256ea5dcdfSWilliam Breathitt Gray 
266ea5dcdfSWilliam Breathitt Gray static unsigned int base[MAX_NUM_GPIOMM];
276ea5dcdfSWilliam Breathitt Gray static unsigned int num_gpiomm;
28d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
296ea5dcdfSWilliam Breathitt Gray MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
306ea5dcdfSWilliam Breathitt Gray 
31*949506dcSWilliam Breathitt Gray #define GPIOMM_NUM_PPI 2
32*949506dcSWilliam Breathitt Gray 
336ea5dcdfSWilliam Breathitt Gray /**
346ea5dcdfSWilliam Breathitt Gray  * struct gpiomm_gpio - GPIO device private data structure
356ea5dcdfSWilliam Breathitt Gray  * @chip:		instance of the gpio_chip
36*949506dcSWilliam Breathitt Gray  * @ppi_state:		Programmable Peripheral Interface group states
37*949506dcSWilliam Breathitt Gray  * @ppi:		Programmable Peripheral Interface groups
386ea5dcdfSWilliam Breathitt Gray  */
396ea5dcdfSWilliam Breathitt Gray struct gpiomm_gpio {
406ea5dcdfSWilliam Breathitt Gray 	struct gpio_chip chip;
41*949506dcSWilliam Breathitt Gray 	struct i8255_state ppi_state[GPIOMM_NUM_PPI];
42*949506dcSWilliam Breathitt Gray 	struct i8255 __iomem *ppi;
436ea5dcdfSWilliam Breathitt Gray };
446ea5dcdfSWilliam Breathitt Gray 
456ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
466ea5dcdfSWilliam Breathitt Gray 	unsigned int offset)
476ea5dcdfSWilliam Breathitt Gray {
486ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
496ea5dcdfSWilliam Breathitt Gray 
50*949506dcSWilliam Breathitt Gray 	if (i8255_get_direction(gpiommgpio->ppi_state, offset))
51e42615ecSMatti Vaittinen 		return GPIO_LINE_DIRECTION_IN;
52e42615ecSMatti Vaittinen 
53e42615ecSMatti Vaittinen 	return GPIO_LINE_DIRECTION_OUT;
546ea5dcdfSWilliam Breathitt Gray }
556ea5dcdfSWilliam Breathitt Gray 
566ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
576ea5dcdfSWilliam Breathitt Gray 	unsigned int offset)
586ea5dcdfSWilliam Breathitt Gray {
596ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
606ea5dcdfSWilliam Breathitt Gray 
61*949506dcSWilliam Breathitt Gray 	i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
626ea5dcdfSWilliam Breathitt Gray 
636ea5dcdfSWilliam Breathitt Gray 	return 0;
646ea5dcdfSWilliam Breathitt Gray }
656ea5dcdfSWilliam Breathitt Gray 
666ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
676ea5dcdfSWilliam Breathitt Gray 	unsigned int offset, int value)
686ea5dcdfSWilliam Breathitt Gray {
696ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
706ea5dcdfSWilliam Breathitt Gray 
71*949506dcSWilliam Breathitt Gray 	i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
72*949506dcSWilliam Breathitt Gray 			       value);
736ea5dcdfSWilliam Breathitt Gray 
746ea5dcdfSWilliam Breathitt Gray 	return 0;
756ea5dcdfSWilliam Breathitt Gray }
766ea5dcdfSWilliam Breathitt Gray 
776ea5dcdfSWilliam Breathitt Gray static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
786ea5dcdfSWilliam Breathitt Gray {
796ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
806ea5dcdfSWilliam Breathitt Gray 
81*949506dcSWilliam Breathitt Gray 	return i8255_get(gpiommgpio->ppi, offset);
826ea5dcdfSWilliam Breathitt Gray }
836ea5dcdfSWilliam Breathitt Gray 
8441b25131SWilliam Breathitt Gray static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
8541b25131SWilliam Breathitt Gray 	unsigned long *bits)
8641b25131SWilliam Breathitt Gray {
8741b25131SWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
8841b25131SWilliam Breathitt Gray 
89*949506dcSWilliam Breathitt Gray 	i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
9041b25131SWilliam Breathitt Gray 
9141b25131SWilliam Breathitt Gray 	return 0;
9241b25131SWilliam Breathitt Gray }
9341b25131SWilliam Breathitt Gray 
946ea5dcdfSWilliam Breathitt Gray static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
956ea5dcdfSWilliam Breathitt Gray 	int value)
966ea5dcdfSWilliam Breathitt Gray {
976ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
986ea5dcdfSWilliam Breathitt Gray 
99*949506dcSWilliam Breathitt Gray 	i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
1006ea5dcdfSWilliam Breathitt Gray }
1016ea5dcdfSWilliam Breathitt Gray 
10265502a12SWilliam Breathitt Gray static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
10365502a12SWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
10465502a12SWilliam Breathitt Gray {
10565502a12SWilliam Breathitt Gray 	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
10665502a12SWilliam Breathitt Gray 
107*949506dcSWilliam Breathitt Gray 	i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
108*949506dcSWilliam Breathitt Gray 			   chip->ngpio);
10965502a12SWilliam Breathitt Gray }
11065502a12SWilliam Breathitt Gray 
111210b4bdeSWilliam Breathitt Gray #define GPIOMM_NGPIO 48
112210b4bdeSWilliam Breathitt Gray static const char *gpiomm_names[GPIOMM_NGPIO] = {
113210b4bdeSWilliam Breathitt Gray 	"Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
114210b4bdeSWilliam Breathitt Gray 	"Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
115210b4bdeSWilliam Breathitt Gray 	"Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
116210b4bdeSWilliam Breathitt Gray 	"Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
117210b4bdeSWilliam Breathitt Gray 	"Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
118210b4bdeSWilliam Breathitt Gray 	"Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
119210b4bdeSWilliam Breathitt Gray 	"Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
120210b4bdeSWilliam Breathitt Gray 	"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
121210b4bdeSWilliam Breathitt Gray };
122210b4bdeSWilliam Breathitt Gray 
123*949506dcSWilliam Breathitt Gray static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
124*949506dcSWilliam Breathitt Gray 			    struct i8255_state *const ppi_state)
125*949506dcSWilliam Breathitt Gray {
126*949506dcSWilliam Breathitt Gray 	const unsigned long ngpio = 24;
127*949506dcSWilliam Breathitt Gray 	const unsigned long mask = GENMASK(ngpio - 1, 0);
128*949506dcSWilliam Breathitt Gray 	const unsigned long bits = 0;
129*949506dcSWilliam Breathitt Gray 	unsigned long i;
130*949506dcSWilliam Breathitt Gray 
131*949506dcSWilliam Breathitt Gray 	/* Initialize all GPIO to output 0 */
132*949506dcSWilliam Breathitt Gray 	for (i = 0; i < GPIOMM_NUM_PPI; i++) {
133*949506dcSWilliam Breathitt Gray 		i8255_mode0_output(&ppi[i]);
134*949506dcSWilliam Breathitt Gray 		i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
135*949506dcSWilliam Breathitt Gray 	}
136*949506dcSWilliam Breathitt Gray }
137*949506dcSWilliam Breathitt Gray 
1386ea5dcdfSWilliam Breathitt Gray static int gpiomm_probe(struct device *dev, unsigned int id)
1396ea5dcdfSWilliam Breathitt Gray {
1406ea5dcdfSWilliam Breathitt Gray 	struct gpiomm_gpio *gpiommgpio;
1416ea5dcdfSWilliam Breathitt Gray 	const char *const name = dev_name(dev);
1426ea5dcdfSWilliam Breathitt Gray 	int err;
1436ea5dcdfSWilliam Breathitt Gray 
1446ea5dcdfSWilliam Breathitt Gray 	gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
1456ea5dcdfSWilliam Breathitt Gray 	if (!gpiommgpio)
1466ea5dcdfSWilliam Breathitt Gray 		return -ENOMEM;
1476ea5dcdfSWilliam Breathitt Gray 
1486ea5dcdfSWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
1496ea5dcdfSWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
1506ea5dcdfSWilliam Breathitt Gray 			base[id], base[id] + GPIOMM_EXTENT);
1516ea5dcdfSWilliam Breathitt Gray 		return -EBUSY;
1526ea5dcdfSWilliam Breathitt Gray 	}
1536ea5dcdfSWilliam Breathitt Gray 
154*949506dcSWilliam Breathitt Gray 	gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
155*949506dcSWilliam Breathitt Gray 	if (!gpiommgpio->ppi)
15654c8e251SWilliam Breathitt Gray 		return -ENOMEM;
15754c8e251SWilliam Breathitt Gray 
1586ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.label = name;
1596ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.parent = dev;
1606ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.owner = THIS_MODULE;
1616ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.base = -1;
162210b4bdeSWilliam Breathitt Gray 	gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
163210b4bdeSWilliam Breathitt Gray 	gpiommgpio->chip.names = gpiomm_names;
1646ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
1656ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
1666ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
1676ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.get = gpiomm_gpio_get;
16841b25131SWilliam Breathitt Gray 	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
1696ea5dcdfSWilliam Breathitt Gray 	gpiommgpio->chip.set = gpiomm_gpio_set;
17065502a12SWilliam Breathitt Gray 	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
1716ea5dcdfSWilliam Breathitt Gray 
172*949506dcSWilliam Breathitt Gray 	i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
173*949506dcSWilliam Breathitt Gray 	gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
1746ea5dcdfSWilliam Breathitt Gray 
1752141b0a1SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
1766ea5dcdfSWilliam Breathitt Gray 	if (err) {
1776ea5dcdfSWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
1786ea5dcdfSWilliam Breathitt Gray 		return err;
1796ea5dcdfSWilliam Breathitt Gray 	}
1806ea5dcdfSWilliam Breathitt Gray 
1816ea5dcdfSWilliam Breathitt Gray 	return 0;
1826ea5dcdfSWilliam Breathitt Gray }
1836ea5dcdfSWilliam Breathitt Gray 
1846ea5dcdfSWilliam Breathitt Gray static struct isa_driver gpiomm_driver = {
1856ea5dcdfSWilliam Breathitt Gray 	.probe = gpiomm_probe,
1866ea5dcdfSWilliam Breathitt Gray 	.driver = {
1876ea5dcdfSWilliam Breathitt Gray 		.name = "gpio-mm"
1886ea5dcdfSWilliam Breathitt Gray 	},
1896ea5dcdfSWilliam Breathitt Gray };
1906ea5dcdfSWilliam Breathitt Gray 
1916ea5dcdfSWilliam Breathitt Gray module_isa_driver(gpiomm_driver, num_gpiomm);
1926ea5dcdfSWilliam Breathitt Gray 
1936ea5dcdfSWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1946ea5dcdfSWilliam Breathitt Gray MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
1956ea5dcdfSWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
196