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.

serial: sc16is7xx: define common register access function

Rename lock/unlock functions to make it more generic and applicable to both
the Enhanced register set and the Special register set.

Use this new generic function when accessing the Special register set in
sc16is7xx_set_baud(), and when accessing the Enhanced register set in
sc16is7xx_set_termios() and sc16is7xx_probe().

This helps readability and also avoid to make future mistakes when
accessing these obfuscated registers.

Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://patch.msgid.link/20251027142957.1032073-4-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Hugo Villeneuve and committed by
Greg Kroah-Hartman
bc20238a d9b2d7dd

+31 -43
+31 -43
drivers/tty/serial/sc16is7xx.c
··· 421 421 } 422 422 423 423 /* 424 - * In an amazing feat of design, the Enhanced Features Register (EFR) 425 - * shares the address of the Interrupt Identification Register (IIR). 426 - * Access to EFR is switched on by writing a magic value (0xbf) to the 427 - * Line Control Register (LCR). Any interrupt firing during this time will 428 - * see the EFR where it expects the IIR to be, leading to 424 + * In an amazing feat of design, the enhanced register set shares the 425 + * addresses 0x02 and 0x04-0x07 with the general register set. 426 + * The special register set also shares the addresses 0x00-0x01 with the 427 + * general register set. 428 + * 429 + * Access to the enhanced or special register set is enabled by writing a magic 430 + * value to the Line Control Register (LCR). When enhanced register set access 431 + * is enabled, for example, any interrupt firing during this time will see the 432 + * EFR where it expects the IIR to be, leading to 429 433 * "Unexpected interrupt" messages. 430 434 * 431 - * Prevent this possibility by claiming a mutex while accessing the EFR, 432 - * and claiming the same mutex from within the interrupt handler. This is 433 - * similar to disabling the interrupt, but that doesn't work because the 434 - * bulk of the interrupt processing is run as a workqueue job in thread 435 - * context. 435 + * Prevent this possibility by claiming a mutex when access to the enhanced 436 + * or special register set is enabled, and claiming the same mutex from within 437 + * the interrupt handler. This is similar to disabling the interrupt, but that 438 + * doesn't work because the bulk of the interrupt processing is run as a 439 + * workqueue job in thread context. 436 440 */ 437 - static void sc16is7xx_efr_lock(struct uart_port *port) 441 + static void sc16is7xx_regs_lock(struct uart_port *port, u8 register_set) 438 442 { 439 443 struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); 440 444 ··· 447 443 /* Backup content of LCR. */ 448 444 one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); 449 445 450 - /* Enable access to Enhanced register set */ 451 - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_REG_SET_ENHANCED); 446 + /* Enable access to the desired register set */ 447 + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, register_set); 452 448 453 - /* Disable cache updates when writing to EFR registers */ 449 + /* Disable cache updates when writing to non-general registers */ 454 450 regcache_cache_bypass(one->regmap, true); 455 451 } 456 452 457 - static void sc16is7xx_efr_unlock(struct uart_port *port) 453 + static void sc16is7xx_regs_unlock(struct uart_port *port) 458 454 { 459 455 struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); 460 456 461 - /* Re-enable cache updates when writing to normal registers */ 457 + /* Re-enable cache updates when writing to general registers */ 462 458 regcache_cache_bypass(one->regmap, false); 463 459 464 460 /* Restore original content of LCR */ ··· 584 580 */ 585 581 static int sc16is7xx_set_baud(struct uart_port *port, int baud) 586 582 { 587 - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); 588 - u8 lcr; 589 583 unsigned int prescaler = 1; 590 584 unsigned long clk = port->uartclk, div = clk / 16 / baud; 591 585 ··· 597 595 SC16IS7XX_MCR_CLKSEL_BIT, 598 596 prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT); 599 597 600 - mutex_lock(&one->lock); 601 - 602 - /* Backup LCR and access special register set (DLL/DLH) */ 603 - lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); 604 - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, 605 - SC16IS7XX_LCR_REG_SET_SPECIAL); 598 + /* Access special register set (DLL/DLH) */ 599 + sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_SPECIAL); 606 600 607 601 /* Write the new divisor */ 608 - regcache_cache_bypass(one->regmap, true); 609 602 sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); 610 603 sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); 611 - regcache_cache_bypass(one->regmap, false); 612 604 613 - /* Restore LCR and access to general register set */ 614 - sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); 615 - 616 - mutex_unlock(&one->lock); 605 + /* Restore access to general register set */ 606 + sc16is7xx_regs_unlock(port); 617 607 618 608 return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); 619 609 } ··· 1102 1108 sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); 1103 1109 1104 1110 /* Update EFR registers */ 1105 - sc16is7xx_efr_lock(port); 1111 + sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED); 1106 1112 sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); 1107 1113 sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); 1108 1114 sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, 1109 1115 SC16IS7XX_EFR_FLOWCTRL_BITS, flow); 1110 - sc16is7xx_efr_unlock(port); 1116 + sc16is7xx_regs_unlock(port); 1111 1117 1112 1118 /* Get baud rate generator configuration */ 1113 1119 baud = uart_get_baud_rate(port, termios, old, ··· 1625 1631 if (ret) 1626 1632 goto out_ports; 1627 1633 1634 + /* Enable access to general register set */ 1635 + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); 1636 + 1628 1637 /* Disable all interrupts */ 1629 1638 sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); 1630 1639 /* Disable TX/RX */ ··· 1647 1650 1648 1651 port_registered[i] = true; 1649 1652 1650 - /* Enable EFR */ 1651 - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 1652 - SC16IS7XX_LCR_REG_SET_ENHANCED); 1653 - 1654 - regcache_cache_bypass(regmaps[i], true); 1655 - 1653 + sc16is7xx_regs_lock(&s->p[i].port, SC16IS7XX_LCR_REG_SET_ENHANCED); 1656 1654 /* Enable write access to enhanced features */ 1657 1655 sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG, 1658 1656 SC16IS7XX_EFR_ENABLE_BIT); 1659 - 1660 - regcache_cache_bypass(regmaps[i], false); 1661 - 1662 - /* Restore access to general registers */ 1663 - sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); 1657 + sc16is7xx_regs_unlock(&s->p[i].port); 1664 1658 1665 1659 /* Go to suspend mode */ 1666 1660 sc16is7xx_power(&s->p[i].port, 0);