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> 17*36fb7218SBartosz 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; 30*36fb7218SBartosz 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 62*36fb7218SBartosz 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 74*36fb7218SBartosz 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 84*36fb7218SBartosz Golaszewski if (value) 85*36fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 86*36fb7218SBartosz Golaszewski else 87*36fb7218SBartosz 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 { 93*36fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 94*36fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 95*36fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 96*36fb7218SBartosz Golaszewski 97eddeae07SAxel Lin exar_set_value(chip, offset, value); 98*36fb7218SBartosz Golaszewski regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 99*36fb7218SBartosz Golaszewski 100*36fb7218SBartosz Golaszewski return 0; 101eddeae07SAxel Lin } 102eddeae07SAxel Lin 103eddeae07SAxel Lin static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 104eddeae07SAxel Lin { 105*36fb7218SBartosz Golaszewski struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 106*36fb7218SBartosz Golaszewski unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 107*36fb7218SBartosz Golaszewski unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 108*36fb7218SBartosz Golaszewski 109*36fb7218SBartosz Golaszewski regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 110*36fb7218SBartosz Golaszewski 111*36fb7218SBartosz Golaszewski return 0; 112eddeae07SAxel Lin } 113eddeae07SAxel Lin 114*36fb7218SBartosz Golaszewski static const struct regmap_config exar_regmap_config = { 115*36fb7218SBartosz Golaszewski .name = "exar-gpio", 116*36fb7218SBartosz Golaszewski .reg_bits = 16, 117*36fb7218SBartosz Golaszewski .val_bits = 8, 118*36fb7218SBartosz Golaszewski }; 119*36fb7218SBartosz Golaszewski 1206596e59eSSudip Mukherjee static int gpio_exar_probe(struct platform_device *pdev) 1216596e59eSSudip Mukherjee { 1220c2c7e13SBartosz Golaszewski struct device *dev = &pdev->dev; 1230c2c7e13SBartosz Golaszewski struct pci_dev *pcidev = to_pci_dev(dev->parent); 1246596e59eSSudip Mukherjee struct exar_gpio_chip *exar_gpio; 125380b1e2fSJan Kiszka u32 first_pin, ngpios; 1266596e59eSSudip Mukherjee void __iomem *p; 1276596e59eSSudip Mukherjee int index, ret; 1286596e59eSSudip Mukherjee 1296596e59eSSudip Mukherjee /* 1308847f5f9SJan Kiszka * The UART driver must have mapped region 0 prior to registering this 1318847f5f9SJan Kiszka * device - use it. 1326596e59eSSudip Mukherjee */ 1338847f5f9SJan Kiszka p = pcim_iomap_table(pcidev)[0]; 1346596e59eSSudip Mukherjee if (!p) 1356596e59eSSudip Mukherjee return -ENOMEM; 1366596e59eSSudip Mukherjee 1370c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); 138380b1e2fSJan Kiszka if (ret) 139380b1e2fSJan Kiszka return ret; 140380b1e2fSJan Kiszka 1410c2c7e13SBartosz Golaszewski ret = device_property_read_u32(dev, "ngpios", &ngpios); 142380b1e2fSJan Kiszka if (ret) 143380b1e2fSJan Kiszka return ret; 144380b1e2fSJan Kiszka 1450c2c7e13SBartosz Golaszewski exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 1466596e59eSSudip Mukherjee if (!exar_gpio) 1476596e59eSSudip Mukherjee return -ENOMEM; 1486596e59eSSudip Mukherjee 149*36fb7218SBartosz Golaszewski /* 150*36fb7218SBartosz Golaszewski * We don't need to check the return values of mmio regmap operations (unless 151*36fb7218SBartosz Golaszewski * the regmap has a clock attached which is not the case here). 152*36fb7218SBartosz Golaszewski */ 153*36fb7218SBartosz Golaszewski exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); 154*36fb7218SBartosz Golaszewski if (IS_ERR(exar_gpio->regmap)) 155*36fb7218SBartosz Golaszewski return PTR_ERR(exar_gpio->regmap); 1566596e59eSSudip Mukherjee 1578e27c2aeSBartosz Golaszewski index = ida_alloc(&ida_index, GFP_KERNEL); 158*36fb7218SBartosz Golaszewski if (index < 0) 159*36fb7218SBartosz Golaszewski return index; 1606596e59eSSudip Mukherjee 1616596e59eSSudip Mukherjee sprintf(exar_gpio->name, "exar_gpio%d", index); 1626596e59eSSudip Mukherjee exar_gpio->gpio_chip.label = exar_gpio->name; 1630c2c7e13SBartosz Golaszewski exar_gpio->gpio_chip.parent = dev; 1646596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_output = exar_direction_output; 1656596e59eSSudip Mukherjee exar_gpio->gpio_chip.direction_input = exar_direction_input; 1666596e59eSSudip Mukherjee exar_gpio->gpio_chip.get_direction = exar_get_direction; 1676596e59eSSudip Mukherjee exar_gpio->gpio_chip.get = exar_get_value; 1686596e59eSSudip Mukherjee exar_gpio->gpio_chip.set = exar_set_value; 1696596e59eSSudip Mukherjee exar_gpio->gpio_chip.base = -1; 170380b1e2fSJan Kiszka exar_gpio->gpio_chip.ngpio = ngpios; 1716596e59eSSudip Mukherjee exar_gpio->index = index; 172380b1e2fSJan Kiszka exar_gpio->first_pin = first_pin; 1736596e59eSSudip Mukherjee 1740c2c7e13SBartosz Golaszewski ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 1756596e59eSSudip Mukherjee if (ret) 1766596e59eSSudip Mukherjee goto err_destroy; 1776596e59eSSudip Mukherjee 1786596e59eSSudip Mukherjee platform_set_drvdata(pdev, exar_gpio); 1796596e59eSSudip Mukherjee 1806596e59eSSudip Mukherjee return 0; 1816596e59eSSudip Mukherjee 1826596e59eSSudip Mukherjee err_destroy: 1838e27c2aeSBartosz Golaszewski ida_free(&ida_index, index); 1846596e59eSSudip Mukherjee return ret; 1856596e59eSSudip Mukherjee } 1866596e59eSSudip Mukherjee 1876596e59eSSudip Mukherjee static int gpio_exar_remove(struct platform_device *pdev) 1886596e59eSSudip Mukherjee { 1896596e59eSSudip Mukherjee struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev); 1906596e59eSSudip Mukherjee 1918e27c2aeSBartosz Golaszewski ida_free(&ida_index, exar_gpio->index); 1926596e59eSSudip Mukherjee 1936596e59eSSudip Mukherjee return 0; 1946596e59eSSudip Mukherjee } 1956596e59eSSudip Mukherjee 1966596e59eSSudip Mukherjee static struct platform_driver gpio_exar_driver = { 1976596e59eSSudip Mukherjee .probe = gpio_exar_probe, 1986596e59eSSudip Mukherjee .remove = gpio_exar_remove, 1996596e59eSSudip Mukherjee .driver = { 2006596e59eSSudip Mukherjee .name = DRIVER_NAME, 2016596e59eSSudip Mukherjee }, 2026596e59eSSudip Mukherjee }; 2036596e59eSSudip Mukherjee 2046596e59eSSudip Mukherjee module_platform_driver(gpio_exar_driver); 2056596e59eSSudip Mukherjee 2066596e59eSSudip Mukherjee MODULE_ALIAS("platform:" DRIVER_NAME); 2076596e59eSSudip Mukherjee MODULE_DESCRIPTION("Exar GPIO driver"); 2086596e59eSSudip Mukherjee MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 2096596e59eSSudip Mukherjee MODULE_LICENSE("GPL"); 210