1d22fcde0SGuenter Roeck /* 2d22fcde0SGuenter Roeck * Kontron PLD GPIO driver 3d22fcde0SGuenter Roeck * 4d22fcde0SGuenter Roeck * Copyright (c) 2010-2013 Kontron Europe GmbH 5d22fcde0SGuenter Roeck * Author: Michael Brunner <michael.brunner@kontron.com> 6d22fcde0SGuenter Roeck * 7d22fcde0SGuenter Roeck * This program is free software; you can redistribute it and/or modify 8d22fcde0SGuenter Roeck * it under the terms of the GNU General Public License 2 as published 9d22fcde0SGuenter Roeck * by the Free Software Foundation. 10d22fcde0SGuenter Roeck * 11d22fcde0SGuenter Roeck * This program is distributed in the hope that it will be useful, 12d22fcde0SGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d22fcde0SGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14d22fcde0SGuenter Roeck * GNU General Public License for more details. 15d22fcde0SGuenter Roeck */ 16d22fcde0SGuenter Roeck 17d22fcde0SGuenter Roeck #include <linux/init.h> 18d22fcde0SGuenter Roeck #include <linux/kernel.h> 19d22fcde0SGuenter Roeck #include <linux/module.h> 20d22fcde0SGuenter Roeck #include <linux/bitops.h> 21d22fcde0SGuenter Roeck #include <linux/errno.h> 22d22fcde0SGuenter Roeck #include <linux/platform_device.h> 23d22fcde0SGuenter Roeck #include <linux/gpio.h> 24d22fcde0SGuenter Roeck #include <linux/mfd/kempld.h> 25d22fcde0SGuenter Roeck 26d22fcde0SGuenter Roeck #define KEMPLD_GPIO_MAX_NUM 16 27459b8180SJavier Martinez Canillas #define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) 28d22fcde0SGuenter Roeck #define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) 29d22fcde0SGuenter Roeck #define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) 30d22fcde0SGuenter Roeck #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 31d22fcde0SGuenter Roeck #define KEMPLD_GPIO_IEN 0x4A 32d22fcde0SGuenter Roeck 33d22fcde0SGuenter Roeck struct kempld_gpio_data { 34d22fcde0SGuenter Roeck struct gpio_chip chip; 35d22fcde0SGuenter Roeck struct kempld_device_data *pld; 36d22fcde0SGuenter Roeck }; 37d22fcde0SGuenter Roeck 38d22fcde0SGuenter Roeck /* 39d22fcde0SGuenter Roeck * Set or clear GPIO bit 40d22fcde0SGuenter Roeck * kempld_get_mutex must be called prior to calling this function. 41d22fcde0SGuenter Roeck */ 42d22fcde0SGuenter Roeck static void kempld_gpio_bitop(struct kempld_device_data *pld, 43d22fcde0SGuenter Roeck u8 reg, u8 bit, u8 val) 44d22fcde0SGuenter Roeck { 45d22fcde0SGuenter Roeck u8 status; 46d22fcde0SGuenter Roeck 47d22fcde0SGuenter Roeck status = kempld_read8(pld, reg); 48d22fcde0SGuenter Roeck if (val) 492e7f6122SBrunner Michael status |= KEMPLD_GPIO_MASK(bit); 50d22fcde0SGuenter Roeck else 512e7f6122SBrunner Michael status &= ~KEMPLD_GPIO_MASK(bit); 52d22fcde0SGuenter Roeck kempld_write8(pld, reg, status); 53d22fcde0SGuenter Roeck } 54d22fcde0SGuenter Roeck 55d22fcde0SGuenter Roeck static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit) 56d22fcde0SGuenter Roeck { 57d22fcde0SGuenter Roeck u8 status; 58d22fcde0SGuenter Roeck 59d22fcde0SGuenter Roeck kempld_get_mutex(pld); 60d22fcde0SGuenter Roeck status = kempld_read8(pld, reg); 61d22fcde0SGuenter Roeck kempld_release_mutex(pld); 62d22fcde0SGuenter Roeck 632e7f6122SBrunner Michael return !!(status & KEMPLD_GPIO_MASK(bit)); 64d22fcde0SGuenter Roeck } 65d22fcde0SGuenter Roeck 66d22fcde0SGuenter Roeck static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset) 67d22fcde0SGuenter Roeck { 681f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 69d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 70d22fcde0SGuenter Roeck 71e9639436SLinus Walleij return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); 72d22fcde0SGuenter Roeck } 73d22fcde0SGuenter Roeck 74d22fcde0SGuenter Roeck static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 75d22fcde0SGuenter Roeck { 761f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 77d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 78d22fcde0SGuenter Roeck 79d22fcde0SGuenter Roeck kempld_get_mutex(pld); 802e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); 81d22fcde0SGuenter Roeck kempld_release_mutex(pld); 82d22fcde0SGuenter Roeck } 83d22fcde0SGuenter Roeck 84d22fcde0SGuenter Roeck static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 85d22fcde0SGuenter Roeck { 861f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 87d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 88d22fcde0SGuenter Roeck 89d22fcde0SGuenter Roeck kempld_get_mutex(pld); 902e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); 91d22fcde0SGuenter Roeck kempld_release_mutex(pld); 92d22fcde0SGuenter Roeck 93d22fcde0SGuenter Roeck return 0; 94d22fcde0SGuenter Roeck } 95d22fcde0SGuenter Roeck 96d22fcde0SGuenter Roeck static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 97d22fcde0SGuenter Roeck int value) 98d22fcde0SGuenter Roeck { 991f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 100d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 101d22fcde0SGuenter Roeck 102d22fcde0SGuenter Roeck kempld_get_mutex(pld); 1032e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); 1042e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); 105d22fcde0SGuenter Roeck kempld_release_mutex(pld); 106d22fcde0SGuenter Roeck 107d22fcde0SGuenter Roeck return 0; 108d22fcde0SGuenter Roeck } 109d22fcde0SGuenter Roeck 110d22fcde0SGuenter Roeck static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 111d22fcde0SGuenter Roeck { 1121f89bccdSLinus Walleij struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 113d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 114d22fcde0SGuenter Roeck 115f230e8ffSMichael Brunner return !kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); 116d22fcde0SGuenter Roeck } 117d22fcde0SGuenter Roeck 118d22fcde0SGuenter Roeck static int kempld_gpio_pincount(struct kempld_device_data *pld) 119d22fcde0SGuenter Roeck { 120d22fcde0SGuenter Roeck u16 evt, evt_back; 121d22fcde0SGuenter Roeck 122d22fcde0SGuenter Roeck kempld_get_mutex(pld); 123d22fcde0SGuenter Roeck 124d22fcde0SGuenter Roeck /* Backup event register as it might be already initialized */ 125d22fcde0SGuenter Roeck evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 126d22fcde0SGuenter Roeck /* Clear event register */ 127d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); 128d22fcde0SGuenter Roeck /* Read back event register */ 129d22fcde0SGuenter Roeck evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 130d22fcde0SGuenter Roeck /* Restore event register */ 131d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); 132d22fcde0SGuenter Roeck 133d22fcde0SGuenter Roeck kempld_release_mutex(pld); 134d22fcde0SGuenter Roeck 135d22fcde0SGuenter Roeck return evt ? __ffs(evt) : 16; 136d22fcde0SGuenter Roeck } 137d22fcde0SGuenter Roeck 138d22fcde0SGuenter Roeck static int kempld_gpio_probe(struct platform_device *pdev) 139d22fcde0SGuenter Roeck { 140d22fcde0SGuenter Roeck struct device *dev = &pdev->dev; 141d22fcde0SGuenter Roeck struct kempld_device_data *pld = dev_get_drvdata(dev->parent); 142e56aee18SJingoo Han struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); 143d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio; 144d22fcde0SGuenter Roeck struct gpio_chip *chip; 145d22fcde0SGuenter Roeck int ret; 146d22fcde0SGuenter Roeck 147d22fcde0SGuenter Roeck if (pld->info.spec_major < 2) { 148d22fcde0SGuenter Roeck dev_err(dev, 149d22fcde0SGuenter Roeck "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); 150d22fcde0SGuenter Roeck return -ENODEV; 151d22fcde0SGuenter Roeck } 152d22fcde0SGuenter Roeck 153d22fcde0SGuenter Roeck gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); 154afeb7b45SVarka Bhadram if (!gpio) 155d22fcde0SGuenter Roeck return -ENOMEM; 156d22fcde0SGuenter Roeck 157d22fcde0SGuenter Roeck gpio->pld = pld; 158d22fcde0SGuenter Roeck 159d22fcde0SGuenter Roeck platform_set_drvdata(pdev, gpio); 160d22fcde0SGuenter Roeck 161d22fcde0SGuenter Roeck chip = &gpio->chip; 162d22fcde0SGuenter Roeck chip->label = "gpio-kempld"; 163d22fcde0SGuenter Roeck chip->owner = THIS_MODULE; 16458383c78SLinus Walleij chip->parent = dev; 1659fb1f39eSLinus Walleij chip->can_sleep = true; 166d22fcde0SGuenter Roeck if (pdata && pdata->gpio_base) 167d22fcde0SGuenter Roeck chip->base = pdata->gpio_base; 168d22fcde0SGuenter Roeck else 169d22fcde0SGuenter Roeck chip->base = -1; 170d22fcde0SGuenter Roeck chip->direction_input = kempld_gpio_direction_input; 171d22fcde0SGuenter Roeck chip->direction_output = kempld_gpio_direction_output; 172d22fcde0SGuenter Roeck chip->get_direction = kempld_gpio_get_direction; 173d22fcde0SGuenter Roeck chip->get = kempld_gpio_get; 174d22fcde0SGuenter Roeck chip->set = kempld_gpio_set; 175d22fcde0SGuenter Roeck chip->ngpio = kempld_gpio_pincount(pld); 176d22fcde0SGuenter Roeck if (chip->ngpio == 0) { 177d22fcde0SGuenter Roeck dev_err(dev, "No GPIO pins detected\n"); 178d22fcde0SGuenter Roeck return -ENODEV; 179d22fcde0SGuenter Roeck } 180d22fcde0SGuenter Roeck 181*7b697b3aSLaxman Dewangan ret = devm_gpiochip_add_data(dev, chip, gpio); 182d22fcde0SGuenter Roeck if (ret) { 183d22fcde0SGuenter Roeck dev_err(dev, "Could not register GPIO chip\n"); 184d22fcde0SGuenter Roeck return ret; 185d22fcde0SGuenter Roeck } 186d22fcde0SGuenter Roeck 187d22fcde0SGuenter Roeck dev_info(dev, "GPIO functionality initialized with %d pins\n", 188d22fcde0SGuenter Roeck chip->ngpio); 189d22fcde0SGuenter Roeck 190d22fcde0SGuenter Roeck return 0; 191d22fcde0SGuenter Roeck } 192d22fcde0SGuenter Roeck 193d22fcde0SGuenter Roeck static struct platform_driver kempld_gpio_driver = { 194d22fcde0SGuenter Roeck .driver = { 19581e9df2cSMichael Brunner .name = "kempld-gpio", 196d22fcde0SGuenter Roeck }, 197d22fcde0SGuenter Roeck .probe = kempld_gpio_probe, 198d22fcde0SGuenter Roeck }; 199d22fcde0SGuenter Roeck 200d22fcde0SGuenter Roeck module_platform_driver(kempld_gpio_driver); 201d22fcde0SGuenter Roeck 202d22fcde0SGuenter Roeck MODULE_DESCRIPTION("KEM PLD GPIO Driver"); 203d22fcde0SGuenter Roeck MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); 204d22fcde0SGuenter Roeck MODULE_LICENSE("GPL"); 2059288ecadSAxel Lin MODULE_ALIAS("platform:kempld-gpio"); 206