1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 26596e59eSSudip Mukherjee /* 36596e59eSSudip Mukherjee * GPIO driver for Exar XR17V35X chip 46596e59eSSudip Mukherjee * 56596e59eSSudip Mukherjee * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk> 66596e59eSSudip Mukherjee */ 71bfaf129SBartosz Golaszewski 86596e59eSSudip Mukherjee #include <linux/bitops.h> 96596e59eSSudip Mukherjee #include <linux/device.h> 106596e59eSSudip Mukherjee #include <linux/gpio/driver.h> 1126ced453SBartosz Golaszewski #include <linux/idr.h> 126596e59eSSudip Mukherjee #include <linux/init.h> 136596e59eSSudip Mukherjee #include <linux/kernel.h> 146596e59eSSudip Mukherjee #include <linux/module.h> 156596e59eSSudip Mukherjee #include <linux/pci.h> 166596e59eSSudip Mukherjee #include <linux/platform_device.h> 1736fb7218SBartosz Golaszewski #include <linux/regmap.h> 186596e59eSSudip Mukherjee 196596e59eSSudip Mukherjee #define EXAR_OFFSET_MPIOLVL_LO 0x90 206596e59eSSudip Mukherjee #define EXAR_OFFSET_MPIOSEL_LO 0x93 216596e59eSSudip Mukherjee #define EXAR_OFFSET_MPIOLVL_HI 0x96 226596e59eSSudip Mukherjee #define EXAR_OFFSET_MPIOSEL_HI 0x99 236596e59eSSudip Mukherjee 246596e59eSSudip Mukherjee #define DRIVER_NAME "gpio_exar" 256596e59eSSudip Mukherjee 266596e59eSSudip Mukherjee static DEFINE_IDA(ida_index); 276596e59eSSudip Mukherjee 286596e59eSSudip Mukherjee struct exar_gpio_chip { 296596e59eSSudip Mukherjee struct gpio_chip gpio_chip; 3036fb7218SBartosz Golaszewski struct regmap *regmap; 316596e59eSSudip Mukherjee int index; 326596e59eSSudip Mukherjee char name[20]; 33380b1e2fSJan Kiszka unsigned int first_pin; 346596e59eSSudip Mukherjee }; 356596e59eSSudip Mukherjee 36696868d0SBartosz Golaszewski static unsigned int 37696868d0SBartosz Golaszewski exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) 38696868d0SBartosz Golaszewski { 39696868d0SBartosz Golaszewski return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI 40696868d0SBartosz Golaszewski : EXAR_OFFSET_MPIOSEL_LO; 41696868d0SBartosz Golaszewski } 42696868d0SBartosz Golaszewski 43696868d0SBartosz Golaszewski static unsigned int 44696868d0SBartosz Golaszewski exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) 45696868d0SBartosz Golaszewski { 46696868d0SBartosz Golaszewski return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI 47696868d0SBartosz Golaszewski : EXAR_OFFSET_MPIOLVL_LO; 48696868d0SBartosz Golaszewski } 49696868d0SBartosz Golaszewski 50696868d0SBartosz Golaszewski static unsigned int 51696868d0SBartosz Golaszewski exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset) 52696868d0SBartosz Golaszewski { 53696868d0SBartosz Golaszewski return (offset + exar_gpio->first_pin) % 8; 54696868d0SBartosz Golaszewski } 55696868d0SBartosz Golaszewski 566596e59eSSudip Mukherjee static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) 576596e59eSSudip Mukherjee { 58380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 59696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 60696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 616596e59eSSudip Mukherjee 6236fb7218SBartosz Golaszewski if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))) 63e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 64e42615ecSMatti Vaittinen 65e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 666596e59eSSudip Mukherjee } 676596e59eSSudip Mukherjee 686596e59eSSudip Mukherjee static int exar_get_value(struct gpio_chip *chip, unsigned int offset) 696596e59eSSudip Mukherjee { 70380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 71696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 72696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 736596e59eSSudip Mukherjee 7436fb7218SBartosz Golaszewski return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))); 756596e59eSSudip Mukherjee } 766596e59eSSudip Mukherjee 776596e59eSSudip Mukherjee static void exar_set_value(struct gpio_chip *chip, unsigned int offset, 786596e59eSSudip Mukherjee int value) 796596e59eSSudip Mukherjee { 80380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 81696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 82696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 836596e59eSSudip Mukherjee 8436fb7218SBartosz Golaszewski if (value) 8536fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 8636fb7218SBartosz Golaszewski else 8736fb7218SBartosz Golaszewski regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 886596e59eSSudip Mukherjee } 896596e59eSSudip Mukherjee 90eddeae07SAxel Lin static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, 91eddeae07SAxel Lin int value) 92eddeae07SAxel Lin { 9336fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 9436fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 9536fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 9636fb7218SBartosz Golaszewski 97eddeae07SAxel Lin exar_set_value(chip, offset, value); 9836fb7218SBartosz Golaszewski regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 9936fb7218SBartosz Golaszewski 10036fb7218SBartosz Golaszewski return 0; 101eddeae07SAxel Lin } 102eddeae07SAxel Lin 103eddeae07SAxel Lin static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 104eddeae07SAxel Lin { 10536fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 10636fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 10736fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 10836fb7218SBartosz Golaszewski 10936fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 11036fb7218SBartosz Golaszewski 11136fb7218SBartosz Golaszewski return 0; 112eddeae07SAxel Lin } 113eddeae07SAxel Lin 114*5300ebb6SBartosz Golaszewski static void exar_devm_ida_free(void *data) 115*5300ebb6SBartosz Golaszewski { 116*5300ebb6SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = data; 117*5300ebb6SBartosz Golaszewski 118*5300ebb6SBartosz Golaszewski ida_free(&ida_index, exar_gpio->index); 119*5300ebb6SBartosz Golaszewski } 120*5300ebb6SBartosz Golaszewski 12136fb7218SBartosz Golaszewski static const struct regmap_config exar_regmap_config = { 12236fb7218SBartosz Golaszewski .name = "exar-gpio", 12336fb7218SBartosz Golaszewski .reg_bits = 16, 12436fb7218SBartosz Golaszewski .val_bits = 8, 12536fb7218SBartosz Golaszewski }; 12636fb7218SBartosz Golaszewski 1276596e59eSSudip Mukherjee static int gpio_exar_probe(struct platform_device *pdev) 1286596e59eSSudip Mukherjee { 1290c2c7e13SBartosz Golaszewski struct device *dev = &pdev->dev; 1300c2c7e13SBartosz Golaszewski struct pci_dev *pcidev = to_pci_dev(dev->parent); 1316596e59eSSudip Mukherjee struct exar_gpio_chip *exar_gpio; 132380b1e2fSJan Kiszka u32 first_pin, ngpios; 1336596e59eSSudip Mukherjee void __iomem *p; 1346596e59eSSudip Mukherjee int index, ret; 1356596e59eSSudip Mukherjee 1366596e59eSSudip Mukherjee /* 1378847f5f9SJan Kiszka * The UART driver must have mapped region 0 prior to registering this 1388847f5f9SJan Kiszka * device - use it. 1396596e59eSSudip Mukherjee */ 1408847f5f9SJan Kiszka p = pcim_iomap_table(pcidev)[0]; 1416596e59eSSudip Mukherjee if (!p) 1426596e59eSSudip Mukherjee return -ENOMEM; 1436596e59eSSudip Mukherjee 1440c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); 145380b1e2fSJan Kiszka if (ret) 146380b1e2fSJan Kiszka return ret; 147380b1e2fSJan Kiszka 1480c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "ngpios", &ngpios); 149380b1e2fSJan Kiszka if (ret) 150380b1e2fSJan Kiszka return ret; 151380b1e2fSJan Kiszka 1520c2c7e13SBartosz Golaszewski exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 1536596e59eSSudip Mukherjee if (!exar_gpio) 1546596e59eSSudip Mukherjee return -ENOMEM; 1556596e59eSSudip Mukherjee 15636fb7218SBartosz Golaszewski /* 15736fb7218SBartosz Golaszewski * We don't need to check the return values of mmio regmap operations (unless 15836fb7218SBartosz Golaszewski * the regmap has a clock attached which is not the case here). 15936fb7218SBartosz Golaszewski */ 16036fb7218SBartosz Golaszewski exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); 16136fb7218SBartosz Golaszewski if (IS_ERR(exar_gpio->regmap)) 16236fb7218SBartosz Golaszewski return PTR_ERR(exar_gpio->regmap); 1636596e59eSSudip Mukherjee 1648e27c2aeSBartosz Golaszewski index = ida_alloc(&ida_index, GFP_KERNEL); 16536fb7218SBartosz Golaszewski if (index < 0) 16636fb7218SBartosz Golaszewski return index; 1676596e59eSSudip Mukherjee 168*5300ebb6SBartosz Golaszewski ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio); 169*5300ebb6SBartosz Golaszewski if (ret) 170*5300ebb6SBartosz Golaszewski return ret; 171*5300ebb6SBartosz Golaszewski 1726596e59eSSudip Mukherjee sprintf(exar_gpio->name, "exar_gpio%d", index); 1736596e59eSSudip Mukherjee exar_gpio->gpio_chip.label = exar_gpio->name; 1740c2c7e13SBartosz Golaszewski exar_gpio->gpio_chip.parent = dev; 1756596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_output = exar_direction_output; 1766596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_input = exar_direction_input; 1776596e59eSSudip Mukherjee exar_gpio->gpio_chip.get_direction = exar_get_direction; 1786596e59eSSudip Mukherjee exar_gpio->gpio_chip.get = exar_get_value; 1796596e59eSSudip Mukherjee exar_gpio->gpio_chip.set = exar_set_value; 1806596e59eSSudip Mukherjee exar_gpio->gpio_chip.base = -1; 181380b1e2fSJan Kiszka exar_gpio->gpio_chip.ngpio = ngpios; 1826596e59eSSudip Mukherjee exar_gpio->index = index; 183380b1e2fSJan Kiszka exar_gpio->first_pin = first_pin; 1846596e59eSSudip Mukherjee 1850c2c7e13SBartosz Golaszewski ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 1866596e59eSSudip Mukherjee if (ret) 187*5300ebb6SBartosz Golaszewski return ret; 1886596e59eSSudip Mukherjee 1896596e59eSSudip Mukherjee platform_set_drvdata(pdev, exar_gpio); 1906596e59eSSudip Mukherjee 1916596e59eSSudip Mukherjee return 0; 1926596e59eSSudip Mukherjee } 1936596e59eSSudip Mukherjee 1946596e59eSSudip Mukherjee static struct platform_driver gpio_exar_driver = { 1956596e59eSSudip Mukherjee .probe = gpio_exar_probe, 1966596e59eSSudip Mukherjee .driver = { 1976596e59eSSudip Mukherjee .name = DRIVER_NAME, 1986596e59eSSudip Mukherjee }, 1996596e59eSSudip Mukherjee }; 2006596e59eSSudip Mukherjee 2016596e59eSSudip Mukherjee module_platform_driver(gpio_exar_driver); 2026596e59eSSudip Mukherjee 2036596e59eSSudip Mukherjee MODULE_ALIAS("platform:" DRIVER_NAME); 2046596e59eSSudip Mukherjee MODULE_DESCRIPTION("Exar GPIO driver"); 2056596e59eSSudip Mukherjee MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 2066596e59eSSudip Mukherjee MODULE_LICENSE("GPL"); 207