1*9f806850SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d22fcde0SGuenter Roeck /* 3d22fcde0SGuenter Roeck * Kontron PLD GPIO driver 4d22fcde0SGuenter Roeck * 5d22fcde0SGuenter Roeck * Copyright (c) 2010-2013 Kontron Europe GmbH 6d22fcde0SGuenter Roeck * Author: Michael Brunner <michael.brunner@kontron.com> 7d22fcde0SGuenter Roeck */ 8d22fcde0SGuenter Roeck 9d22fcde0SGuenter Roeck #include <linux/init.h> 10d22fcde0SGuenter Roeck #include <linux/kernel.h> 11d22fcde0SGuenter Roeck #include <linux/module.h> 12d22fcde0SGuenter Roeck #include <linux/bitops.h> 13d22fcde0SGuenter Roeck #include <linux/errno.h> 14d22fcde0SGuenter Roeck #include <linux/platform_device.h> 15430f6499SLinus Walleij #include <linux/gpio/driver.h> 16d22fcde0SGuenter Roeck #include <linux/mfd/kempld.h> 17d22fcde0SGuenter Roeck 18d22fcde0SGuenter Roeck #define KEMPLD_GPIO_MAX_NUM 16 19459b8180SJavier Martinez Canillas #define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) 20d22fcde0SGuenter Roeck #define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) 21d22fcde0SGuenter Roeck #define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) 22d22fcde0SGuenter Roeck #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 23d22fcde0SGuenter Roeck #define KEMPLD_GPIO_IEN 0x4A 24d22fcde0SGuenter Roeck 25d22fcde0SGuenter Roeck struct kempld_gpio_data { 26d22fcde0SGuenter Roeck struct gpio_chip chip; 27d22fcde0SGuenter Roeck struct kempld_device_data *pld; 28d22fcde0SGuenter Roeck }; 29d22fcde0SGuenter Roeck 30d22fcde0SGuenter Roeck /* 31d22fcde0SGuenter Roeck * Set or clear GPIO bit 32d22fcde0SGuenter Roeck * kempld_get_mutex must be called prior to calling this function. 33d22fcde0SGuenter Roeck */ 34d22fcde0SGuenter Roeck static void kempld_gpio_bitop(struct kempld_device_data *pld, 35d22fcde0SGuenter Roeck u8 reg, u8 bit, u8 val) 36d22fcde0SGuenter Roeck { 37d22fcde0SGuenter Roeck u8 status; 38d22fcde0SGuenter Roeck 39d22fcde0SGuenter Roeck status = kempld_read8(pld, reg); 40d22fcde0SGuenter Roeck if (val) 412e7f6122SBrunner Michael status |= KEMPLD_GPIO_MASK(bit); 42d22fcde0SGuenter Roeck else 432e7f6122SBrunner Michael status &= ~KEMPLD_GPIO_MASK(bit); 44d22fcde0SGuenter Roeck kempld_write8(pld, reg, status); 45d22fcde0SGuenter Roeck } 46d22fcde0SGuenter Roeck 47d22fcde0SGuenter Roeck static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit) 48d22fcde0SGuenter Roeck { 49d22fcde0SGuenter Roeck u8 status; 50d22fcde0SGuenter Roeck 51d22fcde0SGuenter Roeck kempld_get_mutex(pld); 52d22fcde0SGuenter Roeck status = kempld_read8(pld, reg); 53d22fcde0SGuenter Roeck kempld_release_mutex(pld); 54d22fcde0SGuenter Roeck 552e7f6122SBrunner Michael return !!(status & KEMPLD_GPIO_MASK(bit)); 56d22fcde0SGuenter Roeck } 57d22fcde0SGuenter Roeck 58d22fcde0SGuenter Roeck static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) 59d22fcde0SGuenter Roeck { 601f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 61d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 62d22fcde0SGuenter Roeck 63e9639436SLinus Walleij return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); 64d22fcde0SGuenter Roeck } 65d22fcde0SGuenter Roeck 66d22fcde0SGuenter Roeck static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 67d22fcde0SGuenter Roeck { 681f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 69d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 70d22fcde0SGuenter Roeck 71d22fcde0SGuenter Roeck kempld_get_mutex(pld); 722e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); 73d22fcde0SGuenter Roeck kempld_release_mutex(pld); 74d22fcde0SGuenter Roeck } 75d22fcde0SGuenter Roeck 76d22fcde0SGuenter Roeck static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 77d22fcde0SGuenter Roeck { 781f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 79d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 80d22fcde0SGuenter Roeck 81d22fcde0SGuenter Roeck kempld_get_mutex(pld); 822e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); 83d22fcde0SGuenter Roeck kempld_release_mutex(pld); 84d22fcde0SGuenter Roeck 85d22fcde0SGuenter Roeck return 0; 86d22fcde0SGuenter Roeck } 87d22fcde0SGuenter Roeck 88d22fcde0SGuenter Roeck static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 89d22fcde0SGuenter Roeck int value) 90d22fcde0SGuenter Roeck { 911f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 92d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 93d22fcde0SGuenter Roeck 94d22fcde0SGuenter Roeck kempld_get_mutex(pld); 952e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); 962e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); 97d22fcde0SGuenter Roeck kempld_release_mutex(pld); 98d22fcde0SGuenter Roeck 99d22fcde0SGuenter Roeck return 0; 100d22fcde0SGuenter Roeck } 101d22fcde0SGuenter Roeck 102d22fcde0SGuenter Roeck static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 103d22fcde0SGuenter Roeck { 1041f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 105d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 106d22fcde0SGuenter Roeck 107f230e8ffSMichael Brunner return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); 108d22fcde0SGuenter Roeck } 109d22fcde0SGuenter Roeck 110d22fcde0SGuenter Roeck static int kempld_gpio_pincount(struct kempld_device_data *pld) 111d22fcde0SGuenter Roeck { 112d22fcde0SGuenter Roeck u16 evt, evt_back; 113d22fcde0SGuenter Roeck 114d22fcde0SGuenter Roeck kempld_get_mutex(pld); 115d22fcde0SGuenter Roeck 116d22fcde0SGuenter Roeck /* Backup event register as it might be already initialized */ 117d22fcde0SGuenter Roeck evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 118d22fcde0SGuenter Roeck /* Clear event register */ 119d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); 120d22fcde0SGuenter Roeck /* Read back event register */ 121d22fcde0SGuenter Roeck evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 122d22fcde0SGuenter Roeck /* Restore event register */ 123d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); 124d22fcde0SGuenter Roeck 125d22fcde0SGuenter Roeck kempld_release_mutex(pld); 126d22fcde0SGuenter Roeck 127d22fcde0SGuenter Roeck return evt ? __ffs(evt) : 16; 128d22fcde0SGuenter Roeck } 129d22fcde0SGuenter Roeck 130d22fcde0SGuenter Roeck static int kempld_gpio_probe(struct platform_device *pdev) 131d22fcde0SGuenter Roeck { 132d22fcde0SGuenter Roeck struct device *dev = &pdev->dev; 133d22fcde0SGuenter Roeck struct kempld_device_data *pld = dev_get_drvdata(dev->parent); 134e56aee18SJingoo Han struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); 135d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio; 136d22fcde0SGuenter Roeck struct gpio_chip *chip; 137d22fcde0SGuenter Roeck int ret; 138d22fcde0SGuenter Roeck 139d22fcde0SGuenter Roeck if (pld->info.spec_major < 2) { 140d22fcde0SGuenter Roeck dev_err(dev, 141d22fcde0SGuenter Roeck "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); 142d22fcde0SGuenter Roeck return -ENODEV; 143d22fcde0SGuenter Roeck } 144d22fcde0SGuenter Roeck 145d22fcde0SGuenter Roeck gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); 146afeb7b45SVarka Bhadram if (!gpio) 147d22fcde0SGuenter Roeck return -ENOMEM; 148d22fcde0SGuenter Roeck 149d22fcde0SGuenter Roeck gpio->pld = pld; 150d22fcde0SGuenter Roeck 151d22fcde0SGuenter Roeck platform_set_drvdata(pdev, gpio); 152d22fcde0SGuenter Roeck 153d22fcde0SGuenter Roeck chip = &gpio->chip; 154d22fcde0SGuenter Roeck chip->label = "gpio-kempld"; 155d22fcde0SGuenter Roeck chip->owner = THIS_MODULE; 15658383c78SLinus Walleij chip->parent = dev; 1579fb1f39eSLinus Walleij chip->can_sleep = true; 158d22fcde0SGuenter Roeck if (pdata && pdata->gpio_base) 159d22fcde0SGuenter Roeck chip->base = pdata->gpio_base; 160d22fcde0SGuenter Roeck else 161d22fcde0SGuenter Roeck chip->base = -1; 162d22fcde0SGuenter Roeck chip->direction_input = kempld_gpio_direction_input; 163d22fcde0SGuenter Roeck chip->direction_output = kempld_gpio_direction_output; 164d22fcde0SGuenter Roeck chip->get_direction = kempld_gpio_get_direction; 165d22fcde0SGuenter Roeck chip->get = kempld_gpio_get; 166d22fcde0SGuenter Roeck chip->set = kempld_gpio_set; 167d22fcde0SGuenter Roeck chip->ngpio = kempld_gpio_pincount(pld); 168d22fcde0SGuenter Roeck if (chip->ngpio == 0) { 169d22fcde0SGuenter Roeck dev_err(dev, "No GPIO pins detected\n"); 170d22fcde0SGuenter Roeck return -ENODEV; 171d22fcde0SGuenter Roeck } 172d22fcde0SGuenter Roeck 1737b697b3aSLaxman Dewangan ret = devm_gpiochip_add_data(dev, chip, gpio); 174d22fcde0SGuenter Roeck if (ret) { 175d22fcde0SGuenter Roeck dev_err(dev, "Could not register GPIO chip\n"); 176d22fcde0SGuenter Roeck return ret; 177d22fcde0SGuenter Roeck } 178d22fcde0SGuenter Roeck 179d22fcde0SGuenter Roeck dev_info(dev, "GPIO functionality initialized with %d pins\n", 180d22fcde0SGuenter Roeck chip->ngpio); 181d22fcde0SGuenter Roeck 182d22fcde0SGuenter Roeck return 0; 183d22fcde0SGuenter Roeck } 184d22fcde0SGuenter Roeck 185d22fcde0SGuenter Roeck static struct platform_driver kempld_gpio_driver = { 186d22fcde0SGuenter Roeck .driver = { 18781e9df2cSMichael Brunner .name = "kempld-gpio", 188d22fcde0SGuenter Roeck }, 189d22fcde0SGuenter Roeck .probe = kempld_gpio_probe, 190d22fcde0SGuenter Roeck }; 191d22fcde0SGuenter Roeck 192d22fcde0SGuenter Roeck module_platform_driver(kempld_gpio_driver); 193d22fcde0SGuenter Roeck 194d22fcde0SGuenter Roeck MODULE_DESCRIPTION("KEM PLD GPIO Driver"); 195d22fcde0SGuenter Roeck MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); 196d22fcde0SGuenter Roeck MODULE_LICENSE("GPL"); 1979288ecadSAxel Lin MODULE_ALIAS("platform:kempld-gpio"); 198