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