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 { 68d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio 69d22fcde0SGuenter Roeck = container_of(chip, struct kempld_gpio_data, chip); 70d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 71d22fcde0SGuenter Roeck 722e7f6122SBrunner Michael return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); 73d22fcde0SGuenter Roeck } 74d22fcde0SGuenter Roeck 75d22fcde0SGuenter Roeck static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 76d22fcde0SGuenter Roeck { 77d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio 78d22fcde0SGuenter Roeck = container_of(chip, struct kempld_gpio_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_LVL_NUM(offset), offset, value); 83d22fcde0SGuenter Roeck kempld_release_mutex(pld); 84d22fcde0SGuenter Roeck } 85d22fcde0SGuenter Roeck 86d22fcde0SGuenter Roeck static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 87d22fcde0SGuenter Roeck { 88d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio 89d22fcde0SGuenter Roeck = container_of(chip, struct kempld_gpio_data, chip); 90d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 91d22fcde0SGuenter Roeck 92d22fcde0SGuenter Roeck kempld_get_mutex(pld); 932e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); 94d22fcde0SGuenter Roeck kempld_release_mutex(pld); 95d22fcde0SGuenter Roeck 96d22fcde0SGuenter Roeck return 0; 97d22fcde0SGuenter Roeck } 98d22fcde0SGuenter Roeck 99d22fcde0SGuenter Roeck static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 100d22fcde0SGuenter Roeck int value) 101d22fcde0SGuenter Roeck { 102d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio 103d22fcde0SGuenter Roeck = container_of(chip, struct kempld_gpio_data, chip); 104d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 105d22fcde0SGuenter Roeck 106d22fcde0SGuenter Roeck kempld_get_mutex(pld); 1072e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); 1082e7f6122SBrunner Michael kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); 109d22fcde0SGuenter Roeck kempld_release_mutex(pld); 110d22fcde0SGuenter Roeck 111d22fcde0SGuenter Roeck return 0; 112d22fcde0SGuenter Roeck } 113d22fcde0SGuenter Roeck 114d22fcde0SGuenter Roeck static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 115d22fcde0SGuenter Roeck { 116d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio 117d22fcde0SGuenter Roeck = container_of(chip, struct kempld_gpio_data, chip); 118d22fcde0SGuenter Roeck struct kempld_device_data *pld = gpio->pld; 119d22fcde0SGuenter Roeck 1202e7f6122SBrunner Michael return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset); 121d22fcde0SGuenter Roeck } 122d22fcde0SGuenter Roeck 123d22fcde0SGuenter Roeck static int kempld_gpio_pincount(struct kempld_device_data *pld) 124d22fcde0SGuenter Roeck { 125d22fcde0SGuenter Roeck u16 evt, evt_back; 126d22fcde0SGuenter Roeck 127d22fcde0SGuenter Roeck kempld_get_mutex(pld); 128d22fcde0SGuenter Roeck 129d22fcde0SGuenter Roeck /* Backup event register as it might be already initialized */ 130d22fcde0SGuenter Roeck evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 131d22fcde0SGuenter Roeck /* Clear event register */ 132d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000); 133d22fcde0SGuenter Roeck /* Read back event register */ 134d22fcde0SGuenter Roeck evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 135d22fcde0SGuenter Roeck /* Restore event register */ 136d22fcde0SGuenter Roeck kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back); 137d22fcde0SGuenter Roeck 138d22fcde0SGuenter Roeck kempld_release_mutex(pld); 139d22fcde0SGuenter Roeck 140d22fcde0SGuenter Roeck return evt ? __ffs(evt) : 16; 141d22fcde0SGuenter Roeck } 142d22fcde0SGuenter Roeck 143d22fcde0SGuenter Roeck static int kempld_gpio_probe(struct platform_device *pdev) 144d22fcde0SGuenter Roeck { 145d22fcde0SGuenter Roeck struct device *dev = &pdev->dev; 146d22fcde0SGuenter Roeck struct kempld_device_data *pld = dev_get_drvdata(dev->parent); 147e56aee18SJingoo Han struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); 148d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio; 149d22fcde0SGuenter Roeck struct gpio_chip *chip; 150d22fcde0SGuenter Roeck int ret; 151d22fcde0SGuenter Roeck 152d22fcde0SGuenter Roeck if (pld->info.spec_major < 2) { 153d22fcde0SGuenter Roeck dev_err(dev, 154d22fcde0SGuenter Roeck "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n"); 155d22fcde0SGuenter Roeck return -ENODEV; 156d22fcde0SGuenter Roeck } 157d22fcde0SGuenter Roeck 158d22fcde0SGuenter Roeck gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); 159*afeb7b45SVarka Bhadram if (!gpio) 160d22fcde0SGuenter Roeck return -ENOMEM; 161d22fcde0SGuenter Roeck 162d22fcde0SGuenter Roeck gpio->pld = pld; 163d22fcde0SGuenter Roeck 164d22fcde0SGuenter Roeck platform_set_drvdata(pdev, gpio); 165d22fcde0SGuenter Roeck 166d22fcde0SGuenter Roeck chip = &gpio->chip; 167d22fcde0SGuenter Roeck chip->label = "gpio-kempld"; 168d22fcde0SGuenter Roeck chip->owner = THIS_MODULE; 169d22fcde0SGuenter Roeck chip->dev = dev; 1709fb1f39eSLinus Walleij chip->can_sleep = true; 171d22fcde0SGuenter Roeck if (pdata && pdata->gpio_base) 172d22fcde0SGuenter Roeck chip->base = pdata->gpio_base; 173d22fcde0SGuenter Roeck else 174d22fcde0SGuenter Roeck chip->base = -1; 175d22fcde0SGuenter Roeck chip->direction_input = kempld_gpio_direction_input; 176d22fcde0SGuenter Roeck chip->direction_output = kempld_gpio_direction_output; 177d22fcde0SGuenter Roeck chip->get_direction = kempld_gpio_get_direction; 178d22fcde0SGuenter Roeck chip->get = kempld_gpio_get; 179d22fcde0SGuenter Roeck chip->set = kempld_gpio_set; 180d22fcde0SGuenter Roeck chip->ngpio = kempld_gpio_pincount(pld); 181d22fcde0SGuenter Roeck if (chip->ngpio == 0) { 182d22fcde0SGuenter Roeck dev_err(dev, "No GPIO pins detected\n"); 183d22fcde0SGuenter Roeck return -ENODEV; 184d22fcde0SGuenter Roeck } 185d22fcde0SGuenter Roeck 186d22fcde0SGuenter Roeck ret = gpiochip_add(chip); 187d22fcde0SGuenter Roeck if (ret) { 188d22fcde0SGuenter Roeck dev_err(dev, "Could not register GPIO chip\n"); 189d22fcde0SGuenter Roeck return ret; 190d22fcde0SGuenter Roeck } 191d22fcde0SGuenter Roeck 192d22fcde0SGuenter Roeck dev_info(dev, "GPIO functionality initialized with %d pins\n", 193d22fcde0SGuenter Roeck chip->ngpio); 194d22fcde0SGuenter Roeck 195d22fcde0SGuenter Roeck return 0; 196d22fcde0SGuenter Roeck } 197d22fcde0SGuenter Roeck 198d22fcde0SGuenter Roeck static int kempld_gpio_remove(struct platform_device *pdev) 199d22fcde0SGuenter Roeck { 200d22fcde0SGuenter Roeck struct kempld_gpio_data *gpio = platform_get_drvdata(pdev); 201d22fcde0SGuenter Roeck 2029f5132aeSabdoulaye berthe gpiochip_remove(&gpio->chip); 2039f5132aeSabdoulaye berthe return 0; 204d22fcde0SGuenter Roeck } 205d22fcde0SGuenter Roeck 206d22fcde0SGuenter Roeck static struct platform_driver kempld_gpio_driver = { 207d22fcde0SGuenter Roeck .driver = { 20881e9df2cSMichael Brunner .name = "kempld-gpio", 209d22fcde0SGuenter Roeck }, 210d22fcde0SGuenter Roeck .probe = kempld_gpio_probe, 211d22fcde0SGuenter Roeck .remove = kempld_gpio_remove, 212d22fcde0SGuenter Roeck }; 213d22fcde0SGuenter Roeck 214d22fcde0SGuenter Roeck module_platform_driver(kempld_gpio_driver); 215d22fcde0SGuenter Roeck 216d22fcde0SGuenter Roeck MODULE_DESCRIPTION("KEM PLD GPIO Driver"); 217d22fcde0SGuenter Roeck MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); 218d22fcde0SGuenter Roeck MODULE_LICENSE("GPL"); 2199288ecadSAxel Lin MODULE_ALIAS("platform:kempld-gpio"); 220