From patchwork Sun Jun 5 14:46:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cosmin Tanislav X-Patchwork-Id: 578933 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F883C43334 for ; Sun, 5 Jun 2022 14:47:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345108AbiFEOrd (ORCPT ); Sun, 5 Jun 2022 10:47:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37920 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345065AbiFEOrc (ORCPT ); Sun, 5 Jun 2022 10:47:32 -0400 Received: from mail-ej1-x62b.google.com (mail-ej1-x62b.google.com [IPv6:2a00:1450:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 516D55FBA; Sun, 5 Jun 2022 07:47:28 -0700 (PDT) Received: by mail-ej1-x62b.google.com with SMTP id q1so24509732ejz.9; Sun, 05 Jun 2022 07:47:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Tcw7h7wb8BE8oW7NJUYk/qOSs6p8a/jo+wYZpgwb+VQ=; b=JX3yxOQEIfFjwrYv+PF7gJ2N8/lPC0p0PIc//iibkF+NSAJho/LtSUJLc2ZcLXVji7 Xie1usLzB7TPbtPROnLXFnPNdxoUoj/10+7xf3hbeqSLH4KO/Mu+GabeNM9xpBavKxGI vy3QmgbrQW/IIc5edGBqMtSbif5+m/rCXZePNKDTecmmKfrF9Pxxi/T7c5INNtTZXUzv rkYFunLKqxoviIWrgZ+NWdv8C0+hBmXO8SlmLgnEB0GFvGe6sSbDR43SQKfJ5PINFMns Z87uUYlt7/pkfRto4GhwHamHrGaJmyHSPP7mIBeriy+NwU4P3CRVo+odp7ZdKvjp2UR2 EXJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Tcw7h7wb8BE8oW7NJUYk/qOSs6p8a/jo+wYZpgwb+VQ=; b=akqdYVIVLRUNdf61Q3cH82SuAfIwytTAKfowJzDVBpJba83R5UG+PqrKKWgvs0a2At XvVx0tBlJY9qHyQer62IHZrozIJsPqPtefqMK9Ma0RPrTztl3L5Xlxw3l6kZB0qQ6y6S uZbr/RcaDRBccmZ2bdKWy/0GP69pglrKSoejtnTHFbPzT4lg3EwyeXA/KplUEy4SbFLJ EcKXxxnAhUz8+Z+XKb9J6ADyNqd4hv/i76Si4iNzudfO4xG3K1VzNpNmW2PrtuMuwpAB CCGnw+KOyPDE5jzthXKvZAYlQHophEqPFbyN/LEEmL16hgz7djYU7u0fPSlA4LU7NwGy UvPQ== X-Gm-Message-State: AOAM5336T2mL2v3kERspnUVyuyNfv6dmF3g7MAgeZSS0jwG4umYhdhis YDdz099qHoSGAkzuuNEBxGLTOG3AgbU= X-Google-Smtp-Source: ABdhPJwT55ZOVcJ3Yk4iuMj9iWxAseLJSUtYksVIiJaNj2thJGh/5xXNaO1l6CJMrFw8/5aZSBm/uw== X-Received: by 2002:a17:907:1b25:b0:6da:8206:fc56 with SMTP id mp37-20020a1709071b2500b006da8206fc56mr17613796ejc.81.1654440446517; Sun, 05 Jun 2022 07:47:26 -0700 (PDT) Received: from demon-pc.localdomain ([188.24.86.218]) by smtp.gmail.com with ESMTPSA id d20-20020aa7ce14000000b0042dd4ccccf5sm6854254edv.82.2022.06.05.07.47.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Jun 2022 07:47:26 -0700 (PDT) From: Cosmin Tanislav Cc: Greg Kroah-Hartman , Jiri Slaby , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Cosmin Tanislav Subject: [PATCH v2 1/4] serial: max310x: use regmap methods for SPI batch operations Date: Sun, 5 Jun 2022 17:46:56 +0300 Message-Id: <20220605144659.4169853-2-demonsingur@gmail.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220605144659.4169853-1-demonsingur@gmail.com> References: <20220605144659.4169853-1-demonsingur@gmail.com> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org From: Cosmin Tanislav The SPI batch read/write operations can be implemented as simple regmap raw read and write, which will also try to do a gather write just as it is done here. Use the regmap raw read and write methods. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/max310x.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index a0b6ea52d133..46887a4ffea4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -259,8 +259,6 @@ struct max310x_one { struct work_struct md_work; struct work_struct rs_work; - u8 wr_header; - u8 rd_header; u8 rx_buf[MAX310X_FIFO_SIZE]; }; #define to_max310x_port(_port) \ @@ -623,32 +621,18 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->wr_header, - .len = sizeof(one->wr_header), - }, { - .tx_buf = txbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_THR_REG; + + regmap_raw_write(s->regmap, reg, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_one *one = to_max310x_port(port); - struct spi_transfer xfer[] = { - { - .tx_buf = &one->rd_header, - .len = sizeof(one->rd_header), - }, { - .rx_buf = rxbuf, - .len = len, - } - }; - spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer)); + struct max310x_port *s = dev_get_drvdata(port->dev); + u8 reg = port->iobase + MAX310X_RHR_REG; + + regmap_raw_read(s->regmap, reg, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1368,10 +1352,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); - /* Initialize SPI-transfer buffers */ - s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) | - MAX310X_WRITE_BIT; - s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG); /* Register port */ ret = uart_add_one_port(&max310x_uart, &s->p[i].port); From patchwork Sun Jun 5 14:46:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cosmin Tanislav X-Patchwork-Id: 578934 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9776DC433EF for ; Sun, 5 Jun 2022 14:47:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345082AbiFEOrc (ORCPT ); Sun, 5 Jun 2022 10:47:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345029AbiFEOrb (ORCPT ); Sun, 5 Jun 2022 10:47:31 -0400 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC7425FD4; Sun, 5 Jun 2022 07:47:29 -0700 (PDT) Received: by mail-ej1-x633.google.com with SMTP id bg6so4675010ejb.0; Sun, 05 Jun 2022 07:47:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cQkm19AYTjfiIGzMxhbkfzj0qsvPIA6SmaCCAOK1I8Q=; b=L9/TEcu2dNHjO+HEM+M28qtl0/N75Yb4avF+SAZPAGo9N+XUYw3rh39m8moLVka3cH b15JvMxLLwkcGRs/AokgzOGGWp2AAr8WO5PBjF4yQpvsNn2R5hRSNKTFljSpIuhwnnQc E74iDt5wwefdN85heJ4twsaR0XohVRbVvxowk0vdLsNjQ7q048BlqDLY8Ifs3jCuAKkT NPwMLtc0losu5CYpkRy5uFokZUvUdKVsuYpdz1kVREJhaQNQbYtiW5MDk/nSk8DTgz5H M+mU3CkAHq9cuC8Ocq2XL/SsZ2sDoX0W1oryaHvCDMytcfenZcSCqH1NYxierYABv3nl hNNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cQkm19AYTjfiIGzMxhbkfzj0qsvPIA6SmaCCAOK1I8Q=; b=y9HvEvjYiIGyt3VINkzcD5hw7T2pNFL86dFGt79pv8xN15llGRIiRClwFZqMeYYFyG /AbG48AADFvUiIX8ndr2tWkgH8Amy9grZKBynYRwdX9sWvjGHob8aCz3Yaf/nqv2UlI9 wYV3NsOigI2eo3T7ryLU1AX2sFbnTkhrKZ03rcf/swV9fEw1bpL8A2iMq/DG53yz0BbY Y5WMtcOlhULm1ZGBGpUc6UNJYHkh5EcOVwOmOSHPmPd52J3FKRm9T0cBwnBRmZ85O5wS KYRCgS5DBRDVmDxaTJr7vW1o9s0NIuP9Lj/4ZzfhJ3kw4Tnyfnw/3N7b7OZBvhXx8KMf wQ9w== X-Gm-Message-State: AOAM531MJGmUd9KVBe1L95o/OdPaKZUZTibNSqh1l1u+5lhGrIsRJjZC 8WfNOCf8MgjoQXptYOL0YoU= X-Google-Smtp-Source: ABdhPJyrR05tS5mz79Ye1b4UeO4tsC+qcG/6rHtDZpcVmzH2tAIStWZuvv2DgUoGmYSmf4xS0WhmjQ== X-Received: by 2002:a17:907:968b:b0:70f:30b7:9324 with SMTP id hd11-20020a170907968b00b0070f30b79324mr10540607ejc.19.1654440448486; Sun, 05 Jun 2022 07:47:28 -0700 (PDT) Received: from demon-pc.localdomain ([188.24.86.218]) by smtp.gmail.com with ESMTPSA id d20-20020aa7ce14000000b0042dd4ccccf5sm6854254edv.82.2022.06.05.07.47.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Jun 2022 07:47:28 -0700 (PDT) From: Cosmin Tanislav Cc: Greg Kroah-Hartman , Jiri Slaby , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Cosmin Tanislav Subject: [PATCH v2 2/4] serial: max310x: use a separate regmap for each port Date: Sun, 5 Jun 2022 17:46:57 +0300 Message-Id: <20220605144659.4169853-3-demonsingur@gmail.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220605144659.4169853-1-demonsingur@gmail.com> References: <20220605144659.4169853-1-demonsingur@gmail.com> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org From: Cosmin Tanislav The driver currently does manual register manipulation in multiple places to talk to a specific UART port. In order to talk to a specific UART port over SPI, the bits U1 and U0 of the register address can be set, as explained in the Command byte configuration section of the datasheet. Make this more elegant by creating regmaps for each UART port and setting the read_flag_mask and write_flag_mask accordingly. All communcations regarding global registers are done on UART port 0, so replace the global regmap entirely with the port 0 regmap. Also, remove the 0x1f masks from reg_writeable(), reg_volatile() and reg_precious() methods, since setting the U1 and U0 bits of the register address happens inside the regmap core now. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/max310x.c | 68 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 46887a4ffea4..6fd133c177a3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -258,6 +258,7 @@ struct max310x_one { struct work_struct tx_work; struct work_struct md_work; struct work_struct rs_work; + struct regmap *regmap; u8 rx_buf[MAX310X_FIFO_SIZE]; }; @@ -287,26 +288,26 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); static u8 max310x_port_read(struct uart_port *port, u8 reg) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); unsigned int val = 0; - regmap_read(s->regmap, port->iobase + reg, &val); + regmap_read(one->regmap, reg, &val); return val; } static void max310x_port_write(struct uart_port *port, u8 reg, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_write(s->regmap, port->iobase + reg, val); + regmap_write(one->regmap, reg, val); } static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { - struct max310x_port *s = dev_get_drvdata(port->dev); + struct max310x_one *one = to_max310x_port(port); - regmap_update_bits(s->regmap, port->iobase + reg, mask, val); + regmap_update_bits(one->regmap, reg, mask, val); } static int max3107_detect(struct device *dev) @@ -445,7 +446,7 @@ static const struct max310x_devtype max14830_devtype = { static bool max310x_reg_writeable(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -462,7 +463,7 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg) static bool max310x_reg_volatile(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_LSR_IRQSTS_REG: @@ -484,7 +485,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg) static bool max310x_reg_precious(struct device *dev, unsigned int reg) { - switch (reg & 0x1f) { + switch (reg) { case MAX310X_RHR_REG: case MAX310X_IRQSTS_REG: case MAX310X_SPCHR_IRQSTS_REG: @@ -621,18 +622,16 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_THR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_write(s->regmap, reg, txbuf, len); + regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len); } static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len) { - struct max310x_port *s = dev_get_drvdata(port->dev); - u8 reg = port->iobase + MAX310X_RHR_REG; + struct max310x_one *one = to_max310x_port(port); - regmap_raw_read(s->regmap, reg, rxbuf, len); + regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len); } static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) @@ -1234,15 +1233,16 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, #endif static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, - struct regmap *regmap, int irq) + struct regmap *regmaps[], int irq) { int i, ret, fmin, fmax, freq; struct max310x_port *s; u32 uartclk = 0; bool xtal; - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + for (i = 0; i < devtype->nr; i++) + if (IS_ERR(regmaps[i])) + return PTR_ERR(regmaps[i]); /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); @@ -1289,7 +1289,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; } - s->regmap = regmap; + s->regmap = regmaps[0]; s->devtype = devtype; dev_set_drvdata(dev, s); @@ -1299,22 +1299,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; for (i = 0; i < devtype->nr; i++) { - unsigned int offs = i << 5; - /* Reset port */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, + regmap_write(regmaps[i], MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); /* Clear port reset */ - regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0); + regmap_write(regmaps[i], MAX310X_MODE2_REG, 0); /* Wait for port startup */ do { - regmap_read(s->regmap, - MAX310X_BRGDIVLSB_REG + offs, &ret); + regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret); } while (ret != 0x01); - regmap_write(s->regmap, MAX310X_MODE1_REG + offs, - devtype->mode1); + regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); @@ -1337,11 +1333,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty s->p[i].port.fifosize = MAX310X_FIFO_SIZE; s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; - s->p[i].port.iobase = i * 0x20; + s->p[i].port.iobase = i; s->p[i].port.membase = (void __iomem *)~0; s->p[i].port.uartclk = uartclk; s->p[i].port.rs485_config = max310x_rs485_config; s->p[i].port.ops = &max310x_ops; + s->p[i].regmap = regmaps[i]; + /* Disable all interrupts */ max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ @@ -1436,6 +1434,7 @@ static struct regmap_config regcfg = { .val_bits = 8, .write_flag_mask = MAX310X_WRITE_BIT, .cache_type = REGCACHE_RBTREE, + .max_register = MAX310X_REG_1F, .writeable_reg = max310x_reg_writeable, .volatile_reg = max310x_reg_volatile, .precious_reg = max310x_reg_precious, @@ -1445,7 +1444,8 @@ static struct regmap_config regcfg = { static int max310x_spi_probe(struct spi_device *spi) { const struct max310x_devtype *devtype; - struct regmap *regmap; + struct regmap *regmaps[4]; + unsigned int i; int ret; /* Setup SPI bus */ @@ -1460,10 +1460,14 @@ static int max310x_spi_probe(struct spi_device *spi) if (!devtype) devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; - regcfg.max_register = devtype->nr * 0x20 - 1; - regmap = devm_regmap_init_spi(spi, ®cfg); + for (i = 0; i < devtype->nr; i++) { + u8 port_mask = i * 0x20; + regcfg.read_flag_mask = port_mask; + regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT; + regmaps[i] = devm_regmap_init_spi(spi, ®cfg); + } - return max310x_probe(&spi->dev, devtype, regmap, spi->irq); + return max310x_probe(&spi->dev, devtype, regmaps, spi->irq); } static void max310x_spi_remove(struct spi_device *spi) From patchwork Sun Jun 5 14:46:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cosmin Tanislav X-Patchwork-Id: 578932 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 36CA4C43334 for ; Sun, 5 Jun 2022 14:47:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345173AbiFEOri (ORCPT ); Sun, 5 Jun 2022 10:47:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345118AbiFEOrf (ORCPT ); Sun, 5 Jun 2022 10:47:35 -0400 Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B13455F52; Sun, 5 Jun 2022 07:47:33 -0700 (PDT) Received: by mail-ej1-x62e.google.com with SMTP id kq6so11488789ejb.11; Sun, 05 Jun 2022 07:47:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=rHOtVO3YML97AxTHN1lPIFLaGm5HbxOfT4Z5jAGZugo=; b=CL3SS+vgAElyH9qpICNCklTVijTGO/HvPibTqan8lPauLdERlD7mENhyDF0OONNI3S JHADrl6x7vVzddG/JGvK/bImNn1RLIEXZLVJ6tcjqCt61MmhiiIXBS+sXfOI+7sH9Bk8 zXP0UEVlhUgLRkPo4KhLBMlGkyXxSXpYpKON5r258w2fGnjLm53E86oOdCfuijZEj3JY 4DeZrPTHdg3L9kEZcXLtqHkyNCYSvTHHKAKFVw4knUP7aUTrSuyAllQd4Qrx6xuerxxz VokicaLttaR2qTH3adz3Qmavj7/8HOcSC/n8ToSadab929mkkYF72CEnujHHYXCi0kZ3 vYYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rHOtVO3YML97AxTHN1lPIFLaGm5HbxOfT4Z5jAGZugo=; b=n7l8+AplJcapiVVMysJpD5VYTUnuqzLJ0fz64TfWOEA+p54vnxwlZl+lz9cPn+36YX b88hU0hvrhheJb+fJFMpAktjjp2JGfvsAAxgUSU6GcOB4Rv6n+lTpSie9s3WLBefTjVm Capj9f4Qz4AxOhA/Y65GLXwgDNFr9ac7FG/mbYlPcBV+rAI05DR0DUHqZgcXC2GL+9Rm 1lknzQ68ZPUsRn+3DjcCPadBAkKMnhlVbS0sYbeTGxL6h77n2/Z/xmLDsg8Y8TV/MKAR Yoso2ZFeVzXSglGLHHJrTwCJs1GTneaILqIX6aqmQYerxu4V4dKZvUtK2c71rKdCWkZe BFMQ== X-Gm-Message-State: AOAM533eK8FMUFDg30FaqM8kmBY0rqabKJ3sKbc3fl8SViQwphpK4rOr 3brgOJun/hvXRkEAiLYmwZt59u6g9As= X-Google-Smtp-Source: ABdhPJzTPstgV6eipESq+ORYcq7GsSrW2igOzOdZWbARfkjFQ08KUkZpIgvMqq9ZkqYdxnnX83935Q== X-Received: by 2002:a17:907:6e11:b0:6fe:feaa:bb04 with SMTP id sd17-20020a1709076e1100b006fefeaabb04mr18216429ejc.187.1654440452198; Sun, 05 Jun 2022 07:47:32 -0700 (PDT) Received: from demon-pc.localdomain ([188.24.86.218]) by smtp.gmail.com with ESMTPSA id d20-20020aa7ce14000000b0042dd4ccccf5sm6854254edv.82.2022.06.05.07.47.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Jun 2022 07:47:31 -0700 (PDT) From: Cosmin Tanislav Cc: Greg Kroah-Hartman , Jiri Slaby , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Cosmin Tanislav Subject: [PATCH v2 4/4] serial: max310x: implement I2C support Date: Sun, 5 Jun 2022 17:46:59 +0300 Message-Id: <20220605144659.4169853-5-demonsingur@gmail.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220605144659.4169853-1-demonsingur@gmail.com> References: <20220605144659.4169853-1-demonsingur@gmail.com> MIME-Version: 1.0 To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org From: Cosmin Tanislav I2C implementation on this chip has a few key differences compared to SPI, as described in previous patches. * extended register space access needs no extra logic * slave address is used to select which UART to communicate with To accommodate these differences, add an I2C interface config, set the RevID register address and implement an empty method for setting the GlobalCommand register, since no special handling is needed for the extended register space. To handle the port-specific slave address, create an I2C dummy device for each port, except the base one (UART0), which is expected to be the one specified in firmware, and create a regmap for each I2C device. Add minimum and maximum slave addresses to each devtype for sanity checking. Also, use a separate regmap config with no write_flag_mask, since I2C has a R/W bit in its slave address, and set the max register to the address of the RevID register, since the extended register space needs no extra logic. Finally, add the I2C driver. Signed-off-by: Cosmin Tanislav --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/max310x.c | 135 ++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a452748c69b2..8a3ee1525d80 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -324,6 +324,7 @@ config SERIAL_MAX310X depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER + select REGMAP_I2C if I2C help This selects support for an advanced UART from Maxim (Dallas). Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830. diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ef6b91242524..0f7c5908fee0 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ /* Extended registers */ #define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */ +#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */ /* IRQ register bits */ #define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ @@ -252,6 +254,10 @@ struct max310x_if_cfg { }; struct max310x_devtype { + struct { + unsigned short min; + unsigned short max; + } slave_addr; char name[9]; int nr; u8 mode1; @@ -423,6 +429,10 @@ static const struct max310x_devtype max3107_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .detect = max3107_detect, .power = max310x_power, + .slave_addr = { + .min = 0x2c, + .max = 0x2f, + }, }; static const struct max310x_devtype max3108_devtype = { @@ -431,6 +441,10 @@ static const struct max310x_devtype max3108_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3108_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max3109_devtype = { @@ -439,6 +453,10 @@ static const struct max310x_devtype max3109_devtype = { .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3109_detect, .power = max310x_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static const struct max310x_devtype max14830_devtype = { @@ -447,6 +465,10 @@ static const struct max310x_devtype max14830_devtype = { .mode1 = MAX310X_MODE1_IRQSEL_BIT, .detect = max14830_detect, .power = max14830_power, + .slave_addr = { + .min = 0x60, + .max = 0x6f, + }, }; static bool max310x_reg_writeable(struct device *dev, unsigned int reg) @@ -1516,6 +1538,97 @@ static struct spi_driver max310x_spi_driver = { }; #endif +#ifdef CONFIG_I2C +static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) +{ + return 0; +} + +static struct regmap_config regcfg_i2c = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, + .max_register = MAX310X_I2C_REVID_EXTREG, +}; + +static const struct max310x_if_cfg max310x_i2c_if_cfg = { + .extended_reg_enable = max310x_i2c_extended_reg_enable, + .rev_id_reg = MAX310X_I2C_REVID_EXTREG, +}; + +static unsigned short max310x_i2c_slave_addr(unsigned short addr, + unsigned int nr) +{ + /* + * For MAX14830 and MAX3109, the slave address depends on what the + * A0 and A1 pins are tied to. + * See Table I2C Address Map of the datasheet. + * Based on that table, the following formulas were determined. + * UART1 - UART0 = 0x10 + * UART2 - UART1 = 0x20 + 0x10 + * UART3 - UART2 = 0x10 + */ + + addr -= nr * 0x10; + + if (nr >= 2) + addr -= 0x20; + + return addr; +} + +static int max310x_i2c_probe(struct i2c_client *client) +{ + const struct max310x_devtype *devtype = + device_get_match_data(&client->dev); + struct i2c_client *port_client; + struct regmap *regmaps[4]; + unsigned int i; + u8 port_addr; + + if (client->addr < devtype->slave_addr.min || + client->addr > devtype->slave_addr.max) + return dev_err_probe(&client->dev, -EINVAL, + "Slave addr 0x%x outside of range [0x%x, 0x%x]\n", + client->addr, devtype->slave_addr.min, + devtype->slave_addr.max); + + regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c); + + for (i = 1; i < devtype->nr; i++) { + port_addr = max310x_i2c_slave_addr(client->addr, i); + port_client = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + port_addr); + + regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c); + } + + return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg, + regmaps, client->irq); +} + +static int max310x_i2c_remove(struct i2c_client *client) +{ + max310x_remove(&client->dev); + + return 0; +} + +static struct i2c_driver max310x_i2c_driver = { + .driver = { + .name = MAX310X_NAME, + .of_match_table = max310x_dt_ids, + .pm = &max310x_pm_ops, + }, + .probe_new = max310x_i2c_probe, + .remove = max310x_i2c_remove, +}; +#endif + static int __init max310x_uart_init(void) { int ret; @@ -1529,15 +1642,35 @@ static int __init max310x_uart_init(void) #ifdef CONFIG_SPI_MASTER ret = spi_register_driver(&max310x_spi_driver); if (ret) - uart_unregister_driver(&max310x_uart); + goto err_spi_register; +#endif + +#ifdef CONFIG_I2C + ret = i2c_add_driver(&max310x_i2c_driver); + if (ret) + goto err_i2c_register; #endif + return 0; + +#ifdef CONFIG_I2C +err_i2c_register: + spi_unregister_driver(&max310x_spi_driver); +#endif + +err_spi_register: + uart_unregister_driver(&max310x_uart); + return ret; } module_init(max310x_uart_init); static void __exit max310x_uart_exit(void) { +#ifdef CONFIG_I2C + i2c_del_driver(&max310x_i2c_driver); +#endif + #ifdef CONFIG_SPI_MASTER spi_unregister_driver(&max310x_spi_driver); #endif