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: pca953x: Add support for PCAL6534

Add support for the NXP PCAL6534. This device is broadly a 34-bit version
of the PCAL6524. However, whilst the registers are broadly what you'd
expect for a 34-bit version of the PCAL6524, the spacing of the registers
has been compacted. This has the unfortunate effect of breaking the bit
shift based mechanism that is employed to work out register locations used
by the other chips supported by this driver. To accommodate ths, callback
functions have been added to allow alterate implementations of
pca953x_recalc_addr() and pca953x_check_register() for the PCAL6534.

Datasheet: https://www.nxp.com/docs/en/data-sheet/PCAL6534.pdf
Datasheet: https://www.diodes.com/assets/Datasheets/PI4IOE5V6534Q.pdf
Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>

authored by

Martyn Welch and committed by
Bartosz Golaszewski
13c5d4ce 5faf9801

+117 -19
+117 -19
drivers/gpio/gpio-pca953x.c
··· 66 66 #define PCA_LATCH_INT (PCA_PCAL | PCA_INT) 67 67 #define PCA953X_TYPE BIT(12) 68 68 #define PCA957X_TYPE BIT(13) 69 + #define PCAL653X_TYPE BIT(14) 69 70 #define PCA_TYPE_MASK GENMASK(15, 12) 70 71 71 72 #define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK) ··· 93 92 { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, }, 94 93 { "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, }, 95 94 { "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, }, 95 + { "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, }, 96 96 { "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, }, 97 97 { "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, }, 98 98 { "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, }, ··· 214 212 struct regulator *regulator; 215 213 216 214 const struct pca953x_reg_config *regs; 215 + 216 + u8 (*recalc_addr)(struct pca953x_chip *chip, int reg, int off); 217 + bool (*check_reg)(struct pca953x_chip *chip, unsigned int reg, 218 + u32 checkbank); 217 219 }; 218 220 219 221 static int pca953x_bank_shift(struct pca953x_chip *chip) ··· 295 289 return true; 296 290 } 297 291 292 + /* 293 + * Unfortunately, whilst the PCAL6534 chip (and compatibles) broadly follow the 294 + * same register layout as the PCAL6524, the spacing of the registers has been 295 + * fundamentally altered by compacting them and thus does not obey the same 296 + * rules, including being able to use bit shifting to determine bank. These 297 + * chips hence need special handling here. 298 + */ 299 + static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg, 300 + u32 checkbank) 301 + { 302 + int bank; 303 + int offset; 304 + 305 + if (reg >= 0x30) { 306 + /* 307 + * Reserved block between 14h and 2Fh does not align on 308 + * expected bank boundaries like other devices. 309 + */ 310 + int temp = reg - 0x30; 311 + 312 + bank = temp / NBANK(chip); 313 + offset = temp - (bank * NBANK(chip)); 314 + bank += 8; 315 + } else if (reg >= 0x54) { 316 + /* 317 + * Handle lack of reserved registers after output port 318 + * configuration register to form a bank. 319 + */ 320 + int temp = reg - 0x54; 321 + 322 + bank = temp / NBANK(chip); 323 + offset = temp - (bank * NBANK(chip)); 324 + bank += 16; 325 + } else { 326 + bank = reg / NBANK(chip); 327 + offset = reg - (bank * NBANK(chip)); 328 + } 329 + 330 + /* Register is not in the matching bank. */ 331 + if (!(BIT(bank) & checkbank)) 332 + return false; 333 + 334 + /* Register is not within allowed range of bank. */ 335 + if (offset >= NBANK(chip)) 336 + return false; 337 + 338 + return true; 339 + } 340 + 298 341 static bool pca953x_readable_register(struct device *dev, unsigned int reg) 299 342 { 300 343 struct pca953x_chip *chip = dev_get_drvdata(dev); ··· 364 309 PCAL9xxx_BANK_IRQ_STAT; 365 310 } 366 311 367 - return pca953x_check_register(chip, reg, bank); 312 + return chip->check_reg(chip, reg, bank); 368 313 } 369 314 370 315 static bool pca953x_writeable_register(struct device *dev, unsigned int reg) ··· 384 329 bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN | 385 330 PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK; 386 331 387 - return pca953x_check_register(chip, reg, bank); 332 + return chip->check_reg(chip, reg, bank); 388 333 } 389 334 390 335 static bool pca953x_volatile_register(struct device *dev, unsigned int reg) ··· 400 345 if (chip->driver_data & PCA_PCAL) 401 346 bank |= PCAL9xxx_BANK_IRQ_STAT; 402 347 403 - return pca953x_check_register(chip, reg, bank); 348 + return chip->check_reg(chip, reg, bank); 404 349 } 405 350 406 351 static const struct regmap_config pca953x_i2c_regmap = { ··· 445 390 return regaddr; 446 391 } 447 392 393 + /* 394 + * The PCAL6534 and compatible chips have altered bank alignment that doesn't 395 + * fit within the bit shifting scheme used for other devices. 396 + */ 397 + static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off) 398 + { 399 + int addr; 400 + int pinctrl; 401 + 402 + addr = (reg & PCAL_GPIO_MASK) * NBANK(chip); 403 + 404 + switch (reg) { 405 + case PCAL953X_OUT_STRENGTH: 406 + case PCAL953X_IN_LATCH: 407 + case PCAL953X_PULL_EN: 408 + case PCAL953X_PULL_SEL: 409 + case PCAL953X_INT_MASK: 410 + case PCAL953X_INT_STAT: 411 + case PCAL953X_OUT_CONF: 412 + pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20; 413 + break; 414 + case PCAL6524_INT_EDGE: 415 + case PCAL6524_INT_CLR: 416 + case PCAL6524_IN_STATUS: 417 + case PCAL6524_OUT_INDCONF: 418 + case PCAL6524_DEBOUNCE: 419 + pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x1c; 420 + break; 421 + } 422 + 423 + return pinctrl + addr + (off / BANK_SZ); 424 + } 425 + 448 426 static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val) 449 427 { 450 - u8 regaddr = pca953x_recalc_addr(chip, reg, 0); 428 + u8 regaddr = chip->recalc_addr(chip, reg, 0); 451 429 u8 value[MAX_BANK]; 452 430 int i, ret; 453 431 ··· 498 410 499 411 static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val) 500 412 { 501 - u8 regaddr = pca953x_recalc_addr(chip, reg, 0); 413 + u8 regaddr = chip->recalc_addr(chip, reg, 0); 502 414 u8 value[MAX_BANK]; 503 415 int i, ret; 504 416 ··· 517 429 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) 518 430 { 519 431 struct pca953x_chip *chip = gpiochip_get_data(gc); 520 - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); 432 + u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 521 433 u8 bit = BIT(off % BANK_SZ); 522 434 int ret; 523 435 ··· 531 443 unsigned off, int val) 532 444 { 533 445 struct pca953x_chip *chip = gpiochip_get_data(gc); 534 - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); 535 - u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off); 446 + u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 447 + u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); 536 448 u8 bit = BIT(off % BANK_SZ); 537 449 int ret; 538 450 ··· 552 464 static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) 553 465 { 554 466 struct pca953x_chip *chip = gpiochip_get_data(gc); 555 - u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off); 467 + u8 inreg = chip->recalc_addr(chip, chip->regs->input, off); 556 468 u8 bit = BIT(off % BANK_SZ); 557 469 u32 reg_val; 558 470 int ret; ··· 569 481 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) 570 482 { 571 483 struct pca953x_chip *chip = gpiochip_get_data(gc); 572 - u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off); 484 + u8 outreg = chip->recalc_addr(chip, chip->regs->output, off); 573 485 u8 bit = BIT(off % BANK_SZ); 574 486 575 487 mutex_lock(&chip->i2c_lock); ··· 580 492 static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) 581 493 { 582 494 struct pca953x_chip *chip = gpiochip_get_data(gc); 583 - u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off); 495 + u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); 584 496 u8 bit = BIT(off % BANK_SZ); 585 497 u32 reg_val; 586 498 int ret; ··· 639 551 { 640 552 enum pin_config_param param = pinconf_to_config_param(config); 641 553 642 - u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset); 643 - u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset); 554 + u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset); 555 + u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset); 644 556 u8 bit = BIT(offset % BANK_SZ); 645 557 int ret; 646 558 ··· 1003 915 u8 regaddr; 1004 916 int ret; 1005 917 1006 - regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0); 918 + regaddr = chip->recalc_addr(chip, chip->regs->output, 0); 1007 919 ret = regcache_sync_region(chip->regmap, regaddr, 1008 920 regaddr + NBANK(chip) - 1); 1009 921 if (ret) 1010 922 goto out; 1011 923 1012 - regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0); 924 + regaddr = chip->recalc_addr(chip, chip->regs->direction, 0); 1013 925 ret = regcache_sync_region(chip->regmap, regaddr, 1014 926 regaddr + NBANK(chip) - 1); 1015 927 if (ret) ··· 1128 1040 regmap_config = &pca953x_i2c_regmap; 1129 1041 } 1130 1042 1043 + if (PCA_CHIP_TYPE(chip->driver_data) == PCAL653X_TYPE) { 1044 + chip->recalc_addr = pcal6534_recalc_addr; 1045 + chip->check_reg = pcal6534_check_register; 1046 + } else { 1047 + chip->recalc_addr = pca953x_recalc_addr; 1048 + chip->check_reg = pca953x_check_register; 1049 + } 1050 + 1131 1051 chip->regmap = devm_regmap_init_i2c(client, regmap_config); 1132 1052 if (IS_ERR(chip->regmap)) { 1133 1053 ret = PTR_ERR(chip->regmap); ··· 1230 1134 * The ordering between direction and output is important, 1231 1135 * sync these registers first and only then sync the rest. 1232 1136 */ 1233 - regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0); 1137 + regaddr = chip->recalc_addr(chip, chip->regs->direction, 0); 1234 1138 ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1); 1235 1139 if (ret) { 1236 1140 dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret); 1237 1141 return ret; 1238 1142 } 1239 1143 1240 - regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0); 1144 + regaddr = chip->recalc_addr(chip, chip->regs->output, 0); 1241 1145 ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1); 1242 1146 if (ret) { 1243 1147 dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret); ··· 1246 1150 1247 1151 #ifdef CONFIG_GPIO_PCA953X_IRQ 1248 1152 if (chip->driver_data & PCA_PCAL) { 1249 - regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0); 1153 + regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0); 1250 1154 ret = regcache_sync_region(chip->regmap, regaddr, 1251 1155 regaddr + NBANK(chip) - 1); 1252 1156 if (ret) { ··· 1255 1159 return ret; 1256 1160 } 1257 1161 1258 - regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0); 1162 + regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0); 1259 1163 ret = regcache_sync_region(chip->regmap, regaddr, 1260 1164 regaddr + NBANK(chip) - 1); 1261 1165 if (ret) { ··· 1313 1217 #endif 1314 1218 1315 1219 /* convenience to stop overlong match-table lines */ 1220 + #define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int)) 1316 1221 #define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int) 1317 1222 #define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int) 1318 1223 ··· 1339 1242 { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), }, 1340 1243 { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), }, 1341 1244 { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), }, 1245 + { .compatible = "nxp,pcal6534", .data = OF_653X(34, PCA_LATCH_INT), }, 1342 1246 { .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), }, 1343 1247 { .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), }, 1344 1248 { .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },