1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Loongson GPIO Support 4 * 5 * Copyright (C) 2022-2023 Loongson Technology Corporation Limited 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/init.h> 10 #include <linux/irq.h> 11 #include <linux/irqdesc.h> 12 #include <linux/module.h> 13 #include <linux/spinlock.h> 14 #include <linux/err.h> 15 #include <linux/gpio/driver.h> 16 #include <linux/gpio/generic.h> 17 #include <linux/platform_device.h> 18 #include <linux/bitops.h> 19 #include <linux/reset.h> 20 #include <asm/types.h> 21 22 enum loongson_gpio_mode { 23 BIT_CTRL_MODE, 24 BYTE_CTRL_MODE, 25 }; 26 27 struct loongson_gpio_chip_data { 28 const char *label; 29 enum loongson_gpio_mode mode; 30 unsigned int conf_offset; 31 unsigned int out_offset; 32 unsigned int in_offset; 33 unsigned int inten_offset; 34 unsigned int intpol_offset; 35 unsigned int intedge_offset; 36 unsigned int intclr_offset; 37 unsigned int intsts_offset; 38 unsigned int intdual_offset; 39 unsigned int intr_num; 40 irq_flow_handler_t irq_handler; 41 const struct irq_chip *girqchip; 42 }; 43 44 struct loongson_gpio_chip { 45 struct gpio_generic_chip chip; 46 spinlock_t lock; 47 void __iomem *reg_base; 48 const struct loongson_gpio_chip_data *chip_data; 49 }; 50 51 static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip *chip) 52 { 53 return container_of(to_gpio_generic_chip(chip), 54 struct loongson_gpio_chip, chip); 55 } 56 57 static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin, 58 int input) 59 { 60 u8 bval = input ? 1 : 0; 61 62 writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin); 63 } 64 65 static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) 66 { 67 u8 bval = high ? 1 : 0; 68 69 writeb(bval, lgpio->reg_base + lgpio->chip_data->out_offset + pin); 70 } 71 72 static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) 73 { 74 unsigned long flags; 75 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 76 77 spin_lock_irqsave(&lgpio->lock, flags); 78 loongson_commit_direction(lgpio, pin, 1); 79 spin_unlock_irqrestore(&lgpio->lock, flags); 80 81 return 0; 82 } 83 84 static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value) 85 { 86 unsigned long flags; 87 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 88 89 spin_lock_irqsave(&lgpio->lock, flags); 90 loongson_commit_level(lgpio, pin, value); 91 loongson_commit_direction(lgpio, pin, 0); 92 spin_unlock_irqrestore(&lgpio->lock, flags); 93 94 return 0; 95 } 96 97 static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) 98 { 99 u8 bval; 100 int val; 101 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 102 103 bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); 104 val = bval & 1; 105 106 return val; 107 } 108 109 static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) 110 { 111 u8 bval; 112 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 113 114 bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); 115 if (bval & 1) 116 return GPIO_LINE_DIRECTION_IN; 117 118 return GPIO_LINE_DIRECTION_OUT; 119 } 120 121 static int loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) 122 { 123 unsigned long flags; 124 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 125 126 spin_lock_irqsave(&lgpio->lock, flags); 127 loongson_commit_level(lgpio, pin, value); 128 spin_unlock_irqrestore(&lgpio->lock, flags); 129 130 return 0; 131 } 132 133 static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 134 { 135 unsigned int u; 136 struct platform_device *pdev = to_platform_device(chip->parent); 137 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 138 139 if (lgpio->chip_data->mode == BIT_CTRL_MODE) { 140 /* Get the register index from offset then multiply by bytes per register */ 141 u = readl(lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); 142 u |= BIT(offset % 32); 143 writel(u, lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); 144 } else { 145 writeb(1, lgpio->reg_base + lgpio->chip_data->inten_offset + offset); 146 } 147 148 return platform_get_irq(pdev, offset); 149 } 150 151 static void loongson_gpio_irq_ack(struct irq_data *data) 152 { 153 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 154 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 155 irq_hw_number_t hwirq = irqd_to_hwirq(data); 156 157 writeb(0x1, lgpio->reg_base + lgpio->chip_data->intclr_offset + hwirq); 158 } 159 160 static void loongson_gpio_irq_mask(struct irq_data *data) 161 { 162 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 163 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 164 irq_hw_number_t hwirq = irqd_to_hwirq(data); 165 166 writeb(0x0, lgpio->reg_base + lgpio->chip_data->inten_offset + hwirq); 167 } 168 169 static void loongson_gpio_irq_unmask(struct irq_data *data) 170 { 171 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 172 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 173 irq_hw_number_t hwirq = irqd_to_hwirq(data); 174 175 writeb(0x1, lgpio->reg_base + lgpio->chip_data->inten_offset + hwirq); 176 } 177 178 static int loongson_gpio_irq_set_type(struct irq_data *data, unsigned int type) 179 { 180 struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 181 struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); 182 irq_hw_number_t hwirq = irqd_to_hwirq(data); 183 u8 pol = 0, edge = 0, dual = 0; 184 185 if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { 186 edge = 1; 187 dual = 1; 188 irq_set_handler_locked(data, handle_edge_irq); 189 } else { 190 switch (type) { 191 case IRQ_TYPE_LEVEL_HIGH: 192 pol = 1; 193 fallthrough; 194 case IRQ_TYPE_LEVEL_LOW: 195 irq_set_handler_locked(data, handle_level_irq); 196 break; 197 198 case IRQ_TYPE_EDGE_RISING: 199 pol = 1; 200 fallthrough; 201 case IRQ_TYPE_EDGE_FALLING: 202 edge = 1; 203 irq_set_handler_locked(data, handle_edge_irq); 204 break; 205 206 default: 207 return -EINVAL; 208 } 209 } 210 211 writeb(pol, lgpio->reg_base + lgpio->chip_data->intpol_offset + hwirq); 212 writeb(edge, lgpio->reg_base + lgpio->chip_data->intedge_offset + hwirq); 213 writeb(dual, lgpio->reg_base + lgpio->chip_data->intdual_offset + hwirq); 214 215 return 0; 216 } 217 218 static void loongson_gpio_ls2k0300_irq_handler(struct irq_desc *desc) 219 { 220 struct loongson_gpio_chip *lgpio = irq_desc_get_handler_data(desc); 221 struct irq_chip *girqchip = irq_desc_get_chip(desc); 222 int i; 223 224 chained_irq_enter(girqchip, desc); 225 226 for (i = 0; i < lgpio->chip.gc.ngpio; i++) { 227 /* 228 * For the GPIO controller of LS2K0300, interrupts status bits 229 * may be wrongly set even if the corresponding interrupt is 230 * disabled. Thus interrupt enable bits are checked along with 231 * status bits to detect interrupts reliably. 232 */ 233 if (readb(lgpio->reg_base + lgpio->chip_data->intsts_offset + i) && 234 readb(lgpio->reg_base + lgpio->chip_data->inten_offset + i)) 235 generic_handle_domain_irq(lgpio->chip.gc.irq.domain, i); 236 } 237 238 chained_irq_exit(girqchip, desc); 239 } 240 241 static const struct irq_chip loongson_gpio_ls2k0300_irqchip = { 242 .irq_ack = loongson_gpio_irq_ack, 243 .irq_mask = loongson_gpio_irq_mask, 244 .irq_unmask = loongson_gpio_irq_unmask, 245 .irq_set_type = loongson_gpio_irq_set_type, 246 .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE, 247 GPIOCHIP_IRQ_RESOURCE_HELPERS, 248 }; 249 250 static int loongson_gpio_init_irqchip(struct platform_device *pdev, 251 struct loongson_gpio_chip *lgpio) 252 { 253 const struct loongson_gpio_chip_data *data = lgpio->chip_data; 254 struct gpio_chip *chip = &lgpio->chip.gc; 255 int i; 256 257 chip->irq.default_type = IRQ_TYPE_NONE; 258 chip->irq.handler = handle_bad_irq; 259 chip->irq.parent_handler = data->irq_handler; 260 chip->irq.parent_handler_data = lgpio; 261 gpio_irq_chip_set_chip(&chip->irq, data->girqchip); 262 263 chip->irq.num_parents = data->intr_num; 264 chip->irq.parents = devm_kcalloc(&pdev->dev, data->intr_num, 265 sizeof(*chip->irq.parents), GFP_KERNEL); 266 if (!chip->parent) 267 return -ENOMEM; 268 269 for (i = 0; i < data->intr_num; i++) { 270 int ret; 271 272 ret = platform_get_irq(pdev, i); 273 if (ret < 0) 274 return dev_err_probe(&pdev->dev, ret, 275 "failed to get IRQ %d\n", i); 276 chip->irq.parents[i] = ret; 277 } 278 279 for (i = 0; i < data->intr_num; i++) { 280 writeb(0x0, lgpio->reg_base + data->inten_offset + i); 281 writeb(0x1, lgpio->reg_base + data->intclr_offset + i); 282 } 283 284 return 0; 285 } 286 287 static int loongson_gpio_init(struct platform_device *pdev, struct loongson_gpio_chip *lgpio, 288 void __iomem *reg_base) 289 { 290 struct gpio_generic_chip_config config; 291 int ret; 292 293 lgpio->reg_base = reg_base; 294 if (lgpio->chip_data->mode == BIT_CTRL_MODE) { 295 config = (struct gpio_generic_chip_config) { 296 .dev = &pdev->dev, 297 .sz = 8, 298 .dat = lgpio->reg_base + lgpio->chip_data->in_offset, 299 .set = lgpio->reg_base + lgpio->chip_data->out_offset, 300 .dirin = lgpio->reg_base + lgpio->chip_data->conf_offset, 301 }; 302 303 ret = gpio_generic_chip_init(&lgpio->chip, &config); 304 if (ret) { 305 dev_err(&pdev->dev, "unable to init generic GPIO\n"); 306 return ret; 307 } 308 } else { 309 lgpio->chip.gc.direction_input = loongson_gpio_direction_input; 310 lgpio->chip.gc.get = loongson_gpio_get; 311 lgpio->chip.gc.get_direction = loongson_gpio_get_direction; 312 lgpio->chip.gc.direction_output = loongson_gpio_direction_output; 313 lgpio->chip.gc.set = loongson_gpio_set; 314 lgpio->chip.gc.parent = &pdev->dev; 315 lgpio->chip.gc.base = -1; 316 spin_lock_init(&lgpio->lock); 317 } 318 319 lgpio->chip.gc.label = lgpio->chip_data->label; 320 lgpio->chip.gc.can_sleep = false; 321 if (lgpio->chip_data->girqchip) { 322 ret = loongson_gpio_init_irqchip(pdev, lgpio); 323 if (ret) 324 return dev_err_probe(&pdev->dev, ret, "failed to initialize irqchip\n"); 325 } else if (lgpio->chip_data->inten_offset) { 326 lgpio->chip.gc.to_irq = loongson_gpio_to_irq; 327 } 328 329 return devm_gpiochip_add_data(&pdev->dev, &lgpio->chip.gc, lgpio); 330 } 331 332 static int loongson_gpio_probe(struct platform_device *pdev) 333 { 334 void __iomem *reg_base; 335 struct loongson_gpio_chip *lgpio; 336 struct device *dev = &pdev->dev; 337 struct reset_control *rst; 338 339 lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); 340 if (!lgpio) 341 return -ENOMEM; 342 343 lgpio->chip_data = device_get_match_data(dev); 344 345 reg_base = devm_platform_ioremap_resource(pdev, 0); 346 if (IS_ERR(reg_base)) 347 return PTR_ERR(reg_base); 348 349 rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, NULL); 350 if (IS_ERR(rst)) 351 return dev_err_probe(&pdev->dev, PTR_ERR(rst), "failed to get reset control\n"); 352 353 return loongson_gpio_init(pdev, lgpio, reg_base); 354 } 355 356 static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { 357 .label = "ls2k_gpio", 358 .mode = BIT_CTRL_MODE, 359 .conf_offset = 0x0, 360 .in_offset = 0x20, 361 .out_offset = 0x10, 362 .inten_offset = 0x30, 363 }; 364 365 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0300_data = { 366 .label = "ls2k0300_gpio", 367 .mode = BYTE_CTRL_MODE, 368 .conf_offset = 0x800, 369 .in_offset = 0xa00, 370 .out_offset = 0x900, 371 .inten_offset = 0xb00, 372 .intpol_offset = 0xc00, 373 .intedge_offset = 0xd00, 374 .intclr_offset = 0xe00, 375 .intsts_offset = 0xf00, 376 .intdual_offset = 0xf80, 377 .intr_num = 7, 378 .irq_handler = loongson_gpio_ls2k0300_irq_handler, 379 .girqchip = &loongson_gpio_ls2k0300_irqchip, 380 }; 381 382 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = { 383 .label = "ls2k0500_gpio", 384 .mode = BIT_CTRL_MODE, 385 .conf_offset = 0x0, 386 .in_offset = 0x8, 387 .out_offset = 0x10, 388 .inten_offset = 0xb0, 389 }; 390 391 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = { 392 .label = "ls2k0500_gpio", 393 .mode = BIT_CTRL_MODE, 394 .conf_offset = 0x0, 395 .in_offset = 0x8, 396 .out_offset = 0x10, 397 .inten_offset = 0x98, 398 }; 399 400 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { 401 .label = "ls2k2000_gpio", 402 .mode = BIT_CTRL_MODE, 403 .conf_offset = 0x0, 404 .in_offset = 0xc, 405 .out_offset = 0x8, 406 .inten_offset = 0x14, 407 }; 408 409 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { 410 .label = "ls2k2000_gpio", 411 .mode = BYTE_CTRL_MODE, 412 .conf_offset = 0x800, 413 .in_offset = 0xa00, 414 .out_offset = 0x900, 415 .inten_offset = 0xb00, 416 }; 417 418 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { 419 .label = "ls2k2000_gpio", 420 .mode = BIT_CTRL_MODE, 421 .conf_offset = 0x4, 422 .in_offset = 0x8, 423 .out_offset = 0x0, 424 }; 425 426 static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = { 427 .label = "ls3a5000_gpio", 428 .mode = BIT_CTRL_MODE, 429 .conf_offset = 0x0, 430 .in_offset = 0xc, 431 .out_offset = 0x8, 432 .inten_offset = 0x14, 433 }; 434 435 static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { 436 .label = "ls7a_gpio", 437 .mode = BYTE_CTRL_MODE, 438 .conf_offset = 0x800, 439 .in_offset = 0xa00, 440 .out_offset = 0x900, 441 .inten_offset = 0xb00, 442 }; 443 444 /* LS7A2000 chipset GPIO */ 445 static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { 446 .label = "ls7a2000_gpio", 447 .mode = BYTE_CTRL_MODE, 448 .conf_offset = 0x800, 449 .in_offset = 0xa00, 450 .out_offset = 0x900, 451 .inten_offset = 0xb00, 452 }; 453 454 /* LS7A2000 ACPI GPIO */ 455 static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { 456 .label = "ls7a2000_gpio", 457 .mode = BIT_CTRL_MODE, 458 .conf_offset = 0x4, 459 .in_offset = 0x8, 460 .out_offset = 0x0, 461 }; 462 463 /* Loongson-3A6000 node GPIO */ 464 static const struct loongson_gpio_chip_data loongson_gpio_ls3a6000_data = { 465 .label = "ls3a6000_gpio", 466 .mode = BIT_CTRL_MODE, 467 .conf_offset = 0x0, 468 .in_offset = 0xc, 469 .out_offset = 0x8, 470 .inten_offset = 0x14, 471 }; 472 473 static const struct of_device_id loongson_gpio_of_match[] = { 474 { 475 .compatible = "loongson,ls2k-gpio", 476 .data = &loongson_gpio_ls2k_data, 477 }, 478 { 479 .compatible = "loongson,ls2k0300-gpio", 480 .data = &loongson_gpio_ls2k0300_data, 481 }, 482 { 483 .compatible = "loongson,ls2k0500-gpio0", 484 .data = &loongson_gpio_ls2k0500_data0, 485 }, 486 { 487 .compatible = "loongson,ls2k0500-gpio1", 488 .data = &loongson_gpio_ls2k0500_data1, 489 }, 490 { 491 .compatible = "loongson,ls2k2000-gpio0", 492 .data = &loongson_gpio_ls2k2000_data0, 493 }, 494 { 495 .compatible = "loongson,ls2k2000-gpio1", 496 .data = &loongson_gpio_ls2k2000_data1, 497 }, 498 { 499 .compatible = "loongson,ls2k2000-gpio2", 500 .data = &loongson_gpio_ls2k2000_data2, 501 }, 502 { 503 .compatible = "loongson,ls3a5000-gpio", 504 .data = &loongson_gpio_ls3a5000_data, 505 }, 506 { 507 .compatible = "loongson,ls7a-gpio", 508 .data = &loongson_gpio_ls7a_data, 509 }, 510 { 511 .compatible = "loongson,ls7a2000-gpio1", 512 .data = &loongson_gpio_ls7a2000_data0, 513 }, 514 { 515 .compatible = "loongson,ls7a2000-gpio2", 516 .data = &loongson_gpio_ls7a2000_data1, 517 }, 518 { 519 .compatible = "loongson,ls3a6000-gpio", 520 .data = &loongson_gpio_ls3a6000_data, 521 }, 522 {} 523 }; 524 MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); 525 526 static const struct acpi_device_id loongson_gpio_acpi_match[] = { 527 { 528 .id = "LOON0002", 529 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, 530 }, 531 { 532 .id = "LOON0007", 533 .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data, 534 }, 535 { 536 .id = "LOON000A", 537 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0, 538 }, 539 { 540 .id = "LOON000B", 541 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1, 542 }, 543 { 544 .id = "LOON000C", 545 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, 546 }, 547 { 548 .id = "LOON000D", 549 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data0, 550 }, 551 { 552 .id = "LOON000E", 553 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data1, 554 }, 555 { 556 .id = "LOON000F", 557 .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a6000_data, 558 }, 559 {} 560 }; 561 MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); 562 563 static struct platform_driver loongson_gpio_driver = { 564 .driver = { 565 .name = "loongson-gpio", 566 .of_match_table = loongson_gpio_of_match, 567 .acpi_match_table = loongson_gpio_acpi_match, 568 }, 569 .probe = loongson_gpio_probe, 570 }; 571 572 static int __init loongson_gpio_setup(void) 573 { 574 return platform_driver_register(&loongson_gpio_driver); 575 } 576 postcore_initcall(loongson_gpio_setup); 577 578 MODULE_DESCRIPTION("Loongson gpio driver"); 579 MODULE_LICENSE("GPL"); 580