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 spin_lock_init(&lgpio->lock); 316 } 317 318 lgpio->chip.gc.label = lgpio->chip_data->label; 319 lgpio->chip.gc.can_sleep = false; 320 if (lgpio->chip_data->girqchip) { 321 ret = loongson_gpio_init_irqchip(pdev, lgpio); 322 if (ret) 323 return dev_err_probe(&pdev->dev, ret, "failed to initialize irqchip\n"); 324 } else if (lgpio->chip_data->inten_offset) { 325 lgpio->chip.gc.to_irq = loongson_gpio_to_irq; 326 } 327 328 return devm_gpiochip_add_data(&pdev->dev, &lgpio->chip.gc, lgpio); 329 } 330 331 static int loongson_gpio_probe(struct platform_device *pdev) 332 { 333 void __iomem *reg_base; 334 struct loongson_gpio_chip *lgpio; 335 struct device *dev = &pdev->dev; 336 struct reset_control *rst; 337 338 lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); 339 if (!lgpio) 340 return -ENOMEM; 341 342 lgpio->chip_data = device_get_match_data(dev); 343 344 reg_base = devm_platform_ioremap_resource(pdev, 0); 345 if (IS_ERR(reg_base)) 346 return PTR_ERR(reg_base); 347 348 rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, NULL); 349 if (IS_ERR(rst)) 350 return dev_err_probe(&pdev->dev, PTR_ERR(rst), "failed to get reset control\n"); 351 352 return loongson_gpio_init(pdev, lgpio, reg_base); 353 } 354 355 static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { 356 .label = "ls2k_gpio", 357 .mode = BIT_CTRL_MODE, 358 .conf_offset = 0x0, 359 .in_offset = 0x20, 360 .out_offset = 0x10, 361 .inten_offset = 0x30, 362 }; 363 364 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0300_data = { 365 .label = "ls2k0300_gpio", 366 .mode = BYTE_CTRL_MODE, 367 .conf_offset = 0x800, 368 .in_offset = 0xa00, 369 .out_offset = 0x900, 370 .inten_offset = 0xb00, 371 .intpol_offset = 0xc00, 372 .intedge_offset = 0xd00, 373 .intclr_offset = 0xe00, 374 .intsts_offset = 0xf00, 375 .intdual_offset = 0xf80, 376 .intr_num = 7, 377 .irq_handler = loongson_gpio_ls2k0300_irq_handler, 378 .girqchip = &loongson_gpio_ls2k0300_irqchip, 379 }; 380 381 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = { 382 .label = "ls2k0500_gpio", 383 .mode = BIT_CTRL_MODE, 384 .conf_offset = 0x0, 385 .in_offset = 0x8, 386 .out_offset = 0x10, 387 .inten_offset = 0xb0, 388 }; 389 390 static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = { 391 .label = "ls2k0500_gpio", 392 .mode = BIT_CTRL_MODE, 393 .conf_offset = 0x0, 394 .in_offset = 0x8, 395 .out_offset = 0x10, 396 .inten_offset = 0x98, 397 }; 398 399 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { 400 .label = "ls2k2000_gpio", 401 .mode = BIT_CTRL_MODE, 402 .conf_offset = 0x0, 403 .in_offset = 0xc, 404 .out_offset = 0x8, 405 .inten_offset = 0x14, 406 }; 407 408 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { 409 .label = "ls2k2000_gpio", 410 .mode = BIT_CTRL_MODE, 411 .conf_offset = 0x0, 412 .in_offset = 0x20, 413 .out_offset = 0x10, 414 .inten_offset = 0x30, 415 }; 416 417 static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { 418 .label = "ls2k2000_gpio", 419 .mode = BIT_CTRL_MODE, 420 .conf_offset = 0x4, 421 .in_offset = 0x8, 422 .out_offset = 0x0, 423 }; 424 425 static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = { 426 .label = "ls3a5000_gpio", 427 .mode = BIT_CTRL_MODE, 428 .conf_offset = 0x0, 429 .in_offset = 0xc, 430 .out_offset = 0x8, 431 .inten_offset = 0x14, 432 }; 433 434 static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { 435 .label = "ls7a_gpio", 436 .mode = BYTE_CTRL_MODE, 437 .conf_offset = 0x800, 438 .in_offset = 0xa00, 439 .out_offset = 0x900, 440 .inten_offset = 0xb00, 441 }; 442 443 /* LS7A2000 chipset GPIO */ 444 static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { 445 .label = "ls7a2000_gpio", 446 .mode = BYTE_CTRL_MODE, 447 .conf_offset = 0x800, 448 .in_offset = 0xa00, 449 .out_offset = 0x900, 450 .inten_offset = 0xb00, 451 }; 452 453 /* LS7A2000 ACPI GPIO */ 454 static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { 455 .label = "ls7a2000_gpio", 456 .mode = BIT_CTRL_MODE, 457 .conf_offset = 0x4, 458 .in_offset = 0x8, 459 .out_offset = 0x0, 460 }; 461 462 /* Loongson-3A6000 node GPIO */ 463 static const struct loongson_gpio_chip_data loongson_gpio_ls3a6000_data = { 464 .label = "ls3a6000_gpio", 465 .mode = BIT_CTRL_MODE, 466 .conf_offset = 0x0, 467 .in_offset = 0xc, 468 .out_offset = 0x8, 469 .inten_offset = 0x14, 470 }; 471 472 static const struct of_device_id loongson_gpio_of_match[] = { 473 { 474 .compatible = "loongson,ls2k-gpio", 475 .data = &loongson_gpio_ls2k_data, 476 }, 477 { 478 .compatible = "loongson,ls2k0300-gpio", 479 .data = &loongson_gpio_ls2k0300_data, 480 }, 481 { 482 .compatible = "loongson,ls2k0500-gpio0", 483 .data = &loongson_gpio_ls2k0500_data0, 484 }, 485 { 486 .compatible = "loongson,ls2k0500-gpio1", 487 .data = &loongson_gpio_ls2k0500_data1, 488 }, 489 { 490 .compatible = "loongson,ls2k2000-gpio0", 491 .data = &loongson_gpio_ls2k2000_data0, 492 }, 493 { 494 .compatible = "loongson,ls2k2000-gpio1", 495 .data = &loongson_gpio_ls2k2000_data1, 496 }, 497 { 498 .compatible = "loongson,ls2k2000-gpio2", 499 .data = &loongson_gpio_ls2k2000_data2, 500 }, 501 { 502 .compatible = "loongson,ls3a5000-gpio", 503 .data = &loongson_gpio_ls3a5000_data, 504 }, 505 { 506 .compatible = "loongson,ls7a-gpio", 507 .data = &loongson_gpio_ls7a_data, 508 }, 509 { 510 .compatible = "loongson,ls7a2000-gpio1", 511 .data = &loongson_gpio_ls7a2000_data0, 512 }, 513 { 514 .compatible = "loongson,ls7a2000-gpio2", 515 .data = &loongson_gpio_ls7a2000_data1, 516 }, 517 { 518 .compatible = "loongson,ls3a6000-gpio", 519 .data = &loongson_gpio_ls3a6000_data, 520 }, 521 {} 522 }; 523 MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); 524 525 static const struct acpi_device_id loongson_gpio_acpi_match[] = { 526 { 527 .id = "LOON0002", 528 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, 529 }, 530 { 531 .id = "LOON0007", 532 .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data, 533 }, 534 { 535 .id = "LOON000A", 536 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0, 537 }, 538 { 539 .id = "LOON000B", 540 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1, 541 }, 542 { 543 .id = "LOON000C", 544 .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, 545 }, 546 { 547 .id = "LOON000D", 548 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data0, 549 }, 550 { 551 .id = "LOON000E", 552 .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data1, 553 }, 554 { 555 .id = "LOON000F", 556 .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a6000_data, 557 }, 558 {} 559 }; 560 MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); 561 562 static struct platform_driver loongson_gpio_driver = { 563 .driver = { 564 .name = "loongson-gpio", 565 .of_match_table = loongson_gpio_of_match, 566 .acpi_match_table = loongson_gpio_acpi_match, 567 }, 568 .probe = loongson_gpio_probe, 569 }; 570 571 static int __init loongson_gpio_setup(void) 572 { 573 return platform_driver_register(&loongson_gpio_driver); 574 } 575 postcore_initcall(loongson_gpio_setup); 576 577 MODULE_DESCRIPTION("Loongson gpio driver"); 578 MODULE_LICENSE("GPL"); 579