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