Message ID | 20240420182223.1153195-4-rilian.la.te@ya.ru |
---|---|
State | Superseded |
Headers | show |
Series | [v5,1/3] serial: sc16is7xx: announce support of SER_RS485_RTS_ON_SEND | expand |
On 20. 04. 24, 20:22, Konstantin Pugin wrote: > From: Konstantin Pugin <ria.freelander@gmail.com> > > XR20M1172 register set is mostly compatible with SC16IS762, but it has > a support for additional division rates of UART with special DLD register. > So, add handling this register by appropriate devicetree bindings. ... > --- a/drivers/tty/serial/sc16is7xx.c > +++ b/drivers/tty/serial/sc16is7xx.c ... > @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) > return reg == SC16IS7XX_RHR_REG; > } > > +static bool sc16is7xx_has_dld(struct device *dev) > +{ > + struct sc16is7xx_port *s = dev_get_drvdata(dev); > + > + if (s->devtype == &xr20m1172_devtype) > + return true; > + return false; :) so this should simply be: return s->devtype == &xr20m1172_devtype; ... > @@ -1002,6 +1052,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > const struct ktermios *old) > { > struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); > + bool has_dld = sc16is7xx_has_dld(port->dev); > unsigned int lcr, flow = 0; > int baud; > unsigned long flags; > @@ -1084,7 +1135,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > /* Get baud rate generator configuration */ > baud = uart_get_baud_rate(port, termios, old, > port->uartclk / 16 / 4 / 0xffff, > - port->uartclk / 16); > + port->uartclk / (has_dld ? 4 : 16)); Could you do this instead: unsigned int divisor = sc16is7xx_has_dld(port->dev) ? 4 : 16; ... uart_get_baud_rate(..., port->uartclk / divisor); I am not sure the above warrants for a new version. Just in case you are sending one. thanks,
I do not think this is a requirement for a new version. I need to wait. Some folks want to test my patches with their hardware))) On Mon, Apr 22, 2024 at 9:30 AM Jiri Slaby <jirislaby@kernel.org> wrote: > > On 20. 04. 24, 20:22, Konstantin Pugin wrote: > > From: Konstantin Pugin <ria.freelander@gmail.com> > > > > XR20M1172 register set is mostly compatible with SC16IS762, but it has > > a support for additional division rates of UART with special DLD register. > > So, add handling this register by appropriate devicetree bindings. > ... > > --- a/drivers/tty/serial/sc16is7xx.c > > +++ b/drivers/tty/serial/sc16is7xx.c > ... > > @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) > > return reg == SC16IS7XX_RHR_REG; > > } > > > > +static bool sc16is7xx_has_dld(struct device *dev) > > +{ > > + struct sc16is7xx_port *s = dev_get_drvdata(dev); > > + > > + if (s->devtype == &xr20m1172_devtype) > > + return true; > > + return false; > > :) so this should simply be: > > return s->devtype == &xr20m1172_devtype; > > ... > > @@ -1002,6 +1052,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > > const struct ktermios *old) > > { > > struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); > > + bool has_dld = sc16is7xx_has_dld(port->dev); > > unsigned int lcr, flow = 0; > > int baud; > > unsigned long flags; > > @@ -1084,7 +1135,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > > /* Get baud rate generator configuration */ > > baud = uart_get_baud_rate(port, termios, old, > > port->uartclk / 16 / 4 / 0xffff, > > - port->uartclk / 16); > > + port->uartclk / (has_dld ? 4 : 16)); > > Could you do this instead: > unsigned int divisor = sc16is7xx_has_dld(port->dev) ? 4 : 16; > > ... > > uart_get_baud_rate(..., port->uartclk / divisor); > > > I am not sure the above warrants for a new version. Just in case you are > sending one. > > thanks, > -- > js > suse labs >
On Mon, Apr 22, 2024 at 11:35:32AM +0300, Konstantin P. wrote: > I do not think this is a requirement for a new version. I need to > wait. Some folks want to test my patches with their hardware))) You should not top-post! ... Yes, it would be good them to provide a formal Tested-by tag, then you may send a v6 with the tags and Jiri's comments being addressed. Btw, I prefer to have them addressed now to eliminate unneeded churn in the future. > On Mon, Apr 22, 2024 at 9:30 AM Jiri Slaby <jirislaby@kernel.org> wrote: > > On 20. 04. 24, 20:22, Konstantin Pugin wrote: > > I am not sure the above warrants for a new version. Just in case you are > > sending one.
On Sat, Apr 20, 2024 at 09:22:06PM +0300, Konstantin Pugin wrote: > From: Konstantin Pugin <ria.freelander@gmail.com> > > XR20M1172 register set is mostly compatible with SC16IS762, but it has > a support for additional division rates of UART with special DLD register. > So, add handling this register by appropriate devicetree bindings. ... > help > - Core driver for NXP SC16IS7xx UARTs. > + Core driver for NXP SC16IS7xx-compatible UARTs. '-compatible' --> ' and compatible' > Supported ICs are: > - > - SC16IS740 > - SC16IS741 > - SC16IS750 > - SC16IS752 > - SC16IS760 > - SC16IS762 > + NXP: > + SC16IS740 > + SC16IS741 > + SC16IS750 > + SC16IS752 > + SC16IS760 > + SC16IS762 You broke the indentation (as it has mixed TABs and spaces). > + EXAR: > + XR20M1172 No need to rewrite all of them, just add your line as XR20M1172 (Exar) > The driver supports both I2C and SPI interfaces. (Note, this needs to be fixed, hence it justifies a new version of the patch.) ... > +/* > + * Divisor Fractional Register bits (EXAR extension) Missing period at the end of the line. > + * EXAR hardware is mostly compatible with SC16IS7XX, but supports additional feature: > + * 4x and 8x divisor, instead of default 16x. It has a special register to program it. > + * Bits 0 to 3 is fractional divisor, it used to set value of last 16 bits of > + * uartclk * (16 / divisor) / baud, in case of default it will be uartclk / baud. > + * Bits 4 and 5 used as switches, and should not be set to 1 simultaneously. > + */ ... > +static bool sc16is7xx_has_dld(struct device *dev) > +{ > + struct sc16is7xx_port *s = dev_get_drvdata(dev); > + > + if (s->devtype == &xr20m1172_devtype) > + return true; > + return false; Besides what Jiri noticed, this has been indented one TAB too much. > +}
On Mon, Apr 22, 2024 at 9:30 AM Jiri Slaby <jirislaby@kernel.org> wrote: > > On 20. 04. 24, 20:22, Konstantin Pugin wrote: > > From: Konstantin Pugin <ria.freelander@gmail.com> > > > > XR20M1172 register set is mostly compatible with SC16IS762, but it has > > a support for additional division rates of UART with special DLD register. > > So, add handling this register by appropriate devicetree bindings. > ... > > --- a/drivers/tty/serial/sc16is7xx.c > > +++ b/drivers/tty/serial/sc16is7xx.c > ... > > @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) > > return reg == SC16IS7XX_RHR_REG; > > } > > > > +static bool sc16is7xx_has_dld(struct device *dev) > > +{ > > + struct sc16is7xx_port *s = dev_get_drvdata(dev); > > + > > + if (s->devtype == &xr20m1172_devtype) > > + return true; > > + return false; > > :) so this should simply be: > > return s->devtype == &xr20m1172_devtype; > I especially want to avoid this construction, because it will lead to idea than we does not have other DLD-capable UARTS, which is simply not true, there is, for example, XR20M1280 UART, which has roughly the same register set (https://www.alldatasheet.com/datasheet-pdf/pdf/445109/EXAR/XR20M1280.html). I simply do not have other devices, so I do not want to risk sending untested patches upstream. > ... > > @@ -1002,6 +1052,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > > const struct ktermios *old) > > { > > struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); > > + bool has_dld = sc16is7xx_has_dld(port->dev); > > unsigned int lcr, flow = 0; > > int baud; > > unsigned long flags; > > @@ -1084,7 +1135,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, > > /* Get baud rate generator configuration */ > > baud = uart_get_baud_rate(port, termios, old, > > port->uartclk / 16 / 4 / 0xffff, > > - port->uartclk / 16); > > + port->uartclk / (has_dld ? 4 : 16)); > > Could you do this instead: > unsigned int divisor = sc16is7xx_has_dld(port->dev) ? 4 : 16; > > ... > > uart_get_baud_rate(..., port->uartclk / divisor); > > > I am not sure the above warrants for a new version. Just in case you are > sending one. > > thanks, > -- > js > suse labs >
On 22. 04. 24, 14:00, Konstantin P. wrote: > On Mon, Apr 22, 2024 at 9:30 AM Jiri Slaby <jirislaby@kernel.org> wrote: >> >> On 20. 04. 24, 20:22, Konstantin Pugin wrote: >>> From: Konstantin Pugin <ria.freelander@gmail.com> >>> >>> XR20M1172 register set is mostly compatible with SC16IS762, but it has >>> a support for additional division rates of UART with special DLD register. >>> So, add handling this register by appropriate devicetree bindings. >> ... >>> --- a/drivers/tty/serial/sc16is7xx.c >>> +++ b/drivers/tty/serial/sc16is7xx.c >> ... >>> @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) >>> return reg == SC16IS7XX_RHR_REG; >>> } >>> >>> +static bool sc16is7xx_has_dld(struct device *dev) >>> +{ >>> + struct sc16is7xx_port *s = dev_get_drvdata(dev); >>> + >>> + if (s->devtype == &xr20m1172_devtype) >>> + return true; >>> + return false; >> >> :) so this should simply be: >> >> return s->devtype == &xr20m1172_devtype; >> > I especially want to avoid this construction, because it will lead to > idea than we does not have other > DLD-capable UARTS, which is simply not true, there is, for example, > XR20M1280 UART, which has roughly the same register set > (https://www.alldatasheet.com/datasheet-pdf/pdf/445109/EXAR/XR20M1280.html). > I simply do not have other devices, so I do not > want to risk sending untested patches upstream. Sorry, what?
On 22/04/2024 22:35, Konstantin P. wrote: > On Mon, Apr 22, 2024, 23:11 Jiri Slaby <jirislaby@kernel.org> wrote: > >> On 22. 04. 24, 14:00, Konstantin P. wrote: >>> On Mon, Apr 22, 2024 at 9:30 AM Jiri Slaby <jirislaby@kernel.org> wrote: >>>> >>>> On 20. 04. 24, 20:22, Konstantin Pugin wrote: >>>>> From: Konstantin Pugin <ria.freelander@gmail.com> >>>>> >>>>> XR20M1172 register set is mostly compatible with SC16IS762, but it has >>>>> a support for additional division rates of UART with special DLD >> register. >>>>> So, add handling this register by appropriate devicetree bindings. >>>> ... >>>>> --- a/drivers/tty/serial/sc16is7xx.c >>>>> +++ b/drivers/tty/serial/sc16is7xx.c >>>> ... >>>>> @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device >> *dev, unsigned int reg) >>>>> return reg == SC16IS7XX_RHR_REG; >>>>> } >>>>> >>>>> +static bool sc16is7xx_has_dld(struct device *dev) >>>>> +{ >>>>> + struct sc16is7xx_port *s = dev_get_drvdata(dev); >>>>> + >>>>> + if (s->devtype == &xr20m1172_devtype) >>>>> + return true; >>>>> + return false; >>>> >>>> :) so this should simply be: >>>> >>>> return s->devtype == &xr20m1172_devtype; >>>> >>> I especially want to avoid this construction, because it will lead to >>> idea than we does not have other >>> DLD-capable UARTS, which is simply not true, there is, for example, >>> XR20M1280 UART, which has roughly the same register set >>> ( >> https://www.alldatasheet.com/datasheet-pdf/pdf/445109/EXAR/XR20M1280.html >> ). >>> I simply do not have other devices, so I do not >>> want to risk sending untested patches upstream. >> >> Sorry, what? >> >> -- >> js >> suse labs >> > > I do not wish those function to be less generic than I did. If you think > this change is required - I will change. But if it would be okay without a > change - I prefer to stay as is. The code does exactly the same, so what do you mean "less generic"? What does it even mean? Best regards, Krzysztof
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4fdd7857ef4d..4380bfe7dfff 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1029,15 +1029,17 @@ config SERIAL_SC16IS7XX_CORE select SERIAL_SC16IS7XX_SPI if SPI_MASTER select SERIAL_SC16IS7XX_I2C if I2C help - Core driver for NXP SC16IS7xx UARTs. + Core driver for NXP SC16IS7xx-compatible UARTs. Supported ICs are: - - SC16IS740 - SC16IS741 - SC16IS750 - SC16IS752 - SC16IS760 - SC16IS762 + NXP: + SC16IS740 + SC16IS741 + SC16IS750 + SC16IS752 + SC16IS760 + SC16IS762 + EXAR: + XR20M1172 The driver supports both I2C and SPI interfaces. diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index dfcc804f558f..0f95d5aef71b 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -10,6 +10,7 @@ #undef DEFAULT_SYMBOL_NAMESPACE #define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> @@ -68,6 +69,7 @@ /* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */ #define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */ #define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */ +#define XR20M117X_DLD_REG (0x02) /* Divisor Fractional Register */ /* Enhanced Register set: Only if (LCR == 0xBF) */ #define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */ @@ -221,6 +223,20 @@ #define SC16IS7XX_TCR_RX_HALT(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TCR_RX_RESUME(words) ((((words) / 4) & 0x0f) << 4) +/* + * Divisor Fractional Register bits (EXAR extension) + * EXAR hardware is mostly compatible with SC16IS7XX, but supports additional feature: + * 4x and 8x divisor, instead of default 16x. It has a special register to program it. + * Bits 0 to 3 is fractional divisor, it used to set value of last 16 bits of + * uartclk * (16 / divisor) / baud, in case of default it will be uartclk / baud. + * Bits 4 and 5 used as switches, and should not be set to 1 simultaneously. + */ + +#define XR20M117X_DLD_16X 0 +#define XR20M117X_DLD_DIV_MASK GENMASK(3, 0) +#define XR20M117X_DLD_8X BIT(4) +#define XR20M117X_DLD_4X BIT(5) + /* * TLR register bits * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the @@ -523,6 +539,13 @@ const struct sc16is7xx_devtype sc16is762_devtype = { }; EXPORT_SYMBOL_GPL(sc16is762_devtype); +const struct sc16is7xx_devtype xr20m1172_devtype = { + .name = "XR20M1172", + .nr_gpio = 8, + .nr_uart = 2, +}; +EXPORT_SYMBOL_GPL(xr20m1172_devtype); + static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) { switch (reg) { @@ -555,18 +578,43 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) return reg == SC16IS7XX_RHR_REG; } +static bool sc16is7xx_has_dld(struct device *dev) +{ + struct sc16is7xx_port *s = dev_get_drvdata(dev); + + if (s->devtype == &xr20m1172_devtype) + return true; + return false; +} + static int sc16is7xx_set_baud(struct uart_port *port, int baud) { struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - u8 lcr; + unsigned long clk = port->uartclk, div, div16; + bool has_dld = sc16is7xx_has_dld(port->dev); + u8 dld_mode = XR20M117X_DLD_16X; u8 prescaler = 0; - unsigned long clk = port->uartclk, div = clk / 16 / baud; + u8 divisor = 16; + u8 lcr; + + if (has_dld && DIV_ROUND_CLOSEST(clk, baud) < 16) + divisor = rounddown_pow_of_two(DIV_ROUND_CLOSEST(clk, baud)); + + div16 = (clk * 16) / divisor / baud; + div = div16 / 16; if (div >= BIT(16)) { prescaler = SC16IS7XX_MCR_CLKSEL_BIT; div /= 4; } + /* Count additional divisor for EXAR devices */ + if (divisor == 8) + dld_mode = XR20M117X_DLD_8X; + if (divisor == 4) + dld_mode = XR20M117X_DLD_4X; + dld_mode |= FIELD_PREP(XR20M117X_DLD_DIV_MASK, div16); + /* Enable enhanced features */ sc16is7xx_efr_lock(port); sc16is7xx_port_update(port, SC16IS7XX_EFR_REG, @@ -587,12 +635,14 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) regcache_cache_bypass(one->regmap, true); sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); + if (has_dld) + sc16is7xx_port_write(port, XR20M117X_DLD_REG, dld_mode); regcache_cache_bypass(one->regmap, false); /* Restore LCR and access to general register set */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); - return DIV_ROUND_CLOSEST(clk / 16, div); + return DIV_ROUND_CLOSEST(clk / divisor, div); } static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, @@ -1002,6 +1052,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, const struct ktermios *old) { struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + bool has_dld = sc16is7xx_has_dld(port->dev); unsigned int lcr, flow = 0; int baud; unsigned long flags; @@ -1084,7 +1135,7 @@ static void sc16is7xx_set_termios(struct uart_port *port, /* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 4 / 0xffff, - port->uartclk / 16); + port->uartclk / (has_dld ? 4 : 16)); /* Setup baudrate generator */ baud = sc16is7xx_set_baud(port, baud); @@ -1684,6 +1735,7 @@ void sc16is7xx_remove(struct device *dev) EXPORT_SYMBOL_GPL(sc16is7xx_remove); const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { + { .compatible = "exar,xr20m1172", .data = &xr20m1172_devtype, }, { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, }, { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, }, diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h index afb784eaee45..eb2e3bc86f15 100644 --- a/drivers/tty/serial/sc16is7xx.h +++ b/drivers/tty/serial/sc16is7xx.h @@ -28,6 +28,7 @@ extern const struct sc16is7xx_devtype sc16is750_devtype; extern const struct sc16is7xx_devtype sc16is752_devtype; extern const struct sc16is7xx_devtype sc16is760_devtype; extern const struct sc16is7xx_devtype sc16is762_devtype; +extern const struct sc16is7xx_devtype xr20m1172_devtype; const char *sc16is7xx_regmap_name(u8 port_id); diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c index 3ed47c306d85..839de902821b 100644 --- a/drivers/tty/serial/sc16is7xx_i2c.c +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -46,6 +46,7 @@ static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { "xr20m1172", (kernel_ulong_t)&xr20m1172_devtype, }, { } }; MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c index 73df36f8a7fd..2b278282dbd0 100644 --- a/drivers/tty/serial/sc16is7xx_spi.c +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -69,6 +69,7 @@ static const struct spi_device_id sc16is7xx_spi_id_table[] = { { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { "xr20m1172", (kernel_ulong_t)&xr20m1172_devtype, }, { } }; MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);