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/init.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/pci.h> 15 #include <linux/platform_device.h> 16 17 #define EXAR_OFFSET_MPIOLVL_LO 0x90 18 #define EXAR_OFFSET_MPIOSEL_LO 0x93 19 #define EXAR_OFFSET_MPIOLVL_HI 0x96 20 #define EXAR_OFFSET_MPIOSEL_HI 0x99 21 22 #define DRIVER_NAME "gpio_exar" 23 24 static DEFINE_IDA(ida_index); 25 26 struct exar_gpio_chip { 27 struct gpio_chip gpio_chip; 28 struct mutex lock; 29 int index; 30 void __iomem *regs; 31 char name[20]; 32 unsigned int first_pin; 33 }; 34 35 static void exar_update(struct gpio_chip *chip, unsigned int reg, int val, 36 unsigned int offset) 37 { 38 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 39 int temp; 40 41 mutex_lock(&exar_gpio->lock); 42 temp = readb(exar_gpio->regs + reg); 43 temp &= ~BIT(offset); 44 if (val) 45 temp |= BIT(offset); 46 writeb(temp, exar_gpio->regs + reg); 47 mutex_unlock(&exar_gpio->lock); 48 } 49 50 static int exar_set_direction(struct gpio_chip *chip, int direction, 51 unsigned int offset) 52 { 53 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 54 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 55 EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 56 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 57 58 exar_update(chip, addr, direction, bit); 59 return 0; 60 } 61 62 static int exar_get(struct gpio_chip *chip, unsigned int reg) 63 { 64 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 65 int value; 66 67 mutex_lock(&exar_gpio->lock); 68 value = readb(exar_gpio->regs + reg); 69 mutex_unlock(&exar_gpio->lock); 70 71 return value; 72 } 73 74 static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) 75 { 76 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 77 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 78 EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; 79 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 80 81 if (exar_get(chip, addr) & BIT(bit)) 82 return GPIO_LINE_DIRECTION_IN; 83 84 return GPIO_LINE_DIRECTION_OUT; 85 } 86 87 static 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 = (offset + exar_gpio->first_pin) / 8 ? 91 EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 92 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 93 94 return !!(exar_get(chip, addr) & BIT(bit)); 95 } 96 97 static void exar_set_value(struct gpio_chip *chip, unsigned int offset, 98 int value) 99 { 100 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 101 unsigned int addr = (offset + exar_gpio->first_pin) / 8 ? 102 EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; 103 unsigned int bit = (offset + exar_gpio->first_pin) % 8; 104 105 exar_update(chip, addr, value, bit); 106 } 107 108 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, 109 int value) 110 { 111 exar_set_value(chip, offset, value); 112 return exar_set_direction(chip, 0, offset); 113 } 114 115 static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 116 { 117 return exar_set_direction(chip, 1, offset); 118 } 119 120 static int gpio_exar_probe(struct platform_device *pdev) 121 { 122 struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent); 123 struct exar_gpio_chip *exar_gpio; 124 u32 first_pin, ngpios; 125 void __iomem *p; 126 int index, ret; 127 128 /* 129 * The UART driver must have mapped region 0 prior to registering this 130 * device - use it. 131 */ 132 p = pcim_iomap_table(pcidev)[0]; 133 if (!p) 134 return -ENOMEM; 135 136 ret = device_property_read_u32(&pdev->dev, "exar,first-pin", 137 &first_pin); 138 if (ret) 139 return ret; 140 141 ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios); 142 if (ret) 143 return ret; 144 145 exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL); 146 if (!exar_gpio) 147 return -ENOMEM; 148 149 mutex_init(&exar_gpio->lock); 150 151 index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); 152 if (index < 0) { 153 ret = index; 154 goto err_mutex_destroy; 155 } 156 157 sprintf(exar_gpio->name, "exar_gpio%d", index); 158 exar_gpio->gpio_chip.label = exar_gpio->name; 159 exar_gpio->gpio_chip.parent = &pdev->dev; 160 exar_gpio->gpio_chip.direction_output = exar_direction_output; 161 exar_gpio->gpio_chip.direction_input = exar_direction_input; 162 exar_gpio->gpio_chip.get_direction = exar_get_direction; 163 exar_gpio->gpio_chip.get = exar_get_value; 164 exar_gpio->gpio_chip.set = exar_set_value; 165 exar_gpio->gpio_chip.base = -1; 166 exar_gpio->gpio_chip.ngpio = ngpios; 167 exar_gpio->regs = p; 168 exar_gpio->index = index; 169 exar_gpio->first_pin = first_pin; 170 171 ret = devm_gpiochip_add_data(&pdev->dev, 172 &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_simple_remove(&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_simple_remove(&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