1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * GPIO driver for Exar XR17V35X chip 4 * 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 18 #define EXAR_OFFSET_MPIOLVL_LO 0x90 19 #define EXAR_OFFSET_MPIOSEL_LO 0x93 20 #define EXAR_OFFSET_MPIOLVL_HI 0x96 21 #define EXAR_OFFSET_MPIOSEL_HI 0x99 22 23 #define DRIVER_NAME "gpio_exar" 24 25 static DEFINE_IDA(ida_index); 26 27 struct exar_gpio_chip { 28 struct gpio_chip gpio_chip; 29 struct mutex lock; 30 int index; 31 void __iomem *regs; 32 char name[20]; 33 unsigned int first_pin; 34 }; 35 36 static void exar_update(struct gpio_chip *chip, unsigned int reg, int val, 37 unsigned int offset) 38 { 39 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 40 int temp; 41 42 mutex_lock(&exar_gpio->lock); 43 temp = readb(exar_gpio->regs + reg); 44 temp &= ~BIT(offset); 45 if (val) 46 temp |= BIT(offset); 47 writeb(temp, exar_gpio->regs + reg); 48 mutex_unlock(&exar_gpio->lock); 49 } 50 51 static int exar_set_direction(struct gpio_chip *chip, int direction, 52 unsigned int offset) 53 { 54 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 55 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 56 EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 57 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 58 59 exar_update(chip, addr, direction, bit); 60 return 0; 61 } 62 63 static int exar_get(struct gpio_chip *chip, unsigned int reg) 64 { 65 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 66 int value; 67 68 mutex_lock(&exar_gpio->lock); 69 value = readb(exar_gpio->regs + reg); 70 mutex_unlock(&exar_gpio->lock); 71 72 return value; 73 } 74 75 static 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 = (offset + exar_gpio->first_pin) / 8 ? 79 EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 80 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 81 82 if (exar_get(chip, addr) & BIT(bit)) 83 return GPIO_LINE_DIRECTION_IN; 84 85 return GPIO_LINE_DIRECTION_OUT; 86 } 87 88 static int exar_get_value(struct gpio_chip *chip, unsigned int offset) 89 { 90 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 91 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 92 EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 93 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 94 95 return !!(exar_get(chip, addr) & BIT(bit)); 96 } 97 98 static void exar_set_value(struct gpio_chip *chip, unsigned int offset, 99 int value) 100 { 101 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 102 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 103 EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 104 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 105 106 exar_update(chip, addr, value, bit); 107 } 108 109 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, 110 int value) 111 { 112 exar_set_value(chip, offset, value); 113 return exar_set_direction(chip, 0, offset); 114 } 115 116 static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 117 { 118 return exar_set_direction(chip, 1, offset); 119 } 120 121 static int gpio_exar_probe(struct platform_device *pdev) 122 { 123 struct device *dev = &pdev->dev; 124 struct pci_dev *pcidev = to_pci_dev(dev->parent); 125 struct exar_gpio_chip *exar_gpio; 126 u32 first_pin, ngpios; 127 void __iomem *p; 128 int index, ret; 129 130 /* 131 * The UART driver must have mapped region 0 prior to registering this 132 * device - use it. 133 */ 134 p = pcim_iomap_table(pcidev)[0]; 135 if (!p) 136 return -ENOMEM; 137 138 ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); 139 if (ret) 140 return ret; 141 142 ret = device_property_read_u32(dev, "ngpios", &ngpios); 143 if (ret) 144 return ret; 145 146 exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 147 if (!exar_gpio) 148 return -ENOMEM; 149 150 mutex_init(&exar_gpio->lock); 151 152 index = ida_alloc(&ida_index, GFP_KERNEL); 153 if (index < 0) { 154 ret = index; 155 goto err_mutex_destroy; 156 } 157 158 sprintf(exar_gpio->name, "exar_gpio%d", index); 159 exar_gpio->gpio_chip.label = exar_gpio->name; 160 exar_gpio->gpio_chip.parent = dev; 161 exar_gpio->gpio_chip.direction_output = exar_direction_output; 162 exar_gpio->gpio_chip.direction_input = exar_direction_input; 163 exar_gpio->gpio_chip.get_direction = exar_get_direction; 164 exar_gpio->gpio_chip.get = exar_get_value; 165 exar_gpio->gpio_chip.set = exar_set_value; 166 exar_gpio->gpio_chip.base = -1; 167 exar_gpio->gpio_chip.ngpio = ngpios; 168 exar_gpio->regs = p; 169 exar_gpio->index = index; 170 exar_gpio->first_pin = first_pin; 171 172 ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 173 if (ret) 174 goto err_destroy; 175 176 platform_set_drvdata(pdev, exar_gpio); 177 178 return 0; 179 180 err_destroy: 181 ida_free(&ida_index, index); 182 err_mutex_destroy: 183 mutex_destroy(&exar_gpio->lock); 184 return ret; 185 } 186 187 static int gpio_exar_remove(struct platform_device *pdev) 188 { 189 struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev); 190 191 ida_free(&ida_index, exar_gpio->index); 192 mutex_destroy(&exar_gpio->lock); 193 194 return 0; 195 } 196 197 static struct platform_driver gpio_exar_driver = { 198 .probe = gpio_exar_probe, 199 .remove = gpio_exar_remove, 200 .driver = { 201 .name = DRIVER_NAME, 202 }, 203 }; 204 205 module_platform_driver(gpio_exar_driver); 206 207 MODULE_ALIAS("platform:" DRIVER_NAME); 208 MODULE_DESCRIPTION("Exar GPIO driver"); 209 MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 210 MODULE_LICENSE("GPL"); 211