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 24*5134272fSQingtao Cao /* 25*5134272fSQingtao Cao * The Device Configuration and UART Configuration Registers 26*5134272fSQingtao Cao * for each UART channel take 1KB of memory address space. 27*5134272fSQingtao Cao */ 28*5134272fSQingtao Cao #define EXAR_UART_CHANNEL_SIZE 0x400 29*5134272fSQingtao 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; 40*5134272fSQingtao Cao /* 41*5134272fSQingtao Cao * The offset to the cascaded device's (if existing) 42*5134272fSQingtao Cao * Device Configuration Registers. 43*5134272fSQingtao Cao */ 44*5134272fSQingtao 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 { 50*5134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 51*5134272fSQingtao Cao unsigned int cascaded = offset / 16; 52*5134272fSQingtao Cao unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 53*5134272fSQingtao Cao 54*5134272fSQingtao 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 { 60*5134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 61*5134272fSQingtao Cao unsigned int cascaded = offset / 16; 62*5134272fSQingtao Cao unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 63*5134272fSQingtao Cao 64*5134272fSQingtao 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 { 70*5134272fSQingtao Cao unsigned int pin = exar_gpio->first_pin + (offset % 16); 71*5134272fSQingtao Cao 72*5134272fSQingtao 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, 14436fb7218SBartosz Golaszewski }; 14536fb7218SBartosz Golaszewski 1466596e59eSSudip Mukherjee static int gpio_exar_probe(struct platform_device *pdev) 1476596e59eSSudip Mukherjee { 1480c2c7e13SBartosz Golaszewski struct device *dev = &pdev->dev; 1490c2c7e13SBartosz Golaszewski struct pci_dev *pcidev = to_pci_dev(dev->parent); 1506596e59eSSudip Mukherjee struct exar_gpio_chip *exar_gpio; 151380b1e2fSJan Kiszka u32 first_pin, ngpios; 1526596e59eSSudip Mukherjee void __iomem *p; 1536596e59eSSudip Mukherjee int index, ret; 1546596e59eSSudip Mukherjee 1556596e59eSSudip Mukherjee /* 1568847f5f9SJan Kiszka * The UART driver must have mapped region 0 prior to registering this 1578847f5f9SJan Kiszka * device - use it. 1586596e59eSSudip Mukherjee */ 1598847f5f9SJan Kiszka p = pcim_iomap_table(pcidev)[0]; 1606596e59eSSudip Mukherjee if (!p) 1616596e59eSSudip Mukherjee return -ENOMEM; 1626596e59eSSudip Mukherjee 1630c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); 164380b1e2fSJan Kiszka if (ret) 165380b1e2fSJan Kiszka return ret; 166380b1e2fSJan Kiszka 1670c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "ngpios", &ngpios); 168380b1e2fSJan Kiszka if (ret) 169380b1e2fSJan Kiszka return ret; 170380b1e2fSJan Kiszka 1710c2c7e13SBartosz Golaszewski exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 1726596e59eSSudip Mukherjee if (!exar_gpio) 1736596e59eSSudip Mukherjee return -ENOMEM; 1746596e59eSSudip Mukherjee 17536fb7218SBartosz Golaszewski /* 176*5134272fSQingtao Cao * If cascaded, secondary xr17v354 or xr17v358 have the same amount 177*5134272fSQingtao Cao * of MPIOs as their primaries and the last 4 bits of the primary's 178*5134272fSQingtao Cao * PCI Device ID is the number of its UART channels. 179*5134272fSQingtao Cao */ 180*5134272fSQingtao Cao if (pcidev->device & GENMASK(15, 12)) { 181*5134272fSQingtao Cao ngpios += ngpios; 182*5134272fSQingtao Cao exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) * 183*5134272fSQingtao Cao EXAR_UART_CHANNEL_SIZE; 184*5134272fSQingtao Cao } 185*5134272fSQingtao Cao 186*5134272fSQingtao Cao /* 18736fb7218SBartosz Golaszewski * We don't need to check the return values of mmio regmap operations (unless 18836fb7218SBartosz Golaszewski * the regmap has a clock attached which is not the case here). 18936fb7218SBartosz Golaszewski */ 19036fb7218SBartosz Golaszewski exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); 19136fb7218SBartosz Golaszewski if (IS_ERR(exar_gpio->regmap)) 19236fb7218SBartosz Golaszewski return PTR_ERR(exar_gpio->regmap); 1936596e59eSSudip Mukherjee 1948e27c2aeSBartosz Golaszewski index = ida_alloc(&ida_index, GFP_KERNEL); 19536fb7218SBartosz Golaszewski if (index < 0) 19636fb7218SBartosz Golaszewski return index; 1976596e59eSSudip Mukherjee 1985300ebb6SBartosz Golaszewski ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio); 1995300ebb6SBartosz Golaszewski if (ret) 2005300ebb6SBartosz Golaszewski return ret; 2015300ebb6SBartosz Golaszewski 2026596e59eSSudip Mukherjee sprintf(exar_gpio->name, "exar_gpio%d", index); 2036596e59eSSudip Mukherjee exar_gpio->gpio_chip.label = exar_gpio->name; 2040c2c7e13SBartosz Golaszewski exar_gpio->gpio_chip.parent = dev; 2056596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_output = exar_direction_output; 2066596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_input = exar_direction_input; 2076596e59eSSudip Mukherjee exar_gpio->gpio_chip.get_direction = exar_get_direction; 2086596e59eSSudip Mukherjee exar_gpio->gpio_chip.get = exar_get_value; 2096596e59eSSudip Mukherjee exar_gpio->gpio_chip.set = exar_set_value; 2106596e59eSSudip Mukherjee exar_gpio->gpio_chip.base = -1; 211380b1e2fSJan Kiszka exar_gpio->gpio_chip.ngpio = ngpios; 2126596e59eSSudip Mukherjee exar_gpio->index = index; 213380b1e2fSJan Kiszka exar_gpio->first_pin = first_pin; 2146596e59eSSudip Mukherjee 2150c2c7e13SBartosz Golaszewski ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 2166596e59eSSudip Mukherjee if (ret) 2175300ebb6SBartosz Golaszewski return ret; 2186596e59eSSudip Mukherjee 2196596e59eSSudip Mukherjee platform_set_drvdata(pdev, exar_gpio); 2206596e59eSSudip Mukherjee 2216596e59eSSudip Mukherjee return 0; 2226596e59eSSudip Mukherjee } 2236596e59eSSudip Mukherjee 2246596e59eSSudip Mukherjee static struct platform_driver gpio_exar_driver = { 2256596e59eSSudip Mukherjee .probe = gpio_exar_probe, 2266596e59eSSudip Mukherjee .driver = { 2276596e59eSSudip Mukherjee .name = DRIVER_NAME, 2286596e59eSSudip Mukherjee }, 2296596e59eSSudip Mukherjee }; 2306596e59eSSudip Mukherjee 2316596e59eSSudip Mukherjee module_platform_driver(gpio_exar_driver); 2326596e59eSSudip Mukherjee 2336596e59eSSudip Mukherjee MODULE_ALIAS("platform:" DRIVER_NAME); 2346596e59eSSudip Mukherjee MODULE_DESCRIPTION("Exar GPIO driver"); 2356596e59eSSudip Mukherjee MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 2366596e59eSSudip Mukherjee MODULE_LICENSE("GPL"); 237