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 #include <linux/regmap.h> 18 19 #define EXAR_OFFSET_MPIOLVL_LO 0x90 20 #define EXAR_OFFSET_MPIOSEL_LO 0x93 21 #define EXAR_OFFSET_MPIOLVL_HI 0x96 22 #define EXAR_OFFSET_MPIOSEL_HI 0x99 23 24 #define DRIVER_NAME "gpio_exar" 25 26 static DEFINE_IDA(ida_index); 27 28 struct exar_gpio_chip { 29 struct gpio_chip gpio_chip; 30 struct regmap *regmap; 31 int index; 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 int exar_get_direction(struct gpio_chip *chip, unsigned int offset) 57 { 58 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 59 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 60 unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 61 62 if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))) 63 return GPIO_LINE_DIRECTION_IN; 64 65 return GPIO_LINE_DIRECTION_OUT; 66 } 67 68 static int exar_get_value(struct gpio_chip *chip, unsigned int offset) 69 { 70 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 71 unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 72 unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 73 74 return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))); 75 } 76 77 static void exar_set_value(struct gpio_chip *chip, unsigned int offset, 78 int value) 79 { 80 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 81 unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); 82 unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 83 84 if (value) 85 regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 86 else 87 regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 88 } 89 90 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, 91 int value) 92 { 93 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 94 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 95 unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 96 97 exar_set_value(chip, offset, value); 98 regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); 99 100 return 0; 101 } 102 103 static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) 104 { 105 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); 106 unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); 107 unsigned int bit = exar_offset_to_bit(exar_gpio, offset); 108 109 regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); 110 111 return 0; 112 } 113 114 static const struct regmap_config exar_regmap_config = { 115 .name = "exar-gpio", 116 .reg_bits = 16, 117 .val_bits = 8, 118 }; 119 120 static int gpio_exar_probe(struct platform_device *pdev) 121 { 122 struct device *dev = &pdev->dev; 123 struct pci_dev *pcidev = to_pci_dev(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(dev, "exar,first-pin", &first_pin); 138 if (ret) 139 return ret; 140 141 ret = device_property_read_u32(dev, "ngpios", &ngpios); 142 if (ret) 143 return ret; 144 145 exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); 146 if (!exar_gpio) 147 return -ENOMEM; 148 149 /* 150 * We don't need to check the return values of mmio regmap operations (unless 151 * the regmap has a clock attached which is not the case here). 152 */ 153 exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); 154 if (IS_ERR(exar_gpio->regmap)) 155 return PTR_ERR(exar_gpio->regmap); 156 157 index = ida_alloc(&ida_index, GFP_KERNEL); 158 if (index < 0) 159 return index; 160 161 sprintf(exar_gpio->name, "exar_gpio%d", index); 162 exar_gpio->gpio_chip.label = exar_gpio->name; 163 exar_gpio->gpio_chip.parent = dev; 164 exar_gpio->gpio_chip.direction_output = exar_direction_output; 165 exar_gpio->gpio_chip.direction_input = exar_direction_input; 166 exar_gpio->gpio_chip.get_direction = exar_get_direction; 167 exar_gpio->gpio_chip.get = exar_get_value; 168 exar_gpio->gpio_chip.set = exar_set_value; 169 exar_gpio->gpio_chip.base = -1; 170 exar_gpio->gpio_chip.ngpio = ngpios; 171 exar_gpio->index = index; 172 exar_gpio->first_pin = first_pin; 173 174 ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); 175 if (ret) 176 goto err_destroy; 177 178 platform_set_drvdata(pdev, exar_gpio); 179 180 return 0; 181 182 err_destroy: 183 ida_free(&ida_index, index); 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 193 return 0; 194 } 195 196 static struct platform_driver gpio_exar_driver = { 197 .probe = gpio_exar_probe, 198 .remove = gpio_exar_remove, 199 .driver = { 200 .name = DRIVER_NAME, 201 }, 202 }; 203 204 module_platform_driver(gpio_exar_driver); 205 206 MODULE_ALIAS("platform:" DRIVER_NAME); 207 MODULE_DESCRIPTION("Exar GPIO driver"); 208 MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>"); 209 MODULE_LICENSE("GPL"); 210