236 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * GPIO driver for Exar XR17V35X chip4 *5 * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>6 */7 8#include <linux/bitops.h>9#include <linux/device.h>10#include <linux/gpio/driver.h>11#include <linux/idr.h>12#include <linux/init.h>13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/pci.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18 19#define EXAR_OFFSET_MPIOLVL_LO 0x9020#define EXAR_OFFSET_MPIOSEL_LO 0x9321#define EXAR_OFFSET_MPIOLVL_HI 0x9622#define EXAR_OFFSET_MPIOSEL_HI 0x9923 24/*25 * The Device Configuration and UART Configuration Registers26 * for each UART channel take 1KB of memory address space.27 */28#define EXAR_UART_CHANNEL_SIZE 0x40029 30#define DRIVER_NAME "gpio_exar"31 32static DEFINE_IDA(ida_index);33 34struct exar_gpio_chip {35 struct gpio_chip gpio_chip;36 struct regmap *regmap;37 int index;38 char name[20];39 unsigned int first_pin;40 /*41 * The offset to the cascaded device's (if existing)42 * Device Configuration Registers.43 */44 unsigned int cascaded_offset;45};46 47static unsigned int48exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)49{50 unsigned int pin = exar_gpio->first_pin + (offset % 16);51 unsigned int cascaded = offset / 16;52 unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;53 54 return addr + (cascaded ? exar_gpio->cascaded_offset : 0);55}56 57static unsigned int58exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)59{60 unsigned int pin = exar_gpio->first_pin + (offset % 16);61 unsigned int cascaded = offset / 16;62 unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;63 64 return addr + (cascaded ? exar_gpio->cascaded_offset : 0);65}66 67static unsigned int68exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)69{70 unsigned int pin = exar_gpio->first_pin + (offset % 16);71 72 return pin % 8;73}74 75static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)76{77 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);78 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);79 unsigned int bit = exar_offset_to_bit(exar_gpio, offset);80 81 if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)))82 return GPIO_LINE_DIRECTION_IN;83 84 return GPIO_LINE_DIRECTION_OUT;85}86 87static int exar_get_value(struct gpio_chip *chip, unsigned int offset)88{89 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);90 unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);91 unsigned int bit = exar_offset_to_bit(exar_gpio, offset);92 93 return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)));94}95 96static void exar_set_value(struct gpio_chip *chip, unsigned int offset,97 int value)98{99 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);100 unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);101 unsigned int bit = exar_offset_to_bit(exar_gpio, offset);102 103 if (value)104 regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));105 else106 regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));107}108 109static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,110 int value)111{112 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);113 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);114 unsigned int bit = exar_offset_to_bit(exar_gpio, offset);115 116 exar_set_value(chip, offset, value);117 regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));118 119 return 0;120}121 122static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)123{124 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);125 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);126 unsigned int bit = exar_offset_to_bit(exar_gpio, offset);127 128 regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));129 130 return 0;131}132 133static void exar_devm_ida_free(void *data)134{135 struct exar_gpio_chip *exar_gpio = data;136 137 ida_free(&ida_index, exar_gpio->index);138}139 140static const struct regmap_config exar_regmap_config = {141 .name = "exar-gpio",142 .reg_bits = 16,143 .val_bits = 8,144 .io_port = true,145};146 147static int gpio_exar_probe(struct platform_device *pdev)148{149 struct device *dev = &pdev->dev;150 struct pci_dev *pcidev = to_pci_dev(dev->parent);151 struct exar_gpio_chip *exar_gpio;152 u32 first_pin, ngpios;153 void __iomem *p;154 int index, ret;155 156 /*157 * The UART driver must have mapped region 0 prior to registering this158 * device - use it.159 */160 p = pcim_iomap_table(pcidev)[0];161 if (!p)162 return -ENOMEM;163 164 ret = device_property_read_u32(dev, "exar,first-pin", &first_pin);165 if (ret)166 return ret;167 168 ret = device_property_read_u32(dev, "ngpios", &ngpios);169 if (ret)170 return ret;171 172 exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL);173 if (!exar_gpio)174 return -ENOMEM;175 176 /*177 * If cascaded, secondary xr17v354 or xr17v358 have the same amount178 * of MPIOs as their primaries and the last 4 bits of the primary's179 * PCI Device ID is the number of its UART channels.180 */181 if (pcidev->device & GENMASK(15, 12)) {182 ngpios += ngpios;183 exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) *184 EXAR_UART_CHANNEL_SIZE;185 }186 187 /*188 * We don't need to check the return values of mmio regmap operations (unless189 * the regmap has a clock attached which is not the case here).190 */191 exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config);192 if (IS_ERR(exar_gpio->regmap))193 return PTR_ERR(exar_gpio->regmap);194 195 index = ida_alloc(&ida_index, GFP_KERNEL);196 if (index < 0)197 return index;198 199 ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio);200 if (ret)201 return ret;202 203 sprintf(exar_gpio->name, "exar_gpio%d", index);204 exar_gpio->gpio_chip.label = exar_gpio->name;205 exar_gpio->gpio_chip.parent = dev;206 exar_gpio->gpio_chip.direction_output = exar_direction_output;207 exar_gpio->gpio_chip.direction_input = exar_direction_input;208 exar_gpio->gpio_chip.get_direction = exar_get_direction;209 exar_gpio->gpio_chip.get = exar_get_value;210 exar_gpio->gpio_chip.set = exar_set_value;211 exar_gpio->gpio_chip.base = -1;212 exar_gpio->gpio_chip.ngpio = ngpios;213 exar_gpio->index = index;214 exar_gpio->first_pin = first_pin;215 216 ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);217 if (ret)218 return ret;219 220 return 0;221}222 223static struct platform_driver gpio_exar_driver = {224 .probe = gpio_exar_probe,225 .driver = {226 .name = DRIVER_NAME,227 },228};229 230module_platform_driver(gpio_exar_driver);231 232MODULE_ALIAS("platform:" DRIVER_NAME);233MODULE_DESCRIPTION("Exar GPIO driver");234MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");235MODULE_LICENSE("GPL");236