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

Configure Feed

Select the types of activity you want to include in your feed.

gpio: aspeed-sgpio: Support G7 Aspeed sgpiom controller

In the 7th generation of the SoC from Aspeed, the control logic of the
SGPIO controller has been updated to support per-pin control. Each pin now
has its own 32-bit register, allowing for individual control of the pin's
value, interrupt type, and other settings.

Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Link: https://lore.kernel.org/r/20260123-upstream_sgpio-v2-6-69cfd1631400@aspeedtech.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

authored by

Billy Tsai and committed by
Bartosz Golaszewski
274ea0f1 14947001

+108 -2
+108 -2
drivers/gpio/gpio-aspeed-sgpio.c
··· 19 19 #include <linux/spinlock.h> 20 20 #include <linux/string.h> 21 21 22 - #define ASPEED_SGPIO_CTRL 0x54 22 + #define SGPIO_G7_IRQ_STS_BASE 0x40 23 + #define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4) 24 + #define SGPIO_G7_CTRL_REG_BASE 0x80 25 + #define SGPIO_G7_CTRL_REG_OFFSET(x) (SGPIO_G7_CTRL_REG_BASE + (x) * 0x4) 26 + #define SGPIO_G7_OUT_DATA BIT(0) 27 + #define SGPIO_G7_PARALLEL_OUT_DATA BIT(1) 28 + #define SGPIO_G7_IRQ_EN BIT(2) 29 + #define SGPIO_G7_IRQ_TYPE0 BIT(3) 30 + #define SGPIO_G7_IRQ_TYPE1 BIT(4) 31 + #define SGPIO_G7_IRQ_TYPE2 BIT(5) 32 + #define SGPIO_G7_RST_TOLERANCE BIT(6) 33 + #define SGPIO_G7_INPUT_MASK BIT(9) 34 + #define SGPIO_G7_HW_BYPASS_EN BIT(10) 35 + #define SGPIO_G7_HW_IN_SEL BIT(11) 36 + #define SGPIO_G7_IRQ_STS BIT(12) 37 + #define SGPIO_G7_IN_DATA BIT(13) 38 + #define SGPIO_G7_PARALLEL_IN_DATA BIT(14) 39 + #define SGPIO_G7_SERIAL_OUT_SEL GENMASK(17, 16) 40 + #define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18) 41 + #define SELECT_FROM_CSR 0 42 + #define SELECT_FROM_PARALLEL_IN 1 43 + #define SELECT_FROM_SERIAL_IN 2 44 + 45 + #define ASPEED_SGPIO_G4_CFG_OFFSET 0x54 46 + #define ASPEED_SGPIO_G7_CFG_OFFSET 0x0 23 47 24 48 #define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) 25 49 #define ASPEED_SGPIO_ENABLE BIT(0) ··· 52 28 struct aspeed_sgpio_pdata { 53 29 const u32 pin_mask; 54 30 const struct aspeed_sgpio_llops *llops; 31 + const u32 cfg_offset; 55 32 }; 56 33 57 34 struct aspeed_sgpio { ··· 157 132 default: 158 133 /* acturally if code runs to here, it's an error case */ 159 134 BUG(); 135 + } 136 + } 137 + 138 + static u32 aspeed_sgpio_g7_reg_mask(const enum aspeed_sgpio_reg reg) 139 + { 140 + switch (reg) { 141 + case reg_val: 142 + case reg_rdata: 143 + return SGPIO_G7_OUT_DATA; 144 + case reg_irq_enable: 145 + return SGPIO_G7_IRQ_EN; 146 + case reg_irq_type0: 147 + return SGPIO_G7_IRQ_TYPE0; 148 + case reg_irq_type1: 149 + return SGPIO_G7_IRQ_TYPE1; 150 + case reg_irq_type2: 151 + return SGPIO_G7_IRQ_TYPE2; 152 + case reg_irq_status: 153 + return SGPIO_G7_IRQ_STS; 154 + case reg_tolerance: 155 + return SGPIO_G7_RST_TOLERANCE; 156 + default: 157 + WARN_ON_ONCE(1); 158 + return 0; 160 159 } 161 160 } 162 161 ··· 506 457 static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { 507 458 .pin_mask = GENMASK(9, 6), 508 459 .llops = &aspeed_sgpio_g4_llops, 460 + .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, 509 461 }; 510 462 511 463 static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, ··· 536 486 static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { 537 487 .pin_mask = GENMASK(10, 6), 538 488 .llops = &aspeed_sgpio_g4_llops, 489 + .cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET, 490 + }; 491 + 492 + static void aspeed_sgpio_g7_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, 493 + const enum aspeed_sgpio_reg reg, bool val) 494 + { 495 + u32 mask = aspeed_sgpio_g7_reg_mask(reg); 496 + void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); 497 + u32 write_val; 498 + 499 + if (mask) { 500 + write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); 501 + iowrite32(write_val, addr); 502 + } 503 + } 504 + 505 + static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, 506 + const enum aspeed_sgpio_reg reg) 507 + { 508 + u32 mask = aspeed_sgpio_g7_reg_mask(reg); 509 + void __iomem *addr; 510 + 511 + addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1); 512 + if (reg == reg_val) 513 + mask = SGPIO_G7_IN_DATA; 514 + 515 + if (mask) 516 + return field_get(mask, ioread32(addr)); 517 + else 518 + return 0; 519 + } 520 + 521 + static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, 522 + const enum aspeed_sgpio_reg reg) 523 + { 524 + void __iomem *addr; 525 + 526 + if (reg == reg_irq_status) { 527 + addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6); 528 + return ioread32(addr); 529 + } else { 530 + return -EOPNOTSUPP; 531 + } 532 + } 533 + 534 + static const struct aspeed_sgpio_llops aspeed_sgpio_g7_llops = { 535 + .reg_bit_set = aspeed_sgpio_g7_reg_bit_set, 536 + .reg_bit_get = aspeed_sgpio_g7_reg_bit_get, 537 + .reg_bank_get = aspeed_sgpio_g7_reg_bank_get, 538 + }; 539 + 540 + static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = { 541 + .pin_mask = GENMASK(11, 6), 542 + .llops = &aspeed_sgpio_g7_llops, 543 + .cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET, 539 544 }; 540 545 541 546 static const struct of_device_id aspeed_sgpio_of_table[] = { 542 547 { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, }, 543 548 { .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, }, 544 549 { .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, }, 550 + { .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, }, 545 551 {} 546 552 }; 547 553 ··· 668 562 669 563 gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask; 670 564 iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval | 671 - ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL); 565 + ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset); 672 566 673 567 raw_spin_lock_init(&gpio->lock); 674 568