From aa102ffd7b081fc522bc2b966c90a45f0bc3754d Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:31 +0100 Subject: [PATCH 01/19] can: tcan4x5x: replace DEVICE_NAME by KBUILD_MODNAME This patch replaces the DEVICE_NAME macro by KBUILD_MODNAME and removed the superfluous DEVICE_NAME. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-2-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x.c b/drivers/net/can/m_can/tcan4x5x.c index 24c737c4fc446..1b5f706674af4 100644 --- a/drivers/net/can/m_can/tcan4x5x.c +++ b/drivers/net/can/m_can/tcan4x5x.c @@ -10,7 +10,6 @@ #include "m_can.h" -#define DEVICE_NAME "tcan4x5x" #define TCAN4X5X_EXT_CLK_DEF 40000000 #define TCAN4X5X_DEV_ID0 0x00 @@ -132,7 +131,7 @@ static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev) } static struct can_bittiming_const tcan4x5x_bittiming_const = { - .name = DEVICE_NAME, + .name = KBUILD_MODNAME, .tseg1_min = 2, .tseg1_max = 31, .tseg2_min = 2, @@ -144,7 +143,7 @@ static struct can_bittiming_const tcan4x5x_bittiming_const = { }; static struct can_bittiming_const tcan4x5x_data_bittiming_const = { - .name = DEVICE_NAME, + .name = KBUILD_MODNAME, .tseg1_min = 1, .tseg1_max = 32, .tseg2_min = 1, @@ -544,7 +543,7 @@ MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table); static struct spi_driver tcan4x5x_can_driver = { .driver = { - .name = DEVICE_NAME, + .name = KBUILD_MODNAME, .of_match_table = tcan4x5x_of_match, .pm = NULL, }, From bcc3d8ef14c044df225d9e2292ed3f1d5176c77d Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:32 +0100 Subject: [PATCH 02/19] can: tcan4x5x: beautify indention of tcan4x5x_of_match and tcan4x5x_id_table This patch beautifies the indention of the tcan4x5x_of_match and tcan4x5x_id_table. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-3-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x.c b/drivers/net/can/m_can/tcan4x5x.c index 1b5f706674af4..1b47c9d32c308 100644 --- a/drivers/net/can/m_can/tcan4x5x.c +++ b/drivers/net/can/m_can/tcan4x5x.c @@ -527,17 +527,20 @@ static int tcan4x5x_can_remove(struct spi_device *spi) } static const struct of_device_id tcan4x5x_of_match[] = { - { .compatible = "ti,tcan4x5x", }, - { } + { + .compatible = "ti,tcan4x5x", + }, { + /* sentinel */ + }, }; MODULE_DEVICE_TABLE(of, tcan4x5x_of_match); static const struct spi_device_id tcan4x5x_id_table[] = { { - .name = "tcan4x5x", - .driver_data = 0, + .name = "tcan4x5x", + }, { + /* sentinel */ }, - { } }; MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table); From 7813887ea972f69740022aaf1b45d62388813a49 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:33 +0100 Subject: [PATCH 03/19] can: tcan4x5x: rename tcan4x5x.c -> tcan4x5x-core.c This is a preparation patch to move the regmap related code into a seperate file. This patch removes the tcan4x5x.c to tcan4x5x-core.c. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-4-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/Makefile | 3 +++ drivers/net/can/m_can/{tcan4x5x.c => tcan4x5x-core.c} | 0 2 files changed, 3 insertions(+) rename drivers/net/can/m_can/{tcan4x5x.c => tcan4x5x-core.c} (100%) diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile index ef7963ff2006f..91f9190dc007a 100644 --- a/drivers/net/can/m_can/Makefile +++ b/drivers/net/can/m_can/Makefile @@ -7,3 +7,6 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PCI) += m_can_pci.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.o + +tcan4x5x-objs := +tcan4x5x-objs += tcan4x5x-core.o diff --git a/drivers/net/can/m_can/tcan4x5x.c b/drivers/net/can/m_can/tcan4x5x-core.c similarity index 100% rename from drivers/net/can/m_can/tcan4x5x.c rename to drivers/net/can/m_can/tcan4x5x-core.c From 67def4ef8bb9b03795def42448b8a6fdfe4e90cc Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:34 +0100 Subject: [PATCH 04/19] can: tcan4x5x: move regmap code into seperate file This patch moves the regmap code into a seperate file. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-5-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x-core.c | 104 +----------------------- drivers/net/can/m_can/tcan4x5x-regmap.c | 95 ++++++++++++++++++++++ drivers/net/can/m_can/tcan4x5x.h | 34 ++++++++ 4 files changed, 133 insertions(+), 101 deletions(-) create mode 100644 drivers/net/can/m_can/tcan4x5x-regmap.c create mode 100644 drivers/net/can/m_can/tcan4x5x.h diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile index 91f9190dc007a..d717bbc9e0334 100644 --- a/drivers/net/can/m_can/Makefile +++ b/drivers/net/can/m_can/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.o tcan4x5x-objs := tcan4x5x-objs += tcan4x5x-core.o +tcan4x5x-objs += tcan4x5x-regmap.o diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index 1b47c9d32c308..739b8f89a335b 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -2,13 +2,7 @@ // SPI to CAN driver for the Texas Instruments TCAN4x5x // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ -#include -#include - -#include -#include - -#include "m_can.h" +#include "tcan4x5x.h" #define TCAN4X5X_EXT_CLK_DEF 40000000 @@ -87,14 +81,10 @@ #define TCAN4X5X_MRAM_START 0x8000 #define TCAN4X5X_MCAN_OFFSET 0x1000 -#define TCAN4X5X_MAX_REGISTER 0x8fff #define TCAN4X5X_CLEAR_ALL_INT 0xffffffff #define TCAN4X5X_SET_ALL_INT 0xffffffff -#define TCAN4X5X_WRITE_CMD (0x61 << 24) -#define TCAN4X5X_READ_CMD (0x41 << 24) - #define TCAN4X5X_MODE_SEL_MASK (BIT(7) | BIT(6)) #define TCAN4X5X_MODE_SLEEP 0x00 #define TCAN4X5X_MODE_STANDBY BIT(6) @@ -112,18 +102,6 @@ #define TCAN4X5X_WD_3_S_TIMER BIT(29) #define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29)) -struct tcan4x5x_priv { - struct m_can_classdev cdev; - - struct regmap *regmap; - struct spi_device *spi; - - struct gpio_desc *reset_gpio; - struct gpio_desc *device_wake_gpio; - struct gpio_desc *device_state_gpio; - struct regulator *power; -}; - static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev) { return container_of(cdev, struct tcan4x5x_priv, cdev); @@ -190,72 +168,6 @@ static int tcan4x5x_reset(struct tcan4x5x_priv *priv) return ret; } -static int regmap_spi_gather_write(void *context, const void *reg, - size_t reg_len, const void *val, - size_t val_len) -{ - struct device *dev = context; - struct spi_device *spi = to_spi_device(dev); - struct spi_message m; - u32 addr; - struct spi_transfer t[2] = { - { .tx_buf = &addr, .len = reg_len, .cs_change = 0,}, - { .tx_buf = val, .len = val_len, }, - }; - - addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2; - - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - return spi_sync(spi, &m); -} - -static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) -{ - u16 *reg = (u16 *)(data); - const u32 *val = data + 4; - - return regmap_spi_gather_write(context, reg, 4, val, count - 4); -} - -static int regmap_spi_async_write(void *context, - const void *reg, size_t reg_len, - const void *val, size_t val_len, - struct regmap_async *a) -{ - return -ENOTSUPP; -} - -static struct regmap_async *regmap_spi_async_alloc(void) -{ - return NULL; -} - -static int tcan4x5x_regmap_read(void *context, - const void *reg, size_t reg_size, - void *val, size_t val_size) -{ - struct device *dev = context; - struct spi_device *spi = to_spi_device(dev); - - u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2; - - return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size); -} - -static struct regmap_bus tcan4x5x_bus = { - .write = tcan4x5x_regmap_write, - .gather_write = regmap_spi_gather_write, - .async_write = regmap_spi_async_write, - .async_alloc = regmap_spi_async_alloc, - .read = tcan4x5x_regmap_read, - .read_flag_mask = 0x00, - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, -}; - static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg) { struct tcan4x5x_priv *priv = cdev_to_priv(cdev); @@ -410,13 +322,6 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev) return 0; } -static const struct regmap_config tcan4x5x_regmap = { - .reg_bits = 32, - .val_bits = 32, - .cache_type = REGCACHE_NONE, - .max_register = TCAN4X5X_MAX_REGISTER, -}; - static struct m_can_ops tcan4x5x_ops = { .init = tcan4x5x_init, .read_reg = tcan4x5x_read_reg, @@ -480,12 +385,9 @@ static int tcan4x5x_can_probe(struct spi_device *spi) if (ret) goto out_m_can_class_free_dev; - priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus, - &spi->dev, &tcan4x5x_regmap); - if (IS_ERR(priv->regmap)) { - ret = PTR_ERR(priv->regmap); + ret = tcan4x5x_regmap_init(priv); + if (ret) goto out_m_can_class_free_dev; - } ret = tcan4x5x_power_enable(priv->power, 1); if (ret) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c new file mode 100644 index 0000000000000..f130c35865438 --- /dev/null +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver +// +// Copyright (c) 2020 Pengutronix, +// Marc Kleine-Budde +// Copyright (c) 2018-2019 Texas Instruments Incorporated +// http://www.ti.com/ + +#include "tcan4x5x.h" + +#define TCAN4X5X_WRITE_CMD (0x61 << 24) +#define TCAN4X5X_READ_CMD (0x41 << 24) + +#define TCAN4X5X_MAX_REGISTER 0x8fff + +static int regmap_spi_gather_write(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + struct spi_message m; + u32 addr; + struct spi_transfer t[2] = { + { .tx_buf = &addr, .len = reg_len, .cs_change = 0,}, + { .tx_buf = val, .len = val_len, }, + }; + + addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + return spi_sync(spi, &m); +} + +static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) +{ + u16 *reg = (u16 *)(data); + const u32 *val = data + 4; + + return regmap_spi_gather_write(context, reg, 4, val, count - 4); +} + +static int regmap_spi_async_write(void *context, + const void *reg, size_t reg_len, + const void *val, size_t val_len, + struct regmap_async *a) +{ + return -ENOTSUPP; +} + +static struct regmap_async *regmap_spi_async_alloc(void) +{ + return NULL; +} + +static int tcan4x5x_regmap_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + + u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2; + + return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size); +} + +static const struct regmap_config tcan4x5x_regmap = { + .reg_bits = 32, + .val_bits = 32, + .cache_type = REGCACHE_NONE, + .max_register = TCAN4X5X_MAX_REGISTER, +}; + +static struct regmap_bus tcan4x5x_bus = { + .write = tcan4x5x_regmap_write, + .gather_write = regmap_spi_gather_write, + .async_write = regmap_spi_async_write, + .async_alloc = regmap_spi_async_alloc, + .read = tcan4x5x_regmap_read, + .read_flag_mask = 0x00, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv) +{ + priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus, + &priv->spi->dev, &tcan4x5x_regmap); + return PTR_ERR_OR_ZERO(priv->regmap); +} diff --git a/drivers/net/can/m_can/tcan4x5x.h b/drivers/net/can/m_can/tcan4x5x.h new file mode 100644 index 0000000000000..e5bdd91b80054 --- /dev/null +++ b/drivers/net/can/m_can/tcan4x5x.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver + * + * Copyright (c) 2020 Pengutronix, + * Marc Kleine-Budde + */ + +#ifndef _TCAN4X5X_H +#define _TCAN4X5X_H + +#include +#include +#include +#include +#include + +#include "m_can.h" + +struct tcan4x5x_priv { + struct m_can_classdev cdev; + + struct regmap *regmap; + struct spi_device *spi; + + struct gpio_desc *reset_gpio; + struct gpio_desc *device_wake_gpio; + struct gpio_desc *device_state_gpio; + struct regulator *power; +}; + +int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv); + +#endif From 1784aa1449b45edad93ee7d9a50b442bc0ba4a59 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:35 +0100 Subject: [PATCH 05/19] can: tcan4x5x: mark struct regmap_bus tcan4x5x_bus as constant This patch marks the struct regmap_bus tcan4x5x_bus as constant. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-6-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index f130c35865438..1d139554fc16f 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -76,7 +76,7 @@ static const struct regmap_config tcan4x5x_regmap = { .max_register = TCAN4X5X_MAX_REGISTER, }; -static struct regmap_bus tcan4x5x_bus = { +static const struct regmap_bus tcan4x5x_bus = { .write = tcan4x5x_regmap_write, .gather_write = regmap_spi_gather_write, .async_write = regmap_spi_async_write, From 5bcd6e10ad4355f8a78b9b4ee94568807b8232e6 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:36 +0100 Subject: [PATCH 06/19] can: tcan4x5x: tcan4x5x_bus: remove not needed read_flag_mask With C99 initializers, all non mentioned members are initialzied to 0, so remove not needed initialization of read_flag_mask. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-7-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 1d139554fc16f..20bf9a57c9b1b 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -82,7 +82,6 @@ static const struct regmap_bus tcan4x5x_bus = { .async_write = regmap_spi_async_write, .async_alloc = regmap_spi_async_alloc, .read = tcan4x5x_regmap_read, - .read_flag_mask = 0x00, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE, }; From b9c30ef344940610e396d2063a1f50fbb79bb62d Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:37 +0100 Subject: [PATCH 07/19] can: tcan4x5x: remove regmap async support The driver doesn't use regmap async support, so remove the stubs. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-8-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 20bf9a57c9b1b..8905fc36b00a5 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -44,19 +44,6 @@ static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) return regmap_spi_gather_write(context, reg, 4, val, count - 4); } -static int regmap_spi_async_write(void *context, - const void *reg, size_t reg_len, - const void *val, size_t val_len, - struct regmap_async *a) -{ - return -ENOTSUPP; -} - -static struct regmap_async *regmap_spi_async_alloc(void) -{ - return NULL; -} - static int tcan4x5x_regmap_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size) @@ -79,8 +66,6 @@ static const struct regmap_config tcan4x5x_regmap = { static const struct regmap_bus tcan4x5x_bus = { .write = tcan4x5x_regmap_write, .gather_write = regmap_spi_gather_write, - .async_write = regmap_spi_async_write, - .async_alloc = regmap_spi_async_alloc, .read = tcan4x5x_regmap_read, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE, From 52be977b3ade57570ff1110a10755866ded8a1a6 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:38 +0100 Subject: [PATCH 08/19] can: tcan4x5x: rename regmap_spi_gather_write() -> tcan4x5x_regmap_gather_write() This patch renames the regmap_spi_gather_write() function to tcan4x5x_regmap_gather_write(). Now it has a "tcan4x5x_" prefix as all other functions in this driver. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-9-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 8905fc36b00a5..8f718f4395c37 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -14,9 +14,9 @@ #define TCAN4X5X_MAX_REGISTER 0x8fff -static int regmap_spi_gather_write(void *context, const void *reg, - size_t reg_len, const void *val, - size_t val_len) +static int tcan4x5x_regmap_gather_write(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) { struct device *dev = context; struct spi_device *spi = to_spi_device(dev); @@ -41,7 +41,7 @@ static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) u16 *reg = (u16 *)(data); const u32 *val = data + 4; - return regmap_spi_gather_write(context, reg, 4, val, count - 4); + return tcan4x5x_regmap_gather_write(context, reg, 4, val, count - 4); } static int tcan4x5x_regmap_read(void *context, @@ -65,7 +65,7 @@ static const struct regmap_config tcan4x5x_regmap = { static const struct regmap_bus tcan4x5x_bus = { .write = tcan4x5x_regmap_write, - .gather_write = regmap_spi_gather_write, + .gather_write = tcan4x5x_regmap_gather_write, .read = tcan4x5x_regmap_read, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE, From 0c05345210fc265d24f7b800516d2a4eac0c56c1 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:39 +0100 Subject: [PATCH 09/19] can: tcan4x5x: tcan4x5x_regmap_write(): remove not needed casts and replace 4 by sizeof This patch simplifies the tcan4x5x_regmap_write(0 function by removing not needed casts and replaces hardcoded "4" by appropriate sizeof()s. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-10-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 8f718f4395c37..6345bcb7704f6 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -38,10 +38,9 @@ static int tcan4x5x_regmap_gather_write(void *context, const void *reg, static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) { - u16 *reg = (u16 *)(data); - const u32 *val = data + 4; - - return tcan4x5x_regmap_gather_write(context, reg, 4, val, count - 4); + return tcan4x5x_regmap_gather_write(context, data, sizeof(u32), + data + sizeof(u32), + count - sizeof(u32)); } static int tcan4x5x_regmap_read(void *context, From bf722fdd3bc4d0285a131248b8254b30f1f8474a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:40 +0100 Subject: [PATCH 10/19] can: tcan4x5x: tcan4x5x_regmap_init(): use spi as context pointer This patch replaces the context pointer of the regmap callback functions by a pointer to the spi_device. This saves one level of indirection in the callbacks. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-11-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 6345bcb7704f6..4d43c145fdeca 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -18,8 +18,7 @@ static int tcan4x5x_regmap_gather_write(void *context, const void *reg, size_t reg_len, const void *val, size_t val_len) { - struct device *dev = context; - struct spi_device *spi = to_spi_device(dev); + struct spi_device *spi = context; struct spi_message m; u32 addr; struct spi_transfer t[2] = { @@ -47,8 +46,7 @@ static int tcan4x5x_regmap_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size) { - struct device *dev = context; - struct spi_device *spi = to_spi_device(dev); + struct spi_device *spi = context; u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2; @@ -73,6 +71,6 @@ static const struct regmap_bus tcan4x5x_bus = { int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv) { priv->regmap = devm_regmap_init(&priv->spi->dev, &tcan4x5x_bus, - &priv->spi->dev, &tcan4x5x_regmap); + priv->spi, &tcan4x5x_regmap); return PTR_ERR_OR_ZERO(priv->regmap); } From 6e1caaf8ed22eb700cc47ec353816eee33186c1c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:41 +0100 Subject: [PATCH 11/19] can: tcan4x5x: fix max register value This patch fixes the max register value for the regmap. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-12-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 4d43c145fdeca..73be4b6613055 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -12,7 +12,7 @@ #define TCAN4X5X_WRITE_CMD (0x61 << 24) #define TCAN4X5X_READ_CMD (0x41 << 24) -#define TCAN4X5X_MAX_REGISTER 0x8fff +#define TCAN4X5X_MAX_REGISTER 0x8ffc static int tcan4x5x_regmap_gather_write(void *context, const void *reg, size_t reg_len, const void *val, From aaf120c37cffc59b06a3da489bd0d678b365cd5a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:42 +0100 Subject: [PATCH 12/19] can: tcan4x5x: tcan4x5x_regmap: set reg_stride to 4 This patch sets the regmap stide to 4, as the chip only supports access on 32 bit alligned access. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-13-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 73be4b6613055..c6963437064cf 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -55,6 +55,7 @@ static int tcan4x5x_regmap_read(void *context, static const struct regmap_config tcan4x5x_regmap = { .reg_bits = 32, + .reg_stride = 4, .val_bits = 32, .cache_type = REGCACHE_NONE, .max_register = TCAN4X5X_MAX_REGISTER, From 5584114b35f89d43db4fdaa36d7f2650fc0e1bca Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:43 +0100 Subject: [PATCH 13/19] can: tcan4x5x: add max_raw_{read,write} of 256 The tcan4x5x chip support bulk read/write, but as the length field is only 8 bits wide, the maximum is 256. A length of 0 is treated as 256. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-14-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index c6963437064cf..f113881fb0126 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -67,6 +67,8 @@ static const struct regmap_bus tcan4x5x_bus = { .read = tcan4x5x_regmap_read, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE, + .max_raw_read = 256, + .max_raw_write = 256, }; int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv) From 1e81d5258d741ef6b0e6d865ee386dfc5fd95060 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:44 +0100 Subject: [PATCH 14/19] can: tcan4x5x: add {wr,rd}_table The memory space of the chip is not fully populated, so add a regmap range table to document this. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-15-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index f113881fb0126..5ea1625786194 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -53,10 +53,24 @@ static int tcan4x5x_regmap_read(void *context, return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size); } +static const struct regmap_range tcan4x5x_reg_table_yes_range[] = { + regmap_reg_range(0x0000, 0x002c), /* Device ID and SPI Registers */ + regmap_reg_range(0x0800, 0x083c), /* Device configuration registers and Interrupt Flags*/ + regmap_reg_range(0x1000, 0x10fc), /* M_CAN */ + regmap_reg_range(0x8000, 0x87fc), /* MRAM */ +}; + +static const struct regmap_access_table tcan4x5x_reg_table = { + .yes_ranges = tcan4x5x_reg_table_yes_range, + .n_yes_ranges = ARRAY_SIZE(tcan4x5x_reg_table_yes_range), +}; + static const struct regmap_config tcan4x5x_regmap = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, + .wr_table = &tcan4x5x_reg_table, + .rd_table = &tcan4x5x_reg_table, .cache_type = REGCACHE_NONE, .max_register = TCAN4X5X_MAX_REGISTER, }; From 1c5d0fc48b3aef66128b10bcf40ff782f32b3909 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:45 +0100 Subject: [PATCH 15/19] can: tcan4x5x: rework SPI access This patch reworks the SPI access and fixes several probems: - tcan4x5x_regmap_gather_write(), tcan4x5x_regmap_read(): Do not place variable "addr" on stack and use it as buffer for SPI transfer. Buffers for SPI transfers must be allocated from DMA save memory. - tcan4x5x_regmap_gather_write(), tcan4x5x_regmap_read(): Halfe number of SPI transfers by using a single buffer + memcpy(). This improves the performance, especially on SPI controllers, which use interrupt based transfers. - Use "8" bits per word, not "32". This makes it possible to use this driver on SoCs like the Raspberry Pi, which SPI host controller drivers only support 8 bits per word. Note: this breaks half duplex only controllers. Support for them will be re-added in the next patch. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-16-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-core.c | 2 +- drivers/net/can/m_can/tcan4x5x-regmap.c | 87 +++++++++++++++++-------- drivers/net/can/m_can/tcan4x5x.h | 23 +++++++ 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_can/tcan4x5x-core.c index 739b8f89a335b..d37843a74663c 100644 --- a/drivers/net/can/m_can/tcan4x5x-core.c +++ b/drivers/net/can/m_can/tcan4x5x-core.c @@ -380,7 +380,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); /* Configure the SPI bus */ - spi->bits_per_word = 32; + spi->bits_per_word = 8; ret = spi_setup(spi); if (ret) goto out_m_can_class_free_dev; diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 5ea1625786194..660e9d87dffb2 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -9,48 +9,76 @@ #include "tcan4x5x.h" -#define TCAN4X5X_WRITE_CMD (0x61 << 24) -#define TCAN4X5X_READ_CMD (0x41 << 24) +#define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24) +#define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24) #define TCAN4X5X_MAX_REGISTER 0x8ffc -static int tcan4x5x_regmap_gather_write(void *context, const void *reg, - size_t reg_len, const void *val, - size_t val_len) +static int tcan4x5x_regmap_gather_write(void *context, + const void *reg, size_t reg_len, + const void *val, size_t val_len) { struct spi_device *spi = context; - struct spi_message m; - u32 addr; - struct spi_transfer t[2] = { - { .tx_buf = &addr, .len = reg_len, .cs_change = 0,}, - { .tx_buf = val, .len = val_len, }, + struct tcan4x5x_priv *priv = spi_get_drvdata(spi); + struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx; + struct spi_transfer xfer[] = { + { + .tx_buf = buf_tx, + .len = sizeof(buf_tx->cmd) + val_len, + }, }; - addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2; + memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd.cmd) + + sizeof(buf_tx->cmd.addr)); + tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len); + memcpy(buf_tx->data, val, val_len); - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - return spi_sync(spi, &m); + return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer)); } static int tcan4x5x_regmap_write(void *context, const void *data, size_t count) { - return tcan4x5x_regmap_gather_write(context, data, sizeof(u32), - data + sizeof(u32), - count - sizeof(u32)); + return tcan4x5x_regmap_gather_write(context, data, sizeof(__be32), + data + sizeof(__be32), + count - sizeof(__be32)); } static int tcan4x5x_regmap_read(void *context, - const void *reg, size_t reg_size, - void *val, size_t val_size) + const void *reg_buf, size_t reg_len, + void *val_buf, size_t val_len) { struct spi_device *spi = context; + struct tcan4x5x_priv *priv = spi_get_drvdata(spi); + struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx; + struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx; + struct spi_transfer xfer[] = { + { + .tx_buf = buf_tx, + } + }; + struct spi_message msg; + int err; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + + memcpy(&buf_tx->cmd, reg_buf, sizeof(buf_tx->cmd.cmd) + + sizeof(buf_tx->cmd.addr)); + tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len); + + xfer[0].rx_buf = buf_rx; + xfer[0].len = sizeof(buf_tx->cmd) + val_len; - u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2; + if (TCAN4X5X_SANITIZE_SPI) + memset(buf_tx->data, 0x0, val_len); - return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size); + err = spi_sync(spi, &msg); + if (err) + return err; + + memcpy(val_buf, buf_rx->data, val_len); + + return 0; } static const struct regmap_range tcan4x5x_reg_table_yes_range[] = { @@ -66,21 +94,26 @@ static const struct regmap_access_table tcan4x5x_reg_table = { }; static const struct regmap_config tcan4x5x_regmap = { - .reg_bits = 32, + .reg_bits = 24, .reg_stride = 4, + .pad_bits = 8, .val_bits = 32, .wr_table = &tcan4x5x_reg_table, .rd_table = &tcan4x5x_reg_table, - .cache_type = REGCACHE_NONE, .max_register = TCAN4X5X_MAX_REGISTER, + .cache_type = REGCACHE_NONE, + .read_flag_mask = (__force unsigned long) + cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_READ), + .write_flag_mask = (__force unsigned long) + cpu_to_be32(TCAN4X5X_SPI_INSTRUCTION_WRITE), }; static const struct regmap_bus tcan4x5x_bus = { .write = tcan4x5x_regmap_write, .gather_write = tcan4x5x_regmap_gather_write, .read = tcan4x5x_regmap_read, - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, .max_raw_read = 256, .max_raw_write = 256, }; diff --git a/drivers/net/can/m_can/tcan4x5x.h b/drivers/net/can/m_can/tcan4x5x.h index e5bdd91b80054..7bf264f8e81f4 100644 --- a/drivers/net/can/m_can/tcan4x5x.h +++ b/drivers/net/can/m_can/tcan4x5x.h @@ -17,6 +17,19 @@ #include "m_can.h" +#define TCAN4X5X_SANITIZE_SPI 1 + +struct __packed tcan4x5x_buf_cmd { + u8 cmd; + __be16 addr; + u8 len; +}; + +struct __packed tcan4x5x_map_buf { + struct tcan4x5x_buf_cmd cmd; + u8 data[256 * sizeof(u32)]; +} ____cacheline_aligned; + struct tcan4x5x_priv { struct m_can_classdev cdev; @@ -27,8 +40,18 @@ struct tcan4x5x_priv { struct gpio_desc *device_wake_gpio; struct gpio_desc *device_state_gpio; struct regulator *power; + + struct tcan4x5x_map_buf map_buf_rx; + struct tcan4x5x_map_buf map_buf_tx; }; +static inline void +tcan4x5x_spi_cmd_set_len(struct tcan4x5x_buf_cmd *cmd, u8 len) +{ + /* number of u32 */ + cmd->len = len >> 2; +} + int tcan4x5x_regmap_init(struct tcan4x5x_priv *priv); #endif From 0460ecaeba90f418f29f9ea57d994429c8f88a4e Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 16 Dec 2020 00:17:46 +0100 Subject: [PATCH 16/19] can: tcan4x5x: add support for half-duplex controllers This patch adds back support for half-duplex controllers, which was removed in the last patch. Reviewed-by: Dan Murphy Tested-by: Sean Nyekjaer Link: https://lore.kernel.org/r/20201215231746.1132907-17-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/tcan4x5x-regmap.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/m_can/tcan4x5x-regmap.c b/drivers/net/can/m_can/tcan4x5x-regmap.c index 660e9d87dffb2..ca80dbaf7a3f5 100644 --- a/drivers/net/can/m_can/tcan4x5x-regmap.c +++ b/drivers/net/can/m_can/tcan4x5x-regmap.c @@ -51,7 +51,7 @@ static int tcan4x5x_regmap_read(void *context, struct tcan4x5x_priv *priv = spi_get_drvdata(spi); struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx; struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx; - struct spi_transfer xfer[] = { + struct spi_transfer xfer[2] = { { .tx_buf = buf_tx, } @@ -66,17 +66,26 @@ static int tcan4x5x_regmap_read(void *context, sizeof(buf_tx->cmd.addr)); tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len); - xfer[0].rx_buf = buf_rx; - xfer[0].len = sizeof(buf_tx->cmd) + val_len; + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { + xfer[0].len = sizeof(buf_tx->cmd); + + xfer[1].rx_buf = val_buf; + xfer[1].len = val_len; + spi_message_add_tail(&xfer[1], &msg); + } else { + xfer[0].rx_buf = buf_rx; + xfer[0].len = sizeof(buf_tx->cmd) + val_len; - if (TCAN4X5X_SANITIZE_SPI) - memset(buf_tx->data, 0x0, val_len); + if (TCAN4X5X_SANITIZE_SPI) + memset(buf_tx->data, 0x0, val_len); + } err = spi_sync(spi, &msg); if (err) return err; - memcpy(val_buf, buf_rx->data, val_len); + if (!(spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX)) + memcpy(val_buf, buf_rx->data, val_len); return 0; } From 0de70e287b44a0735273919c987313f021cccb72 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 16 Dec 2020 18:49:28 +0100 Subject: [PATCH 17/19] can: raw: return -ERANGE when filterset does not fit into user space buffer Multiple filters (struct can_filter) can be set with the setsockopt() function, which was originally intended as a write-only operation. As getsockopt() also provides a CAN_RAW_FILTER option to read back the given filters, the caller has to provide an appropriate user space buffer. In the case this buffer is too small the getsockopt() silently truncates the filter information and gives no information about the needed space. This is safe but not convenient for the programmer. In net/core/sock.c the SO_PEERGROUPS sockopt had a similar requirement and solved it by returning -ERANGE in the case that the provided data does not fit into the given user space buffer and fills the required size into optlen, so that the caller can retry with a matching buffer length. This patch adopts this approach for CAN_RAW_FILTER getsockopt(). Reported-by: Phillip Schichtel Signed-off-by: Oliver Hartkopp Tested-By: Phillip Schichtel Link: https://lore.kernel.org/r/20201216174928.21663-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- net/can/raw.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/can/raw.c b/net/can/raw.c index 6ec8aa1d0da46..37b47a39a3edc 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -665,10 +665,18 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, if (ro->count > 0) { int fsize = ro->count * sizeof(struct can_filter); - if (len > fsize) - len = fsize; - if (copy_to_user(optval, ro->filter, len)) - err = -EFAULT; + /* user space buffer to small for filter list? */ + if (len < fsize) { + /* return -ERANGE and needed space in optlen */ + err = -ERANGE; + if (put_user(fsize, optlen)) + err = -EFAULT; + } else { + if (len > fsize) + len = fsize; + if (copy_to_user(optval, ro->filter, len)) + err = -EFAULT; + } } else { len = 0; } From 8b76621b8917a87a8da5fd19f615ff573abf27a3 Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Fri, 6 Nov 2020 18:56:24 +0800 Subject: [PATCH 18/19] dt-bindings: can: fsl,flexcan: add fsl,scu-index property to indicate a resource For SoCs with SCU support, need setup stop mode via SCU firmware, so this property can help indicate a resource in SCU firmware. Signed-off-by: Joakim Zhang Link: https://lore.kernel.org/r/20201106105627.31061-3-qiangqing.zhang@nxp.com Signed-off-by: Marc Kleine-Budde --- .../devicetree/bindings/net/can/fsl,flexcan.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml index 0d2df30f19db6..fe6a949a2eab2 100644 --- a/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml +++ b/Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml @@ -110,6 +110,16 @@ properties: description: Enable CAN remote wakeup. + fsl,scu-index: + description: | + The scu index of CAN instance. + For SoCs with SCU support, need setup stop mode via SCU firmware, so this + property can help indicate a resource. It supports up to 3 CAN instances + now. + $ref: /schemas/types.yaml#/definitions/uint8 + minimum: 0 + maximum: 2 + required: - compatible - reg @@ -137,4 +147,5 @@ examples: clocks = <&clks 1>, <&clks 2>; clock-names = "ipg", "per"; fsl,stop-mode = <&gpr 0x34 28>; + fsl,scu-index = /bits/ 8 <1>; }; From 812f0116c66a3ebaf0b6062226aa85574dd79f67 Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Fri, 6 Nov 2020 18:56:27 +0800 Subject: [PATCH 19/19] can: flexcan: add CAN wakeup function for i.MX8QM The System Controller Firmware (SCFW) is a low-level system function which runs on a dedicated Cortex-M core to provide power, clock, and resource management. It exists on some i.MX8 processors. e.g. i.MX8QM (QM, QP), and i.MX8QX (QXP, DX). SCU driver manages the IPC interface between host CPU and the SCU firmware running on M4. For i.MX8QM, stop mode request is controlled by System Controller Unit(SCU) firmware, this patch introduces FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW quirk for this function. Signed-off-by: Joakim Zhang Link: https://lore.kernel.org/r/20201106105627.31061-6-qiangqing.zhang@nxp.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 123 ++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 17 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 038fe1036df23..7ab20a6b0d1db 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -9,6 +9,7 @@ // // Based on code originally by Andrey Volkov +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +244,8 @@ #define FLEXCAN_QUIRK_SUPPORT_FD BIT(9) /* support memory detection and correction */ #define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10) +/* Setup stop mode with SCU firmware to support wakeup */ +#define FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW BIT(11) /* Structure of the message buffer */ struct flexcan_mb { @@ -347,6 +351,7 @@ struct flexcan_priv { u8 mb_count; u8 mb_size; u8 clk_src; /* clock source of CAN Protocol Engine */ + u8 scu_idx; u64 rx_mask; u64 tx_mask; @@ -358,6 +363,9 @@ struct flexcan_priv { struct regulator *reg_xceiver; struct flexcan_stop_mode stm; + /* IPC handle when setup stop mode by System Controller firmware(scfw) */ + struct imx_sc_ipc *sc_ipc_handle; + /* Read and Write APIs */ u32 (*read)(void __iomem *addr); void (*write)(u32 val, void __iomem *addr); @@ -387,7 +395,7 @@ static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | - FLEXCAN_QUIRK_SUPPORT_FD, + FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW, }; static struct flexcan_devtype_data fsl_imx8mp_devtype_data = { @@ -546,18 +554,42 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) priv->write(reg_mcr, ®s->mcr); } +static int flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled) +{ + u8 idx = priv->scu_idx; + u32 rsrc_id, val; + + rsrc_id = IMX_SC_R_CAN(idx); + + if (enabled) + val = 1; + else + val = 0; + + /* stop mode request via scu firmware */ + return imx_sc_misc_set_control(priv->sc_ipc_handle, rsrc_id, + IMX_SC_C_IPG_STOP, val); +} + static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; u32 reg_mcr; + int ret; reg_mcr = priv->read(®s->mcr); reg_mcr |= FLEXCAN_MCR_SLF_WAK; priv->write(reg_mcr, ®s->mcr); /* enable stop request */ - regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, - 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { + ret = flexcan_stop_mode_enable_scfw(priv, true); + if (ret < 0) + return ret; + } else { + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); + } return flexcan_low_power_enter_ack(priv); } @@ -566,10 +598,17 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; u32 reg_mcr; + int ret; /* remove stop request */ - regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, - 1 << priv->stm.req_bit, 0); + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) { + ret = flexcan_stop_mode_enable_scfw(priv, false); + if (ret < 0) + return ret; + } else { + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 0); + } reg_mcr = priv->read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; @@ -1867,7 +1906,7 @@ static void unregister_flexcandev(struct net_device *dev) unregister_candev(dev); } -static int flexcan_setup_stop_mode(struct platform_device *pdev) +static int flexcan_setup_stop_mode_gpr(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; @@ -1912,11 +1951,6 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) "gpr %s req_gpr=0x02%x req_bit=%u\n", gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit); - device_set_wakeup_capable(&pdev->dev, true); - - if (of_property_read_bool(np, "wakeup-source")) - device_set_wakeup_enable(&pdev->dev, true); - return 0; out_put_node: @@ -1924,6 +1958,58 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) return ret; } +static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct flexcan_priv *priv; + u8 scu_idx; + int ret; + + ret = of_property_read_u8(pdev->dev.of_node, "fsl,scu-index", &scu_idx); + if (ret < 0) { + dev_dbg(&pdev->dev, "failed to get scu index\n"); + return ret; + } + + priv = netdev_priv(dev); + priv->scu_idx = scu_idx; + + /* this function could be defered probe, return -EPROBE_DEFER */ + return imx_scu_get_handle(&priv->sc_ipc_handle); +} + +/* flexcan_setup_stop_mode - Setup stop mode for wakeup + * + * Return: = 0 setup stop mode successfully or doesn't support this feature + * < 0 fail to setup stop mode (could be defered probe) + */ +static int flexcan_setup_stop_mode(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct flexcan_priv *priv; + int ret; + + priv = netdev_priv(dev); + + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) + ret = flexcan_setup_stop_mode_scfw(pdev); + else if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) + ret = flexcan_setup_stop_mode_gpr(pdev); + else + /* return 0 directly if doesn't support stop mode feature */ + return 0; + + if (ret) + return ret; + + device_set_wakeup_capable(&pdev->dev, true); + + if (of_property_read_bool(pdev->dev.of_node, "wakeup-source")) + device_set_wakeup_enable(&pdev->dev, true); + + return 0; +} + static const struct of_device_id flexcan_of_match[] = { { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, @@ -2054,17 +2140,20 @@ static int flexcan_probe(struct platform_device *pdev) goto failed_register; } + err = flexcan_setup_stop_mode(pdev); + if (err < 0) { + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, "setup stop mode failed\n"); + goto failed_setup_stop_mode; + } + of_can_transceiver(dev); devm_can_led_init(dev); - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) { - err = flexcan_setup_stop_mode(pdev); - if (err) - dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); - } - return 0; + failed_setup_stop_mode: + unregister_flexcandev(dev); failed_register: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev);