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

gpio: pca953x: Add support for TI TCA6418

The TI TCA6418 is a 18-channel I2C I/O expander. It is slightly
different to other models from the same family, such as TCA6416,
but has enough in common with them to make it work with just a
few tweaks, which are explained in the code's documentation.

Signed-off-by: Maria Garcia <mariagarcia7293@gmail.com>
Link: https://lore.kernel.org/r/20250703205740.45385-3-mariagarcia7293@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

authored by

Maria Garcia and committed by
Bartosz Golaszewski
6c99a046 453de04b

+133 -20
+133 -20
drivers/gpio/gpio-pca953x.c
··· 38 38 #define PCA953X_INVERT 0x02 39 39 #define PCA953X_DIRECTION 0x03 40 40 41 + #define TCA6418_INPUT 0x14 42 + #define TCA6418_OUTPUT 0x17 43 + #define TCA6418_DIRECTION 0x23 44 + 41 45 #define REG_ADDR_MASK GENMASK(5, 0) 42 46 #define REG_ADDR_EXT BIT(6) 43 47 #define REG_ADDR_AI BIT(7) ··· 80 76 #define PCA953X_TYPE BIT(12) 81 77 #define PCA957X_TYPE BIT(13) 82 78 #define PCAL653X_TYPE BIT(14) 83 - #define PCA_TYPE_MASK GENMASK(15, 12) 79 + #define TCA6418_TYPE BIT(16) 80 + #define PCA_TYPE_MASK GENMASK(16, 12) 84 81 85 82 #define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK) 86 83 ··· 120 115 { "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, 121 116 { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, 122 117 { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, 118 + { "tca6418", 18 | TCA6418_TYPE | PCA_INT, }, 123 119 { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, 124 120 { "tca9538", 8 | PCA953X_TYPE | PCA_INT, }, 125 121 { "tca9539", 16 | PCA953X_TYPE | PCA_INT, }, ··· 210 204 .invert = PCA957X_INVRT, 211 205 }; 212 206 207 + static const struct pca953x_reg_config tca6418_regs = { 208 + .direction = TCA6418_DIRECTION, 209 + .output = TCA6418_OUTPUT, 210 + .input = TCA6418_INPUT, 211 + .invert = 0xFF, /* Does not apply */ 212 + }; 213 + 213 214 struct pca953x_chip { 214 215 unsigned gpio_start; 215 216 struct mutex i2c_lock; ··· 248 235 static int pca953x_bank_shift(struct pca953x_chip *chip) 249 236 { 250 237 return fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); 238 + } 239 + 240 + /* 241 + * Helper function to get the correct bit mask for a given offset and chip type. 242 + * The TCA6418's input, output, and direction banks have a peculiar bit order: 243 + * the first byte uses reversed bit order, while the second byte uses standard order. 244 + */ 245 + static inline u8 pca953x_get_bit_mask(struct pca953x_chip *chip, unsigned int offset) 246 + { 247 + unsigned int bit_pos_in_bank = offset % BANK_SZ; 248 + int msb = BANK_SZ - 1; 249 + 250 + if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE && offset <= msb) 251 + return BIT(msb - bit_pos_in_bank); 252 + 253 + return BIT(bit_pos_in_bank); 251 254 } 252 255 253 256 #define PCA953x_BANK_INPUT BIT(0) ··· 382 353 return true; 383 354 } 384 355 356 + /* TCA6418 breaks the PCA953x register order rule */ 357 + static bool tca6418_check_register(struct pca953x_chip *chip, unsigned int reg, 358 + u32 access_type_mask) 359 + { 360 + /* Valid Input Registers - BIT(0) for readable access */ 361 + if (reg >= TCA6418_INPUT && reg < (TCA6418_INPUT + NBANK(chip))) 362 + return (access_type_mask & BIT(0)); 363 + 364 + /* Valid Output Registers - BIT(1) for writeable access */ 365 + if (reg >= TCA6418_OUTPUT && reg < (TCA6418_OUTPUT + NBANK(chip))) 366 + return (access_type_mask & (BIT(0) | BIT(1))); 367 + 368 + /* Valid Direction Registers - BIT(2) for volatile access */ 369 + if (reg >= TCA6418_DIRECTION && reg < (TCA6418_DIRECTION + NBANK(chip))) 370 + return (access_type_mask & (BIT(0) | BIT(1))); 371 + 372 + return false; 373 + } 374 + 385 375 static bool pca953x_readable_register(struct device *dev, unsigned int reg) 386 376 { 387 377 struct pca953x_chip *chip = dev_get_drvdata(dev); 388 378 u32 bank; 389 379 390 - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { 380 + switch (PCA_CHIP_TYPE(chip->driver_data)) { 381 + case PCA957X_TYPE: 391 382 bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT | 392 383 PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG | 393 384 PCA957x_BANK_BUSHOLD; 394 - } else { 385 + break; 386 + case TCA6418_TYPE: 387 + /* BIT(0) to indicate read access */ 388 + return tca6418_check_register(chip, reg, BIT(0)); 389 + default: 395 390 bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT | 396 391 PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG; 392 + break; 397 393 } 398 394 399 395 if (chip->driver_data & PCA_PCAL) { ··· 435 381 struct pca953x_chip *chip = dev_get_drvdata(dev); 436 382 u32 bank; 437 383 438 - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { 384 + switch (PCA_CHIP_TYPE(chip->driver_data)) { 385 + case PCA957X_TYPE: 439 386 bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY | 440 387 PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD; 441 - } else { 388 + break; 389 + case TCA6418_TYPE: 390 + /* BIT(1) for write access */ 391 + return tca6418_check_register(chip, reg, BIT(1)); 392 + default: 442 393 bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY | 443 394 PCA953x_BANK_CONFIG; 395 + break; 444 396 } 445 397 446 398 if (chip->driver_data & PCA_PCAL) ··· 461 401 struct pca953x_chip *chip = dev_get_drvdata(dev); 462 402 u32 bank; 463 403 464 - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) 404 + switch (PCA_CHIP_TYPE(chip->driver_data)) { 405 + case PCA957X_TYPE: 465 406 bank = PCA957x_BANK_INPUT; 466 - else 407 + break; 408 + case TCA6418_TYPE: 409 + /* BIT(2) for volatile access */ 410 + return tca6418_check_register(chip, reg, BIT(2)); 411 + default: 467 412 bank = PCA953x_BANK_INPUT; 413 + break; 414 + } 468 415 469 416 if (chip->driver_data & PCA_PCAL) 470 417 bank |= PCAL9xxx_BANK_IRQ_STAT; ··· 556 489 return pinctrl + addr + (off / BANK_SZ); 557 490 } 558 491 492 + static u8 tca6418_recalc_addr(struct pca953x_chip *chip, int reg_base, int offset) 493 + { 494 + /* 495 + * reg_base will be TCA6418_INPUT, TCA6418_OUTPUT, or TCA6418_DIRECTION 496 + * offset is the global GPIO line offset (0-17) 497 + * BANK_SZ is 8 for TCA6418 (8 bits per register bank) 498 + */ 499 + return reg_base + (offset / BANK_SZ); 500 + } 501 + 559 502 static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val) 560 503 { 561 504 u8 regaddr = chip->recalc_addr(chip, reg, 0); ··· 606 529 { 607 530 struct pca953x_chip *chip = gpiochip_get_data(gc); 608 531 u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 609 - u8 bit = BIT(off % BANK_SZ); 532 + u8 bit = pca953x_get_bit_mask(chip, off); 610 533 611 534 guard(mutex)(&chip->i2c_lock); 535 + 536 + if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) 537 + return regmap_write_bits(chip->regmap, dirreg, bit, 0); 612 538 613 539 return regmap_write_bits(chip->regmap, dirreg, bit, bit); 614 540 } ··· 622 542 struct pca953x_chip *chip = gpiochip_get_data(gc); 623 543 u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 624 544 u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); 625 - u8 bit = BIT(off % BANK_SZ); 545 + u8 bit = pca953x_get_bit_mask(chip, off); 626 546 int ret; 627 547 628 548 guard(mutex)(&chip->i2c_lock); ··· 632 552 if (ret) 633 553 return ret; 634 554 635 - /* then direction */ 555 + /* 556 + * then direction 557 + * (in/out logic is inverted on TCA6418) 558 + */ 559 + if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) 560 + return regmap_write_bits(chip->regmap, dirreg, bit, bit); 561 + 636 562 return regmap_write_bits(chip->regmap, dirreg, bit, 0); 637 563 } 638 564 ··· 646 560 { 647 561 struct pca953x_chip *chip = gpiochip_get_data(gc); 648 562 u8 inreg = chip->recalc_addr(chip, chip->regs->input, off); 649 - u8 bit = BIT(off % BANK_SZ); 563 + u8 bit = pca953x_get_bit_mask(chip, off); 650 564 u32 reg_val; 651 565 int ret; 652 566 ··· 663 577 { 664 578 struct pca953x_chip *chip = gpiochip_get_data(gc); 665 579 u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); 666 - u8 bit = BIT(off % BANK_SZ); 580 + u8 bit = pca953x_get_bit_mask(chip, off); 667 581 668 582 guard(mutex)(&chip->i2c_lock); 669 583 ··· 674 588 { 675 589 struct pca953x_chip *chip = gpiochip_get_data(gc); 676 590 u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 677 - u8 bit = BIT(off % BANK_SZ); 591 + u8 bit = pca953x_get_bit_mask(chip, off); 678 592 u32 reg_val; 679 593 int ret; 680 594 ··· 683 597 if (ret < 0) 684 598 return ret; 685 599 686 - if (reg_val & bit) 600 + /* (in/out logic is inverted on TCA6418) */ 601 + if (reg_val & bit) { 602 + if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) 603 + return GPIO_LINE_DIRECTION_OUT; 604 + 605 + return GPIO_LINE_DIRECTION_IN; 606 + } 607 + if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) 687 608 return GPIO_LINE_DIRECTION_IN; 688 609 689 610 return GPIO_LINE_DIRECTION_OUT; ··· 1210 1117 regmap_config = &pca953x_i2c_regmap; 1211 1118 } 1212 1119 1213 - if (PCA_CHIP_TYPE(chip->driver_data) == PCAL653X_TYPE) { 1120 + switch (PCA_CHIP_TYPE(chip->driver_data)) { 1121 + case PCAL653X_TYPE: 1214 1122 chip->recalc_addr = pcal6534_recalc_addr; 1215 1123 chip->check_reg = pcal6534_check_register; 1216 - } else { 1124 + break; 1125 + case TCA6418_TYPE: 1126 + chip->recalc_addr = tca6418_recalc_addr; 1127 + /* 1128 + * We don't assign chip->check_reg = tca6418_check_register directly here. 1129 + * Instead, the wrappers handle the dispatch based on PCA_CHIP_TYPE. 1130 + */ 1131 + break; 1132 + default: 1217 1133 chip->recalc_addr = pca953x_recalc_addr; 1218 1134 chip->check_reg = pca953x_check_register; 1135 + break; 1219 1136 } 1220 1137 1221 1138 chip->regmap = devm_regmap_init_i2c(client, regmap_config); ··· 1254 1151 lockdep_set_subclass(&chip->i2c_lock, 1255 1152 i2c_adapter_depth(client->adapter)); 1256 1153 1257 - /* initialize cached registers from their original values. 1154 + /* 1155 + * initialize cached registers from their original values. 1258 1156 * we can't share this chip with another i2c master. 1259 1157 */ 1260 - if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) { 1158 + switch (PCA_CHIP_TYPE(chip->driver_data)) { 1159 + case PCA957X_TYPE: 1261 1160 chip->regs = &pca957x_regs; 1262 1161 ret = device_pca957x_init(chip); 1263 - } else { 1162 + break; 1163 + case TCA6418_TYPE: 1164 + chip->regs = &tca6418_regs; 1165 + break; 1166 + default: 1264 1167 chip->regs = &pca953x_regs; 1265 1168 ret = device_pca95xx_init(chip); 1169 + break; 1266 1170 } 1267 1171 if (ret) 1268 1172 return ret; ··· 1435 1325 { .compatible = "ti,pca9536", .data = OF_953X( 4, 0), }, 1436 1326 { .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), }, 1437 1327 { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), }, 1328 + { .compatible = "ti,tca6418", .data = (void *)(18 | TCA6418_TYPE | PCA_INT), }, 1438 1329 { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, 1439 1330 { .compatible = "ti,tca9535", .data = OF_953X(16, PCA_INT), }, 1440 1331 { .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), }, ··· 1466 1355 { 1467 1356 return i2c_add_driver(&pca953x_driver); 1468 1357 } 1469 - /* register after i2c postcore initcall and before 1358 + 1359 + /* 1360 + * register after i2c postcore initcall and before 1470 1361 * subsys initcalls that may rely on these GPIOs 1471 1362 */ 1472 1363 subsys_initcall(pca953x_init);