lkml.org 
[lkml]   [2023]   [May]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v3 09/11] serial: sc16is7xx: add I/O register translation offset
    On Thu, 25 May 2023, Hugo Villeneuve wrote:

    > From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
    >
    > If the shared GPIO pins on a dual port/channel variant like the
    > SC16IS752 are configured as GPIOs for port A, and modem control lines
    > on port A, we need to translate the Linux GPIO offset to an offset
    > that is compatible with the I/O registers of the SC16IS7XX (IOState,
    > IODir and IOIntEna).
    >
    > Add a new variable to store that offset and set it when we detect that
    > special case.
    >
    > Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
    > ---
    > drivers/tty/serial/sc16is7xx.c | 54 +++++++++++++++++++++++++++++++++-
    > 1 file changed, 53 insertions(+), 1 deletion(-)
    >
    > diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
    > index 97ec532a0a19..c2cfd057ed9a 100644
    > --- a/drivers/tty/serial/sc16is7xx.c
    > +++ b/drivers/tty/serial/sc16is7xx.c
    > @@ -338,6 +338,7 @@ struct sc16is7xx_port {
    > #ifdef CONFIG_GPIOLIB
    > struct gpio_chip gpio;
    > int gpio_configured;
    > + int gpio_offset;
    > #endif
    > unsigned char buf[SC16IS7XX_FIFO_SIZE];
    > struct kthread_worker kworker;
    > @@ -1298,12 +1299,50 @@ static const struct uart_ops sc16is7xx_ops = {
    > };
    >
    > #ifdef CONFIG_GPIOLIB
    > +
    > +/*
    > + * We may need to translate the Linux GPIO offset to a SC16IS7XX offset.
    > + * This is needed only for the case where a dual port variant is configured to
    > + * have only port B as modem status lines.
    > + *
    > + * Example for SC16IS752/762 with upper bank (port A) set as GPIOs, and
    > + * lower bank (port B) set as modem status lines (special case described above):
    > + *
    > + * Pin GPIO pin Linux GPIO SC16IS7XX
    > + * name function offset offset
    > + * --------------------------------------------------
    > + * GPIO7/RIA GPIO7 3 7
    > + * GPIO6/CDA GPIO6 2 6
    > + * GPIO5/DTRA GPIO5 1 5
    > + * GPIO4/DSRA GPIO4 0 4
    > + * GPIO3/RIB RIB N/A N/A
    > + * GPIO2/CDB CDB N/A N/A
    > + * GPIO1/DTRB DTRB N/A N/A
    > + * GPIO0/DSRB DSRB N/A N/A
    > + *
    > + * Example for SC16IS750/760 with upper bank (7..4) set as modem status lines,
    > + * and lower bank (3..0) as GPIOs:
    > + *
    > + * Pin GPIO pin Linux GPIO SC16IS7XX
    > + * name function offset offset
    > + * --------------------------------------------------
    > + * GPIO7/RI RI N/A N/A
    > + * GPIO6/CD CD N/A N/A
    > + * GPIO5/DTR DTR N/A N/A
    > + * GPIO4/DSR DSR N/A N/A
    > + * GPIO3 GPIO3 3 3
    > + * GPIO2 GPIO2 2 2
    > + * GPIO1 GPIO1 1 1
    > + * GPIO0 GPIO0 0 0
    > + */
    > +
    > static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
    > {
    > unsigned int val;
    > struct sc16is7xx_port *s = gpiochip_get_data(chip);
    > struct uart_port *port = &s->p[0].port;
    >
    > + offset += s->gpio_offset;
    > val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG);
    >
    > return !!(val & BIT(offset));
    > @@ -1314,6 +1353,7 @@ static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
    > struct sc16is7xx_port *s = gpiochip_get_data(chip);
    > struct uart_port *port = &s->p[0].port;
    >
    > + offset += s->gpio_offset;
    > sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
    > val ? BIT(offset) : 0);
    > }
    > @@ -1324,6 +1364,7 @@ static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
    > struct sc16is7xx_port *s = gpiochip_get_data(chip);
    > struct uart_port *port = &s->p[0].port;
    >
    > + offset += s->gpio_offset;
    > sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0);
    >
    > return 0;
    > @@ -1336,6 +1377,8 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
    > struct uart_port *port = &s->p[0].port;
    > u8 state = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG);
    >
    > + offset += s->gpio_offset;
    > +
    > if (val)
    > state |= BIT(offset);
    > else
    > @@ -1395,6 +1438,7 @@ static int sc16is7xx_probe(struct device *dev,
    >
    > #ifdef CONFIG_GPIOLIB
    > s->gpio_configured = devtype->nr_gpio;
    > + s->gpio_offset = 0;
    > #endif /* CONFIG_GPIOLIB */
    >
    > /* Always ask for fixed clock rate from a property. */
    > @@ -1529,16 +1573,24 @@ static int sc16is7xx_probe(struct device *dev,
    > #endif /* CONFIG_GPIOLIB */
    > }
    >
    > - if (val)
    > + if (val) {
    > +#ifdef CONFIG_GPIOLIB
    > + /* Additional I/O regs offset. */
    > + if (val == SC16IS7XX_IOCONTROL_MODEM_B_BIT)
    > + s->gpio_offset = SC16IS7XX_GPIOS_PER_BANK;
    > +#endif /* CONFIG_GPIOLIB */
    > +
    > regmap_update_bits(
    > s->regmap,
    > SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
    > SC16IS7XX_IOCONTROL_MODEM_A_BIT |
    > SC16IS7XX_IOCONTROL_MODEM_B_BIT, val);
    > + }
    > }
    >
    > #ifdef CONFIG_GPIOLIB
    > dev_dbg(dev, "GPIOs to configure: %d\n", s->gpio_configured);
    > + dev_dbg(dev, "GPIOs offset: %d\n", s->gpio_offset);
    >
    > if (s->gpio_configured) {
    > /* Setup GPIO controller */
    >

    Is the order of this and 8/11 patch correct or should this precede that
    other patch? That is, is 8/11 alone useful enough or would this also be
    wanted? (I'm aware that 8/11 has a Fixes tag).

    --
    i.

    \
     
     \ /
      Last update: 2023-05-25 14:11    [W:2.603 / U:0.088 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site