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 245134272fSQingtao Cao /* 255134272fSQingtao Cao * The Device Configuration and UART Configuration Registers 265134272fSQingtao Cao * for each UART channel take 1KB of memory address space. 275134272fSQingtao Cao */ 285134272fSQingtao Cao #define EXAR_UART_CHANNEL_SIZE 0x400 295134272fSQingtao Cao 306596e59eSSudip Mukherjee #define DRIVER_NAME "gpio_exar" 316596e59eSSudip Mukherjee 326596e59eSSudip Mukherjee static DEFINE_IDA(ida_index); 336596e59eSSudip Mukherjee 346596e59eSSudip Mukherjee struct exar_gpio_chip { 356596e59eSSudip Mukherjee struct gpio_chip gpio_chip; 3636fb7218SBartosz Golaszewski struct regmap *regmap; 376596e59eSSudip Mukherjee int index; 386596e59eSSudip Mukherjee char name[20]; 39380b1e2fSJan Kiszka unsigned int first_pin; 405134272fSQingtao Cao /* 415134272fSQingtao Cao * The offset to the cascaded device's (if existing) 425134272fSQingtao Cao * Device Configuration Registers. 435134272fSQingtao Cao */ 445134272fSQingtao Cao unsigned int cascaded_offset; 456596e59eSSudip Mukherjee }; 466596e59eSSudip Mukherjee 47696868d0SBartosz Golaszewski static unsigned int 48696868d0SBartosz Golaszewski exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) 49696868d0SBartosz Golaszewski { 505134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 515134272fSQingtao Cao unsigned int cascaded = offset / 16; 525134272fSQingtao Cao unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 535134272fSQingtao Cao 545134272fSQingtao Cao return addr + (cascaded ? exar_gpio->cascaded_offset : 0); 55696868d0SBartosz Golaszewski } 56696868d0SBartosz Golaszewski 57696868d0SBartosz Golaszewski static unsigned int 58696868d0SBartosz Golaszewski exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) 59696868d0SBartosz Golaszewski { 605134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 615134272fSQingtao Cao unsigned int cascaded = offset / 16; 625134272fSQingtao Cao unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 635134272fSQingtao Cao 645134272fSQingtao Cao return addr + (cascaded ? exar_gpio->cascaded_offset : 0); 65696868d0SBartosz Golaszewski } 66696868d0SBartosz Golaszewski 67696868d0SBartosz Golaszewski static unsigned int 68696868d0SBartosz Golaszewski exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset) 69696868d0SBartosz Golaszewski { 705134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 715134272fSQingtao Cao 725134272fSQingtao Cao return pin % 8; 73696868d0SBartosz Golaszewski } 74696868d0SBartosz Golaszewski 756596e59eSSudip Mukherjee static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) 766596e59eSSudip Mukherjee { 77380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 78696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 79696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 806596e59eSSudip Mukherjee 8136fb7218SBartosz Golaszewski if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))) 82e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 83e42615ecSMatti Vaittinen 84e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 856596e59eSSudip Mukherjee } 866596e59eSSudip Mukherjee 876596e59eSSudip Mukherjee static int exar_get_value(struct gpio_chip *chip, unsigned int offset) 886596e59eSSudip Mukherjee { 89380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 90696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 91696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 926596e59eSSudip Mukherjee 9336fb7218SBartosz Golaszewski return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))); 946596e59eSSudip Mukherjee } 956596e59eSSudip Mukherjee 966596e59eSSudip Mukherjee static void exar_set_value(struct gpio_chip *chip, unsigned int offset, 976596e59eSSudip Mukherjee int value) 986596e59eSSudip Mukherjee { 99380b1e2fSJan Kiszka struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 100696868d0SBartosz Golaszewski unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 101696868d0SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 1026596e59eSSudip Mukherjee 10336fb7218SBartosz Golaszewski if (value) 10436fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 10536fb7218SBartosz Golaszewski else 10636fb7218SBartosz Golaszewski regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 1076596e59eSSudip Mukherjee } 1086596e59eSSudip Mukherjee 109eddeae07SAxel Lin static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, 110eddeae07SAxel Lin int value) 111eddeae07SAxel Lin { 11236fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 11336fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 11436fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 11536fb7218SBartosz Golaszewski 116eddeae07SAxel Lin exar_set_value(chip, offset, value); 11736fb7218SBartosz Golaszewski regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 11836fb7218SBartosz Golaszewski 11936fb7218SBartosz Golaszewski return 0; 120eddeae07SAxel Lin } 121eddeae07SAxel Lin 122eddeae07SAxel Lin static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 123eddeae07SAxel Lin { 12436fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 12536fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 12636fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 12736fb7218SBartosz Golaszewski 12836fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 12936fb7218SBartosz Golaszewski 13036fb7218SBartosz Golaszewski return 0; 131eddeae07SAxel Lin } 132eddeae07SAxel Lin 1335300ebb6SBartosz Golaszewski static void exar_devm_ida_free(void *data) 1345300ebb6SBartosz Golaszewski { 1355300ebb6SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = data; 1365300ebb6SBartosz Golaszewski 1375300ebb6SBartosz Golaszewski ida_free(&ida_index, exar_gpio->index); 1385300ebb6SBartosz Golaszewski } 1395300ebb6SBartosz Golaszewski 14036fb7218SBartosz Golaszewski static const struct regmap_config exar_regmap_config = { 14136fb7218SBartosz Golaszewski .name = "exar-gpio", 14236fb7218SBartosz Golaszewski .reg_bits = 16, 14336fb7218SBartosz Golaszewski .val_bits = 8, 144*b4e83d36SAndy Shevchenko .io_port = true, 14536fb7218SBartosz Golaszewski }; 14636fb7218SBartosz Golaszewski 1476596e59eSSudip Mukherjee static int gpio_exar_probe(struct platform_device *pdev) 1486596e59eSSudip Mukherjee { 1490c2c7e13SBartosz Golaszewski struct device *dev = &pdev->dev; 1500c2c7e13SBartosz Golaszewski struct pci_dev *pcidev = to_pci_dev(dev->parent); 1516596e59eSSudip Mukherjee struct exar_gpio_chip *exar_gpio; 152380b1e2fSJan Kiszka u32 first_pin, ngpios; 1536596e59eSSudip Mukherjee void __iomem *p; 1546596e59eSSudip Mukherjee int index, ret; 1556596e59eSSudip Mukherjee 1566596e59eSSudip Mukherjee /* 1578847f5f9SJan Kiszka * The UART driver must have mapped region 0 prior to registering this 1588847f5f9SJan Kiszka * device - use it. 1596596e59eSSudip Mukherjee */ 1608847f5f9SJan Kiszka p = pcim_iomap_table(pcidev)[0]; 1616596e59eSSudip Mukherjee if (!p) 1626596e59eSSudip Mukherjee return -ENOMEM; 1636596e59eSSudip Mukherjee 1640c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); 165380b1e2fSJan Kiszka if (ret) 166380b1e2fSJan Kiszka return ret; 167380b1e2fSJan Kiszka 1680c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "ngpios", &ngpios); 169380b1e2fSJan Kiszka if (ret) 170380b1e2fSJan Kiszka return ret; 171380b1e2fSJan Kiszka 1720c2c7e13SBartosz Golaszewski exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 1736596e59eSSudip Mukherjee if (!exar_gpio) 1746596e59eSSudip Mukherjee return -ENOMEM; 1756596e59eSSudip Mukherjee 17636fb7218SBartosz Golaszewski /* 1775134272fSQingtao Cao * If cascaded, secondary xr17v354 or xr17v358 have the same amount 1785134272fSQingtao Cao * of MPIOs as their primaries and the last 4 bits of the primary's 1795134272fSQingtao Cao * PCI Device ID is the number of its UART channels. 1805134272fSQingtao Cao */ 1815134272fSQingtao Cao if (pcidev->device & GENMASK(15, 12)) { 1825134272fSQingtao Cao ngpios += ngpios; 1835134272fSQingtao Cao exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) * 1845134272fSQingtao Cao EXAR_UART_CHANNEL_SIZE; 1855134272fSQingtao Cao } 1865134272fSQingtao Cao 1875134272fSQingtao Cao /* 18836fb7218SBartosz Golaszewski * We don't need to check the return values of mmio regmap operations (unless 18936fb7218SBartosz Golaszewski * the regmap has a clock attached which is not the case here). 19036fb7218SBartosz Golaszewski */ 19136fb7218SBartosz Golaszewski exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); 19236fb7218SBartosz Golaszewski if (IS_ERR(exar_gpio->regmap)) 19336fb7218SBartosz Golaszewski return PTR_ERR(exar_gpio->regmap); 1946596e59eSSudip Mukherjee 1958e27c2aeSBartosz Golaszewski index = ida_alloc(&ida_index, GFP_KERNEL); 19636fb7218SBartosz Golaszewski if (index < 0) 19736fb7218SBartosz Golaszewski return index; 1986596e59eSSudip Mukherjee 1995300ebb6SBartosz Golaszewski ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio); 2005300ebb6SBartosz Golaszewski if (ret) 2015300ebb6SBartosz Golaszewski return ret; 2025300ebb6SBartosz Golaszewski 2036596e59eSSudip Mukherjee sprintf(exar_gpio->name, "exar_gpio%d", index); 2046596e59eSSudip Mukherjee exar_gpio->gpio_chip.label = exar_gpio->name; 2050c2c7e13SBartosz Golaszewski exar_gpio->gpio_chip.parent = dev; 2066596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_output = exar_direction_output; 2076596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_input = exar_direction_input; 2086596e59eSSudip Mukherjee exar_gpio->gpio_chip.get_direction = exar_get_direction; 2096596e59eSSudip Mukherjee exar_gpio->gpio_chip.get = exar_get_value; 2106596e59eSSudip Mukherjee exar_gpio->gpio_chip.set = exar_set_value; 2116596e59eSSudip Mukherjee exar_gpio->gpio_chip.base = -1; 212380b1e2fSJan Kiszka exar_gpio->gpio_chip.ngpio = ngpios; 2136596e59eSSudip Mukherjee exar_gpio->index = index; 214380b1e2fSJan Kiszka exar_gpio->first_pin = first_pin; 2156596e59eSSudip Mukherjee 2160c2c7e13SBartosz Golaszewski ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 2176596e59eSSudip Mukherjee if (ret) 2185300ebb6SBartosz Golaszewski return ret; 2196596e59eSSudip Mukherjee 2206596e59eSSudip Mukherjee platform_set_drvdata(pdev, exar_gpio); 2216596e59eSSudip Mukherjee 2226596e59eSSudip Mukherjee return 0; 2236596e59eSSudip Mukherjee } 2246596e59eSSudip Mukherjee 2256596e59eSSudip Mukherjee static struct platform_driver gpio_exar_driver = { 2266596e59eSSudip Mukherjee .probe = gpio_exar_probe, 2276596e59eSSudip Mukherjee .driver = { 2286596e59eSSudip Mukherjee .name = DRIVER_NAME, 2296596e59eSSudip Mukherjee }, 2306596e59eSSudip Mukherjee }; 2316596e59eSSudip Mukherjee 2326596e59eSSudip Mukherjee module_platform_driver(gpio_exar_driver); 2336596e59eSSudip Mukherjee 2346596e59eSSudip Mukherjee MODULE_ALIAS("platform:" DRIVER_NAME); 2356596e59eSSudip Mukherjee MODULE_DESCRIPTION("Exar GPIO driver"); 2366596e59eSSudip Mukherjee MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 2376596e59eSSudip Mukherjee MODULE_LICENSE("GPL"); 238