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: Create llops to handle hardware access

Add low-level operations (llops) to abstract the register access for SGPIO
registers. With this abstraction layer, the driver can separate the
hardware and software logic, making it easier to extend the driver to
support different hardware register layouts.
The llops abstraction changes the programming semantics from bitmask-based
writes to a value-based interface.

Instead of passing a pre-shifted bitmask to the caller, the driver now
passes:
- the GPIO offset, and
- the value to be set (0 or 1),

and the llops helpers are responsible for deriving the correct register
and bit position internally.

As a result, assignments such as:
type0 = 1;
type1 = 1;
type2 = 1;
do not represent a behavioral change. They indicate that the bit
corresponding to the given GPIO offset should be set, with the actual
bit manipulation handled by llops.

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-3-69cfd1631400@aspeedtech.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

authored by

Billy Tsai and committed by
Bartosz Golaszewski
a3d37e0c 5928e0d1

+104 -118
+104 -118
drivers/gpio/gpio-aspeed-sgpio.c
··· 27 27 28 28 struct aspeed_sgpio_pdata { 29 29 const u32 pin_mask; 30 + const struct aspeed_sgpio_llops *llops; 30 31 }; 31 32 32 33 struct aspeed_sgpio { ··· 37 36 raw_spinlock_t lock; 38 37 void __iomem *base; 39 38 int irq; 39 + const struct aspeed_sgpio_pdata *pdata; 40 40 }; 41 41 42 42 struct aspeed_sgpio_bank { ··· 92 90 reg_tolerance, 93 91 }; 94 92 93 + struct aspeed_sgpio_llops { 94 + void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset, 95 + const enum aspeed_sgpio_reg reg, bool val); 96 + bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset, 97 + const enum aspeed_sgpio_reg reg); 98 + int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset, 99 + const enum aspeed_sgpio_reg reg); 100 + }; 101 + 95 102 #define GPIO_VAL_VALUE 0x00 96 103 #define GPIO_IRQ_ENABLE 0x00 97 104 #define GPIO_IRQ_TYPE0 0x04 ··· 108 97 #define GPIO_IRQ_TYPE2 0x0C 109 98 #define GPIO_IRQ_STATUS 0x10 110 99 111 - static void __iomem *bank_reg(struct aspeed_sgpio *gpio, 112 - const struct aspeed_sgpio_bank *bank, 113 - const enum aspeed_sgpio_reg reg) 100 + static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio, 101 + const struct aspeed_sgpio_bank *bank, 102 + const enum aspeed_sgpio_reg reg) 114 103 { 115 104 switch (reg) { 116 105 case reg_val: ··· 176 165 static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) 177 166 { 178 167 struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 179 - const struct aspeed_sgpio_bank *bank = to_bank(offset); 180 168 enum aspeed_sgpio_reg reg; 181 169 int rc = 0; 182 170 183 171 guard(raw_spinlock_irqsave)(&gpio->lock); 184 172 185 173 reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; 186 - rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); 174 + rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg); 187 175 188 176 return rc; 189 177 } ··· 190 180 static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) 191 181 { 192 182 struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 193 - const struct aspeed_sgpio_bank *bank = to_bank(offset); 194 - void __iomem *addr_r, *addr_w; 195 - u32 reg = 0; 196 183 197 184 if (aspeed_sgpio_is_input(offset)) 198 185 return -EINVAL; 199 186 200 - /* Since this is an output, read the cached value from rdata, then 201 - * update val. */ 202 - addr_r = bank_reg(gpio, bank, reg_rdata); 203 - addr_w = bank_reg(gpio, bank, reg_val); 204 - 205 - reg = ioread32(addr_r); 206 - 207 - if (val) 208 - reg |= GPIO_BIT(offset); 209 - else 210 - reg &= ~GPIO_BIT(offset); 211 - 212 - iowrite32(reg, addr_w); 187 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val); 213 188 214 189 return 0; 215 190 } ··· 233 238 return !!aspeed_sgpio_is_input(offset); 234 239 } 235 240 236 - static void irqd_to_aspeed_sgpio_data(struct irq_data *d, 237 - struct aspeed_sgpio **gpio, 238 - const struct aspeed_sgpio_bank **bank, 239 - u32 *bit, int *offset) 240 - { 241 - struct aspeed_sgpio *internal; 242 - 243 - *offset = irqd_to_hwirq(d); 244 - internal = irq_data_get_irq_chip_data(d); 245 - WARN_ON(!internal); 246 - 247 - *gpio = internal; 248 - *bank = to_bank(*offset); 249 - *bit = GPIO_BIT(*offset); 250 - } 251 241 252 242 static void aspeed_sgpio_irq_ack(struct irq_data *d) 253 243 { 254 - const struct aspeed_sgpio_bank *bank; 255 - struct aspeed_sgpio *gpio; 256 - void __iomem *status_addr; 257 - int offset; 258 - u32 bit; 259 - 260 - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 261 - 262 - status_addr = bank_reg(gpio, bank, reg_irq_status); 244 + struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); 245 + int offset = irqd_to_hwirq(d); 263 246 264 247 guard(raw_spinlock_irqsave)(&gpio->lock); 265 248 266 - iowrite32(bit, status_addr); 249 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); 267 250 } 268 251 269 252 static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) 270 253 { 271 - const struct aspeed_sgpio_bank *bank; 272 - struct aspeed_sgpio *gpio; 273 - u32 reg, bit; 274 - void __iomem *addr; 275 - int offset; 276 - 277 - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 278 - addr = bank_reg(gpio, bank, reg_irq_enable); 254 + struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); 255 + int offset = irqd_to_hwirq(d); 279 256 280 257 /* Unmasking the IRQ */ 281 258 if (set) 282 - gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); 283 - 284 - scoped_guard(raw_spinlock_irqsave, &gpio->lock) { 285 - reg = ioread32(addr); 286 - if (set) 287 - reg |= bit; 288 - else 289 - reg &= ~bit; 290 - 291 - iowrite32(reg, addr); 259 + gpiochip_enable_irq(&gpio->chip, offset); 260 + scoped_guard(raw_spinlock_irqsave, &gpio->lock) 261 + { 262 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable, 263 + set); 292 264 } 293 265 294 266 /* Masking the IRQ */ 295 267 if (!set) 296 - gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d)); 297 - 298 - 268 + gpiochip_disable_irq(&gpio->chip, offset); 299 269 } 300 270 301 271 static void aspeed_sgpio_irq_mask(struct irq_data *d) ··· 278 318 u32 type0 = 0; 279 319 u32 type1 = 0; 280 320 u32 type2 = 0; 281 - u32 bit, reg; 282 - const struct aspeed_sgpio_bank *bank; 283 321 irq_flow_handler_t handler; 284 - struct aspeed_sgpio *gpio; 285 - void __iomem *addr; 286 - int offset; 287 - 288 - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 322 + struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); 323 + int offset = irqd_to_hwirq(d); 289 324 290 325 switch (type & IRQ_TYPE_SENSE_MASK) { 291 326 case IRQ_TYPE_EDGE_BOTH: 292 - type2 |= bit; 327 + type2 = 1; 293 328 fallthrough; 294 329 case IRQ_TYPE_EDGE_RISING: 295 - type0 |= bit; 330 + type0 = 1; 296 331 fallthrough; 297 332 case IRQ_TYPE_EDGE_FALLING: 298 333 handler = handle_edge_irq; 299 334 break; 300 335 case IRQ_TYPE_LEVEL_HIGH: 301 - type0 |= bit; 336 + type0 = 1; 302 337 fallthrough; 303 338 case IRQ_TYPE_LEVEL_LOW: 304 - type1 |= bit; 339 + type1 = 1; 305 340 handler = handle_level_irq; 306 341 break; 307 342 default: ··· 304 349 } 305 350 306 351 scoped_guard(raw_spinlock_irqsave, &gpio->lock) { 307 - addr = bank_reg(gpio, bank, reg_irq_type0); 308 - reg = ioread32(addr); 309 - reg = (reg & ~bit) | type0; 310 - iowrite32(reg, addr); 311 - 312 - addr = bank_reg(gpio, bank, reg_irq_type1); 313 - reg = ioread32(addr); 314 - reg = (reg & ~bit) | type1; 315 - iowrite32(reg, addr); 316 - 317 - addr = bank_reg(gpio, bank, reg_irq_type2); 318 - reg = ioread32(addr); 319 - reg = (reg & ~bit) | type2; 320 - iowrite32(reg, addr); 352 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); 353 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); 354 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); 321 355 } 322 356 323 357 irq_set_handler_locked(d, handler); ··· 325 381 chained_irq_enter(ic, desc); 326 382 327 383 for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { 328 - const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; 329 - 330 - reg = ioread32(bank_reg(data, bank, reg_irq_status)); 384 + reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status); 331 385 332 386 for_each_set_bit(p, &reg, 32) 333 387 generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2); ··· 336 394 337 395 static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) 338 396 { 339 - const struct aspeed_sgpio_bank *bank; 340 - struct aspeed_sgpio *gpio; 341 - u32 bit; 342 - int offset; 397 + struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d); 343 398 344 - irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 345 399 seq_puts(p, dev_name(gpio->dev)); 346 400 } 347 401 ··· 385 447 386 448 /* Apply default IRQ settings */ 387 449 for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { 388 - bank = &aspeed_sgpio_banks[i]; 450 + bank = &aspeed_sgpio_banks[i]; 389 451 /* set falling or level-low irq */ 390 452 iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); 391 453 /* trigger type is edge */ ··· 397 459 return 0; 398 460 } 399 461 462 + static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset, 463 + const enum aspeed_sgpio_reg reg, bool val) 464 + { 465 + const struct aspeed_sgpio_bank *bank = to_bank(offset); 466 + void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); 467 + u32 temp; 468 + 469 + if (reg == reg_val) { 470 + /* Since this is an output, read the cached value from rdata, then update val. */ 471 + addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata); 472 + temp = ioread32(addr); 473 + if (val) 474 + temp |= GPIO_BIT(offset); 475 + else 476 + temp &= ~GPIO_BIT(offset); 477 + 478 + addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val); 479 + iowrite32(temp, addr); 480 + } else if (reg == reg_irq_status) { 481 + if (val) 482 + iowrite32(GPIO_BIT(offset), addr); 483 + } else { 484 + /* When setting other registers, we read from the register itself */ 485 + temp = ioread32(addr); 486 + if (val) 487 + temp |= GPIO_BIT(offset); 488 + else 489 + temp &= ~GPIO_BIT(offset); 490 + iowrite32(temp, addr); 491 + } 492 + } 493 + 494 + static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset, 495 + const enum aspeed_sgpio_reg reg) 496 + { 497 + const struct aspeed_sgpio_bank *bank = to_bank(offset); 498 + void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); 499 + 500 + return !!(ioread32(addr) & GPIO_BIT(offset)); 501 + } 502 + 503 + static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset, 504 + const enum aspeed_sgpio_reg reg) 505 + { 506 + const struct aspeed_sgpio_bank *bank = to_bank(offset); 507 + void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg); 508 + 509 + if (reg == reg_irq_status) 510 + return ioread32(addr); 511 + else 512 + return -EOPNOTSUPP; 513 + } 514 + 515 + static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = { 516 + .reg_bit_set = aspeed_sgpio_g4_reg_bit_set, 517 + .reg_bit_get = aspeed_sgpio_g4_reg_bit_get, 518 + .reg_bank_get = aspeed_sgpio_g4_reg_bank_get, 519 + }; 520 + 400 521 static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = { 401 522 .pin_mask = GENMASK(9, 6), 523 + .llops = &aspeed_sgpio_g4_llops, 402 524 }; 403 525 404 526 static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip, 405 527 unsigned int offset, bool enable) 406 528 { 407 529 struct aspeed_sgpio *gpio = gpiochip_get_data(chip); 408 - void __iomem *reg; 409 - u32 val; 410 - 411 - reg = bank_reg(gpio, to_bank(offset), reg_tolerance); 412 530 413 531 guard(raw_spinlock_irqsave)(&gpio->lock); 414 532 415 - val = readl(reg); 416 - 417 - if (enable) 418 - val |= GPIO_BIT(offset); 419 - else 420 - val &= ~GPIO_BIT(offset); 421 - 422 - writel(val, reg); 533 + gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); 423 534 424 535 return 0; 425 536 } ··· 487 500 488 501 static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = { 489 502 .pin_mask = GENMASK(10, 6), 503 + .llops = &aspeed_sgpio_g4_llops, 490 504 }; 491 505 492 506 static const struct of_device_id aspeed_sgpio_of_table[] = { ··· 502 514 static int aspeed_sgpio_probe(struct platform_device *pdev) 503 515 { 504 516 u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask; 505 - const struct aspeed_sgpio_pdata *pdata; 506 517 struct aspeed_sgpio *gpio; 507 518 unsigned long apb_freq; 508 519 int rc; ··· 516 529 517 530 gpio->dev = &pdev->dev; 518 531 519 - pdata = device_get_match_data(&pdev->dev); 520 - if (!pdata) 532 + gpio->pdata = device_get_match_data(&pdev->dev); 533 + if (!gpio->pdata) 521 534 return -EINVAL; 522 535 523 - pin_mask = pdata->pin_mask; 524 - 536 + pin_mask = gpio->pdata->pin_mask; 525 537 rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios); 526 538 if (rc < 0) { 527 539 dev_err(&pdev->dev, "Could not read ngpios property\n");