Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: kempld: Implement the interrupt controller

Add a GPIO IRQ chip implementation for the kempld GPIO controller. Of
note is only how the parent IRQ is obtained.

The IRQ for the GPIO controller can be configured in the BIOS, along
with the IRQ for the I2C controller. These IRQ are returned by ACPI
but this information is only usable if both IRQ are configured. When
only one is configured, only one is returned making it impossible to
know which one it is.

Luckily the BIOS will set the configured IRQ in the PLD registers, so
it can be read from there instead, and that also work on platforms
without ACPI.

The vendor driver allowed to override the IRQ using a module
parameters, so there are boards in field which used this parameter
instead of properly configuring the BIOS. This implementation provides
this as well for compatibility.

Signed-off-by: Alban Bedel <alban.bedel@lht.dlh.de>
Link: https://patch.msgid.link/20260311143120.2179347-5-alban.bedel@lht.dlh.de
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

authored by

Alban Bedel and committed by
Bartosz Golaszewski
a25f48fd 2443c2e1

+194
+1
drivers/gpio/Kconfig
··· 1440 1440 config GPIO_KEMPLD 1441 1441 tristate "Kontron ETX / COMexpress GPIO" 1442 1442 depends on MFD_KEMPLD 1443 + select GPIOLIB_IRQCHIP 1443 1444 help 1444 1445 This enables support for the PLD GPIO interface on some Kontron ETX 1445 1446 and COMexpress (ETXexpress) modules.
+192
drivers/gpio/gpio-kempld.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/bitops.h> 13 13 #include <linux/errno.h> 14 + #include <linux/interrupt.h> 14 15 #include <linux/platform_device.h> 15 16 #include <linux/gpio/driver.h> 16 17 #include <linux/mfd/kempld.h> ··· 20 19 #define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) 21 20 #define KEMPLD_GPIO_DIR 0x40 22 21 #define KEMPLD_GPIO_LVL 0x42 22 + #define KEMPLD_GPIO_STS 0x44 23 23 #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 24 + #define KEMPLD_GPIO_EVT_LOW_HIGH 0x48 24 25 #define KEMPLD_GPIO_IEN 0x4A 26 + #define KEMPLD_GPIO_OUT_LVL 0x4E 27 + 28 + /* The IRQ to use if none was configured in the BIOS */ 29 + static unsigned int gpio_irq; 30 + module_param_hw(gpio_irq, uint, irq, 0444); 31 + MODULE_PARM_DESC(gpio_irq, "Set legacy GPIO IRQ (1-15)"); 25 32 26 33 struct kempld_gpio_data { 27 34 struct gpio_chip chip; 28 35 struct kempld_device_data *pld; 29 36 u8 out_lvl_reg; 37 + 38 + struct mutex irq_lock; 39 + u16 ien; 40 + u16 evt_low_high; 41 + u16 evt_lvl_edge; 30 42 }; 31 43 32 44 /* ··· 207 193 return evt ? __ffs(evt) : 16; 208 194 } 209 195 196 + static void kempld_irq_mask(struct irq_data *data) 197 + { 198 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 199 + struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 200 + 201 + gpio->ien &= ~BIT(irqd_to_hwirq(data)); 202 + gpiochip_disable_irq(chip, irqd_to_hwirq(data)); 203 + } 204 + 205 + static void kempld_irq_unmask(struct irq_data *data) 206 + { 207 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 208 + struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 209 + 210 + gpiochip_enable_irq(chip, irqd_to_hwirq(data)); 211 + gpio->ien |= BIT(irqd_to_hwirq(data)); 212 + } 213 + 214 + static int kempld_irq_set_type(struct irq_data *data, unsigned int type) 215 + { 216 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 217 + struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 218 + 219 + switch (type) { 220 + case IRQ_TYPE_EDGE_RISING: 221 + gpio->evt_low_high |= BIT(data->hwirq); 222 + gpio->evt_lvl_edge |= BIT(data->hwirq); 223 + break; 224 + case IRQ_TYPE_EDGE_FALLING: 225 + gpio->evt_low_high &= ~BIT(data->hwirq); 226 + gpio->evt_lvl_edge |= BIT(data->hwirq); 227 + break; 228 + case IRQ_TYPE_LEVEL_HIGH: 229 + gpio->evt_low_high |= BIT(data->hwirq); 230 + gpio->evt_lvl_edge &= ~BIT(data->hwirq); 231 + break; 232 + case IRQ_TYPE_LEVEL_LOW: 233 + gpio->evt_low_high &= ~BIT(data->hwirq); 234 + gpio->evt_lvl_edge &= ~BIT(data->hwirq); 235 + break; 236 + default: 237 + return -EINVAL; 238 + } 239 + 240 + return 0; 241 + } 242 + 243 + static void kempld_irq_bus_lock(struct irq_data *data) 244 + { 245 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 246 + struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 247 + 248 + mutex_lock(&gpio->irq_lock); 249 + } 250 + 251 + static void kempld_irq_bus_sync_unlock(struct irq_data *data) 252 + { 253 + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 254 + struct kempld_gpio_data *gpio = gpiochip_get_data(chip); 255 + struct kempld_device_data *pld = gpio->pld; 256 + 257 + kempld_get_mutex(pld); 258 + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, gpio->evt_lvl_edge); 259 + kempld_write16(pld, KEMPLD_GPIO_EVT_LOW_HIGH, gpio->evt_low_high); 260 + kempld_write16(pld, KEMPLD_GPIO_IEN, gpio->ien); 261 + kempld_release_mutex(pld); 262 + 263 + mutex_unlock(&gpio->irq_lock); 264 + } 265 + 266 + static const struct irq_chip kempld_irqchip = { 267 + .name = "kempld-gpio", 268 + .irq_mask = kempld_irq_mask, 269 + .irq_unmask = kempld_irq_unmask, 270 + .irq_set_type = kempld_irq_set_type, 271 + .irq_bus_lock = kempld_irq_bus_lock, 272 + .irq_bus_sync_unlock = kempld_irq_bus_sync_unlock, 273 + .flags = IRQCHIP_IMMUTABLE, 274 + GPIOCHIP_IRQ_RESOURCE_HELPERS, 275 + }; 276 + 277 + static irqreturn_t kempld_gpio_irq_handler(int irq, void *data) 278 + { 279 + struct kempld_gpio_data *gpio = data; 280 + struct gpio_chip *chip = &gpio->chip; 281 + unsigned int pin, child_irq; 282 + unsigned long status; 283 + 284 + kempld_get_mutex(gpio->pld); 285 + 286 + status = kempld_read16(gpio->pld, KEMPLD_GPIO_STS); 287 + if (status) 288 + kempld_write16(gpio->pld, KEMPLD_GPIO_STS, status); 289 + 290 + kempld_release_mutex(gpio->pld); 291 + 292 + status &= gpio->ien; 293 + if (!status) 294 + return IRQ_NONE; 295 + 296 + for_each_set_bit(pin, &status, chip->ngpio) { 297 + child_irq = irq_find_mapping(chip->irq.domain, pin); 298 + handle_nested_irq(child_irq); 299 + } 300 + 301 + return IRQ_HANDLED; 302 + } 303 + 304 + static int kempld_gpio_irq_init(struct device *dev, 305 + struct kempld_gpio_data *gpio) 306 + { 307 + struct kempld_device_data *pld = gpio->pld; 308 + struct gpio_chip *chip = &gpio->chip; 309 + struct gpio_irq_chip *girq; 310 + unsigned int irq; 311 + int ret; 312 + 313 + /* Get the IRQ configured by the BIOS in the PLD */ 314 + kempld_get_mutex(pld); 315 + irq = kempld_read8(pld, KEMPLD_IRQ_GPIO); 316 + kempld_release_mutex(pld); 317 + 318 + if (irq == 0xff) { 319 + dev_info(dev, "GPIO controller has no IRQ support\n"); 320 + return 0; 321 + } 322 + 323 + /* Allow overriding the IRQ with the module parameter */ 324 + if (gpio_irq > 0) { 325 + dev_warn(dev, "Forcing IRQ to %d\n", gpio_irq); 326 + irq &= ~KEMPLD_IRQ_GPIO_MASK; 327 + irq |= gpio_irq & KEMPLD_IRQ_GPIO_MASK; 328 + } 329 + 330 + if (!(irq & KEMPLD_IRQ_GPIO_MASK)) { 331 + dev_warn(dev, "No IRQ configured\n"); 332 + return 0; 333 + } 334 + 335 + /* Get the current config, disable all child interrupts, clear them 336 + * and set the parent IRQ 337 + */ 338 + kempld_get_mutex(pld); 339 + gpio->evt_low_high = kempld_read16(pld, KEMPLD_GPIO_EVT_LOW_HIGH); 340 + gpio->evt_lvl_edge = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); 341 + kempld_write16(pld, KEMPLD_GPIO_IEN, 0); 342 + kempld_write16(pld, KEMPLD_GPIO_STS, 0xFFFF); 343 + kempld_write16(pld, KEMPLD_IRQ_GPIO, irq); 344 + kempld_release_mutex(pld); 345 + 346 + girq = &chip->irq; 347 + gpio_irq_chip_set_chip(girq, &kempld_irqchip); 348 + 349 + girq->parent_handler = NULL; 350 + girq->num_parents = 0; 351 + girq->parents = NULL; 352 + girq->default_type = IRQ_TYPE_NONE; 353 + girq->handler = handle_simple_irq; 354 + girq->threaded = true; 355 + 356 + mutex_init(&gpio->irq_lock); 357 + 358 + ret = devm_request_threaded_irq(dev, irq & KEMPLD_IRQ_GPIO_MASK, 359 + NULL, kempld_gpio_irq_handler, 360 + IRQF_ONESHOT, chip->label, 361 + gpio); 362 + if (ret) { 363 + dev_err(dev, "failed to request irq %d\n", irq); 364 + return ret; 365 + } 366 + 367 + return 0; 368 + } 369 + 210 370 static int kempld_gpio_probe(struct platform_device *pdev) 211 371 { 212 372 struct device *dev = &pdev->dev; ··· 434 246 dev_err(dev, "No GPIO pins detected\n"); 435 247 return -ENODEV; 436 248 } 249 + 250 + ret = kempld_gpio_irq_init(dev, gpio); 251 + if (ret) 252 + return ret; 437 253 438 254 ret = devm_gpiochip_add_data(dev, chip, gpio); 439 255 if (ret) {
+1
include/linux/mfd/kempld.h
··· 37 37 #define KEMPLD_SPEC_GET_MINOR(x) (x & 0x0f) 38 38 #define KEMPLD_SPEC_GET_MAJOR(x) ((x >> 4) & 0x0f) 39 39 #define KEMPLD_IRQ_GPIO 0x35 40 + #define KEMPLD_IRQ_GPIO_MASK 0x0f 40 41 #define KEMPLD_IRQ_I2C 0x36 41 42 #define KEMPLD_CFG 0x37 42 43 #define KEMPLD_CFG_GPIO_I2C_MUX (1 << 0)