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 pci_dev *pcidev = to_pci_dev(pdev->dev.parent); 124 struct exar_gpio_chip *exar_gpio; 125 u32 first_pin, ngpios; 126 void __iomem *p; 127 int index, ret; 128 129 /* 130 * The UART driver must have mapped region 0 prior to registering this 131 * device - use it. 132 */ 133 p = pcim_iomap_table(pcidev)[0]; 134 if (!p) 135 return -ENOMEM; 136 137 ret = device_property_read_u32(&pdev->dev, "exar,first-pin", 138 &first_pin); 139 if (ret) 140 return ret; 141 142 ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios); 143 if (ret) 144 return ret; 145 146 exar_gpio = devm_kzalloc(&pdev->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 = &pdev->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(&pdev->dev, 173 &exar_gpio->gpio_chip, exar_gpio); 174 if (ret) 175 goto err_destroy; 176 177 platform_set_drvdata(pdev, exar_gpio); 178 179 return 0; 180 181 err_destroy: 182 ida_free(&ida_index, index); 183 err_mutex_destroy: 184 mutex_destroy(&exar_gpio->lock); 185 return ret; 186 } 187 188 static int gpio_exar_remove(struct platform_device *pdev) 189 { 190 struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev); 191 192 ida_free(&ida_index, exar_gpio->index); 193 mutex_destroy(&exar_gpio->lock); 194 195 return 0; 196 } 197 198 static struct platform_driver gpio_exar_driver = { 199 .probe = gpio_exar_probe, 200 .remove = gpio_exar_remove, 201 .driver = { 202 .name = DRIVER_NAME, 203 }, 204 }; 205 206 module_platform_driver(gpio_exar_driver); 207 208 MODULE_ALIAS("platform:" DRIVER_NAME); 209 MODULE_DESCRIPTION("Exar GPIO driver"); 210 MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 211 MODULE_LICENSE("GPL"); 212