19f806850SThomas 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 107*e42615ecSMatti Vaittinen if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset)) 108*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 109*e42615ecSMatti Vaittinen 110*e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 111d22fcde0SGuenter Roeck } 112d22fcde0SGuenter Roeck 113d22fcde0SGuenter Roeck static int kempld_gpio_pincount(struct kempld_device_data *pld) 114d22fcde0SGuenter Roeck { 115d22fcde0SGuenter Roeck u16 evt, evt_back; 116d22fcde0SGuenter Roeck 117d22fcde0SGuenter Roeck kempld_get_mutex(pld); 118d22fcde0SGuenter Roeck 119d22fcde0SGuenter Roeck /* Backup event register as it might be already initialized */ 120d22fcde0SGuenter Roeck evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 121d22fcde0SGuenter Roeck /* Clear event register */ 122d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); 123d22fcde0SGuenter Roeck /* Read back event register */ 124d22fcde0SGuenter Roeck evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 125d22fcde0SGuenter Roeck /* Restore event register */ 126d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); 127d22fcde0SGuenter Roeck 128d22fcde0SGuenter Roeck kempld_release_mutex(pld); 129d22fcde0SGuenter Roeck 130d22fcde0SGuenter Roeck return evt ? __ffs(evt) : 16; 131d22fcde0SGuenter Roeck } 132d22fcde0SGuenter Roeck 133d22fcde0SGuenter Roeck static int kempld_gpio_probe(struct platform_device *pdev) 134d22fcde0SGuenter Roeck { 135d22fcde0SGuenter Roeck struct device *dev = &pdev->dev; 136d22fcde0SGuenter Roeck struct kempld_device_data *pld = dev_get_drvdata(dev->parent); 137e56aee18SJingoo Han struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); 138d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio; 139d22fcde0SGuenter Roeck struct gpio_chip *chip; 140d22fcde0SGuenter Roeck int ret; 141d22fcde0SGuenter Roeck 142d22fcde0SGuenter Roeck if (pld->info.spec_major < 2) { 143d22fcde0SGuenter Roeck dev_err(dev, 144d22fcde0SGuenter Roeck "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); 145d22fcde0SGuenter Roeck return -ENODEV; 146d22fcde0SGuenter Roeck } 147d22fcde0SGuenter Roeck 148d22fcde0SGuenter Roeck gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); 149afeb7b45SVarka Bhadram if (!gpio) 150d22fcde0SGuenter Roeck return -ENOMEM; 151d22fcde0SGuenter Roeck 152d22fcde0SGuenter Roeck gpio->pld = pld; 153d22fcde0SGuenter Roeck 154d22fcde0SGuenter Roeck platform_set_drvdata(pdev, gpio); 155d22fcde0SGuenter Roeck 156d22fcde0SGuenter Roeck chip = &gpio->chip; 157d22fcde0SGuenter Roeck chip->label = "gpio-kempld"; 158d22fcde0SGuenter Roeck chip->owner = THIS_MODULE; 15958383c78SLinus Walleij chip->parent = dev; 1609fb1f39eSLinus Walleij chip->can_sleep = true; 161d22fcde0SGuenter Roeck if (pdata && pdata->gpio_base) 162d22fcde0SGuenter Roeck chip->base = pdata->gpio_base; 163d22fcde0SGuenter Roeck else 164d22fcde0SGuenter Roeck chip->base = -1; 165d22fcde0SGuenter Roeck chip->direction_input = kempld_gpio_direction_input; 166d22fcde0SGuenter Roeck chip->direction_output = kempld_gpio_direction_output; 167d22fcde0SGuenter Roeck chip->get_direction = kempld_gpio_get_direction; 168d22fcde0SGuenter Roeck chip->get = kempld_gpio_get; 169d22fcde0SGuenter Roeck chip->set = kempld_gpio_set; 170d22fcde0SGuenter Roeck chip->ngpio = kempld_gpio_pincount(pld); 171d22fcde0SGuenter Roeck if (chip->ngpio == 0) { 172d22fcde0SGuenter Roeck dev_err(dev, "No GPIO pins detected\n"); 173d22fcde0SGuenter Roeck return -ENODEV; 174d22fcde0SGuenter Roeck } 175d22fcde0SGuenter Roeck 1767b697b3aSLaxman Dewangan ret = devm_gpiochip_add_data(dev, chip, gpio); 177d22fcde0SGuenter Roeck if (ret) { 178d22fcde0SGuenter Roeck dev_err(dev, "Could not register GPIO chip\n"); 179d22fcde0SGuenter Roeck return ret; 180d22fcde0SGuenter Roeck } 181d22fcde0SGuenter Roeck 182d22fcde0SGuenter Roeck dev_info(dev, "GPIO functionality initialized with %d pins\n", 183d22fcde0SGuenter Roeck chip->ngpio); 184d22fcde0SGuenter Roeck 185d22fcde0SGuenter Roeck return 0; 186d22fcde0SGuenter Roeck } 187d22fcde0SGuenter Roeck 188d22fcde0SGuenter Roeck static struct platform_driver kempld_gpio_driver = { 189d22fcde0SGuenter Roeck .driver = { 19081e9df2cSMichael Brunner .name = "kempld-gpio", 191d22fcde0SGuenter Roeck }, 192d22fcde0SGuenter Roeck .probe = kempld_gpio_probe, 193d22fcde0SGuenter Roeck }; 194d22fcde0SGuenter Roeck 195d22fcde0SGuenter Roeck module_platform_driver(kempld_gpio_driver); 196d22fcde0SGuenter Roeck 197d22fcde0SGuenter Roeck MODULE_DESCRIPTION("KEM PLD GPIO Driver"); 198d22fcde0SGuenter Roeck MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); 199d22fcde0SGuenter Roeck MODULE_LICENSE("GPL"); 2009288ecadSAxel Lin MODULE_ALIAS("platform:kempld-gpio"); 201