M_CAN Framework re-write
Subsystems (5)
v5 cover M_CAN Framework re-write
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from the m_can base file to a platfrom file.
The next patch "Migrate the m_can code to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames the m_can_priv to m_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.
AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then m_can functionality is affected in the migration patch.
Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can: m_can: Create a m_can platform framework
can: m_can: Migrate the m_can code to use the framework
can: m_can: Rename m_can_priv to m_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel
.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Signature · 1 line
2.20.1.390.gb5101f9297
PATCH v5 1/5 can: m_can: Create a m_can platform framework
Create a m_can platform framework that peripherial devices can register to and use common code and register sets. The peripherial devices may provide read/write and configuration support of the IP.
---
v5 - Created ops struct, renamed header to m_can.h, updated license and copyright added MODULE_AUTHOR and removed unneeded changes - https://lore.kernel.org/patchwork/patch/1033094/
drivers/net/can/m_can/m_can.h | 159 ++++++++++++++++++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c
drivers/net/can/m_can/m_can.h new file +159 -0
@@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#ifndef _CAN_M_CAN_H_ +#define _CAN_M_CAN_H_ + +#include <linux/can/core.h> +#include <linux/can/led.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/freezer.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/iopoll.h> +#include <linux/can/dev.h> +#include <linux/pinctrl/consumer.h> + +/* m_can lec values */ +enum m_can_lec_type { +LEC_NO_ERROR =0 , +LEC_STUFF_ERROR , +LEC_FORM_ERROR , +LEC_ACK_ERROR , +LEC_BIT1_ERROR , +LEC_BIT0_ERROR , +LEC_CRC_ERROR , +LEC_UNUSED , +}; + +enum m_can_mram_cfg { +MRAM_SIDF =0 , +MRAM_XIDF , +MRAM_RXF0 , +MRAM_RXF1 , +MRAM_RXB , +MRAM_TXE , +MRAM_TXB , +MRAM_CFG_NUM , +}; + +/* registers definition */ +enum m_can_reg { +M_CAN_CREL =0x0 , +M_CAN_ENDN =0x4 , +M_CAN_CUST =0x8 , +M_CAN_DBTP =0xc , +M_CAN_TEST =0x10 , +M_CAN_RWD =0x14 , +M_CAN_CCCR =0x18 , +M_CAN_NBTP =0x1c , +M_CAN_TSCC =0x20 , +M_CAN_TSCV =0x24 , +M_CAN_TOCC =0x28 , +M_CAN_TOCV =0x2c , +M_CAN_ECR =0x40 , +M_CAN_PSR =0x44 , +/* TDCR Register only available for version >=3.1.x */ +M_CAN_TDCR =0x48 , +M_CAN_IR =0x50 , +M_CAN_IE =0x54 , +M_CAN_ILS =0x58 , +M_CAN_ILE =0x5c , +M_CAN_GFC =0x80 , +M_CAN_SIDFC =0x84 , +M_CAN_XIDFC =0x88 , +M_CAN_XIDAM =0x90 , +M_CAN_HPMS =0x94 , +M_CAN_NDAT1 =0x98 , +M_CAN_NDAT2 =0x9c , +M_CAN_RXF0C =0xa0 , +M_CAN_RXF0S =0xa4 , +M_CAN_RXF0A =0xa8 , +M_CAN_RXBC =0xac , +M_CAN_RXF1C =0xb0 , +M_CAN_RXF1S =0xb4 , +M_CAN_RXF1A =0xb8 , +M_CAN_RXESC =0xbc , +M_CAN_TXBC =0xc0 , +M_CAN_TXFQS =0xc4 , +M_CAN_TXESC =0xc8 , +M_CAN_TXBRP =0xcc , +M_CAN_TXBAR =0xd0 , +M_CAN_TXBCR =0xd4 , +M_CAN_TXBTO =0xd8 , +M_CAN_TXBCF =0xdc , +M_CAN_TXBTIE =0xe0 , +M_CAN_TXBCIE =0xe4 , +M_CAN_TXEFC =0xf0 , +M_CAN_TXEFS =0xf4 , +M_CAN_TXEFA =0xf8 , +}; + +/* address offset and element number for each FIFO/Buffer in the Message RAM */ +struct mram_cfg { +u16 off; +u8 num; +}; + +struct m_can_priv ; +struct m_can_ops { +/* Device specific call backs */ +int (*clr_dev_interrupts) (struct m_can_priv *m_can_class); +u32 (*read_reg) (struct m_can_priv *m_can_class,int reg); +int (*write_reg) (struct m_can_priv *m_can_class,int reg,int val); +u32 (*read_fifo) (struct m_can_priv *m_can_class,int addr_offset); +int (*write_fifo) (struct m_can_priv *m_can_class,int addr_offset,int val); +int (*device_init) (struct m_can_priv *m_can_class); +}; + +struct m_can_priv { +struct can_priv can; +struct napi_struct napi; +struct net_device *net; +struct device *dev; +struct clk *hclk; +struct clk *cclk; + +struct workqueue_struct *wq; +struct work_struct tx_work; +struct sk_buff *skb; + +struct can_bittiming_const *bit_timing; +struct can_bittiming_const *data_timing; + +struct m_can_ops *ops; + +void *device_data; + +int version; +int freq; +u32 irqstatus; + +int pm_clock_support; +bool is_peripherial; + +struct mram_cfg mcfg[MRAM_CFG_NUM ]; +}; + +struct m_can_priv *m_can_class_allocate_dev (struct device *dev); +int m_can_class_register (struct m_can_priv *m_can_dev); +void m_can_class_unregister (struct m_can_priv *m_can_dev); +int m_can_class_get_clocks (struct m_can_priv *m_can_dev); +void m_can_init_ram (struct m_can_priv *priv); +void m_can_config_endisable (struct m_can_priv *priv,bool enable); + +int m_can_class_suspend (struct device *dev); +int m_can_class_resume (struct device *dev); +#endif /* _CAN_M_H_ */
drivers/net/can/m_can/m_can_platform.c new file +198 -0
198 lines not on this page · raw message
Signature · 1 line
2.20.1.390.gb5101f9297
Re: [PATCH v5 1/5] can: m_can: Create a m_can platform framework
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 114 lines
Create a
m_canplatform framework that peripherial
devices can register to and use common code and register sets.
The peripherial devices may provide read/write and configuration> support of the IP.Signed-off-by Dan Murphy <[email protected]>---
v5 - Created ops struct, renamed header to
m_can.h, updated license and copyright addedMODULE_AUTHORand removed unneeded changes - https://lore.kernel.org/patchwork/patch/1033094/drivers/net/can/m_can/m_can.h | 159 ++++++++++++++++++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.cdrivers/net/can/m_can/m_can.h new file +92
-0@@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#ifndef _CAN_M_CAN_H_ +#define _CAN_M_CAN_H_ + +#include <linux/can/core.h> +#include <linux/can/led.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/freezer.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/iopoll.h> +#include <linux/can/dev.h> +#include <linux/pinctrl/consumer.h> + +/* m_can lec values */ +enum m_can_lec_type { +LEC_NO_ERROR =0 , +LEC_STUFF_ERROR , +LEC_FORM_ERROR , +LEC_ACK_ERROR , +LEC_BIT1_ERROR , +LEC_BIT0_ERROR , +LEC_CRC_ERROR , +LEC_UNUSED , +}; + +enum m_can_mram_cfg { +MRAM_SIDF =0 , +MRAM_XIDF , +MRAM_RXF0 , +MRAM_RXF1 , +MRAM_RXB , +MRAM_TXE , +MRAM_TXB , +MRAM_CFG_NUM , +}; + +/* registers definition */ +enum m_can_reg { +M_CAN_CREL =0x0 , +M_CAN_ENDN =0x4 , +M_CAN_CUST =0x8 , +M_CAN_DBTP =0xc , +M_CAN_TEST =0x10 , +M_CAN_RWD =0x14 , +M_CAN_CCCR =0x18 , +M_CAN_NBTP =0x1c , +M_CAN_TSCC =0x20 , +M_CAN_TSCV =0x24 , +M_CAN_TOCC =0x28 , +M_CAN_TOCV =0x2c , +M_CAN_ECR =0x40 , +M_CAN_PSR =0x44 , +/* TDCR Register only available for version >=3.1.x */ +M_CAN_TDCR =0x48 , +M_CAN_IR =0x50 , +M_CAN_IE =0x54 , +M_CAN_ILS =0x58 , +M_CAN_ILE =0x5c , +M_CAN_GFC =0x80 , +M_CAN_SIDFC =0x84 , +M_CAN_XIDFC =0x88 , +M_CAN_XIDAM =0x90 , +M_CAN_HPMS =0x94 , +M_CAN_NDAT1 =0x98 , +M_CAN_NDAT2 =0x9c , +M_CAN_RXF0C =0xa0 , +M_CAN_RXF0S =0xa4 , +M_CAN_RXF0A =0xa8 , +M_CAN_RXBC =0xac , +M_CAN_RXF1C =0xb0 , +M_CAN_RXF1S =0xb4 , +M_CAN_RXF1A =0xb8 , +M_CAN_RXESC =0xbc , +M_CAN_TXBC =0xc0 , +M_CAN_TXFQS =0xc4 , +M_CAN_TXESC =0xc8 , + M_CAN_TXBRP = 0xcc,
drivers/net/can/m_can/m_can.h line 102
Quoted 10 lines
drivers/net/can/m_can/m_can.h new file +10
-0+M_CAN_TXBAR =0xd0 , +M_CAN_TXBCR =0xd4 , +M_CAN_TXBTO =0xd8 , +M_CAN_TXBCF =0xdc , +M_CAN_TXBTIE =0xe0 , +M_CAN_TXBCIE =0xe4 , +M_CAN_TXEFC =0xf0 , +M_CAN_TXEFS =0xf4 , + M_CAN_TXEFA = 0xf8, +};
You moved the register offsets here but not the register flags and masks. Why?
Quoted 250 lines
drivers/net/can/m_can/m_can.h new file +56
-0+/* address offset and element number for each FIFO/Buffer in the Message RAM */ +struct mram_cfg { +u16 off; +u8 num; +}; + +struct m_can_priv ; +struct m_can_ops { +/* Device specific call backs */ +int (*clr_dev_interrupts) (struct m_can_priv *m_can_class); +u32 (*read_reg) (struct m_can_priv *m_can_class,int reg); +int (*write_reg) (struct m_can_priv *m_can_class,int reg,int val); +u32 (*read_fifo) (struct m_can_priv *m_can_class,int addr_offset); +int (*write_fifo) (struct m_can_priv *m_can_class,int addr_offset,int val); +int (*device_init) (struct m_can_priv *m_can_class); +}; + +struct m_can_priv { +struct can_priv can; +struct napi_struct napi; +struct net_device *net; +struct device *dev; +struct clk *hclk; +struct clk *cclk; + +struct workqueue_struct *wq; +struct work_struct tx_work; +struct sk_buff *skb; + +struct can_bittiming_const *bit_timing; +struct can_bittiming_const *data_timing; + +struct m_can_ops *ops; + +void *device_data; + +int version; +int freq; +u32 irqstatus; + +int pm_clock_support; +bool is_peripherial; + +struct mram_cfg mcfg[MRAM_CFG_NUM ]; +}; + +struct m_can_priv *m_can_class_allocate_dev (struct device *dev); +int m_can_class_register (struct m_can_priv *m_can_dev); +void m_can_class_unregister (struct m_can_priv *m_can_dev); +int m_can_class_get_clocks (struct m_can_priv *m_can_dev); +void m_can_init_ram (struct m_can_priv *priv); +void m_can_config_endisable (struct m_can_priv *priv,bool enable); + +int m_can_class_suspend (struct device *dev); +int m_can_class_resume (struct device *dev); +#endif /* _CAN_M_H_ */ drivers/net/can/m_can/m_can_platform.c new file +188
-0@@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// IOMapped CAN bus driver for Bosch M_CAN controller +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Dong Aisheng <[email protected]> +// +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/platform_device.h> + +#include "m_can.h" + +struct m_can_plat_priv { +void __iomem *base; +void __iomem *mram_base; +}; + +static u32 iomap_read_reg (struct m_can_priv *m_can_class,int reg) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +return readl (priv->base + reg); +} + +static u32 iomap_read_fifo (struct m_can_priv *m_can_class,int offset) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +return readl (priv->mram_base + offset); +} + +static int iomap_write_reg (struct m_can_priv *m_can_class,int reg,int val) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +writel (val, priv->base + reg); + +return 0 ; +} + +static int iomap_write_fifo (struct m_can_priv *m_can_class,int offset,int val) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +writel (val, priv->mram_base + offset); + +return 0 ; +} + +static struct m_can_ops m_can_plat_ops = { + .read_reg = iomap_read_reg, + .write_reg = iomap_write_reg, + .write_fifo = iomap_write_fifo, + .read_fifo = iomap_read_fifo, +}; + +static int m_can_plat_probe (struct platform_device *pdev) +{ +struct m_can_priv *mcan_class; +struct m_can_plat_priv *priv; +struct resource *res; +void __iomem *addr; +void __iomem *mram_addr; +int irq, ret =0 ; + + mcan_class =m_can_class_allocate_dev (&pdev->dev); + priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"m_can" ); + addr =devm_ioremap_resource (&pdev->dev, res); + irq =platform_get_irq_byname (pdev,"int0" ); +if (IS_ERR (addr) || irq <0 ) { + ret = -EINVAL ; + goto failed_ret; + } + +/* message ram could be shared */ + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"message_ram" ); +if (!res) { + ret = -ENODEV ; + goto failed_ret; + } + + mram_addr =devm_ioremap (&pdev->dev, res->start,resource_size (res)); +if (!mram_addr) { + ret = -ENOMEM ; + goto failed_ret; + } + + priv->base = addr; + priv->mram_base = mram_addr; + + mcan_class->net->irq = irq; + mcan_class->pm_clock_support =1 ; + mcan_class->can.clock.freq =clk_get_rate (mcan_class->cclk); + mcan_class->dev = &pdev->dev; + + mcan_class->ops = &m_can_plat_ops; + + mcan_class->is_peripherial = false; + +platform_set_drvdata (pdev, mcan_class->dev); + +m_can_init_ram (mcan_class); + + ret =m_can_class_register (mcan_class); + +failed_ret: +return ret; +} + +static __maybe_unused int m_can_suspend (struct device *dev) +{ +return m_can_class_suspend (dev); +} + +static __maybe_unused int m_can_resume (struct device *dev) +{ +return m_can_class_resume (dev); +} + +static int m_can_plat_remove (struct platform_device *pdev) +{ +struct net_device *dev =platform_get_drvdata (pdev); +struct m_can_priv *mcan_class =netdev_priv (dev); + +m_can_class_unregister (mcan_class); + +platform_set_drvdata (pdev,NULL ); + +return 0 ; +} + +static int __maybe_unused m_can_runtime_suspend (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct m_can_priv *mcan_class =netdev_priv (ndev); + +m_can_class_suspend (dev); + +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + +return 0 ; +} + +static int __maybe_unused m_can_runtime_resume (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct m_can_priv *mcan_class =netdev_priv (ndev); +int err; + + err =clk_prepare_enable (mcan_class->hclk); +if (err) +return err; + + err =clk_prepare_enable (mcan_class->cclk); +if (err) +clk_disable_unprepare (mcan_class->hclk); + +m_can_class_resume (dev); + +return err; +} + +static const struct dev_pm_ops m_can_pmops = { + SET_RUNTIME_PM_OPS(m_can_runtime_suspend, + m_can_runtime_resume, NULL) +SET_SYSTEM_SLEEP_PM_OPS (m_can_suspend, m_can_resume) +}; + +static const struct of_device_id m_can_of_table[] = { + { .compatible ="bosch,m_can" , .data =NULL }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, m_can_of_table); + +static struct platform_driver m_can_plat_driver = { + .driver = { + .name =KBUILD_MODNAME , + .of_match_table = m_can_of_table, + .pm = &m_can_pmops, + },
drivers/net/can/m_can/m_can_platform.c line 198
Quoted 10 lines
drivers/net/can/m_can/m_can_platform.c new file +10
-0+ .probe = m_can_plat_probe, + .remove = m_can_plat_remove, +}; + +module_platform_driver (m_can_plat_driver); + +MODULE_AUTHOR ("Dong Aisheng <[email protected]>" ); +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_DESCRIPTION ("CAN bus driver for Bosch M_CAN controller" );
Please fix the description.
Wolfgang
Re: [PATCH v5 1/5] can: m_can: Create a m_can platform framework
Wolfgang
Quoted 121 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 119 lines
Create a
m_canplatform framework that peripherial
devices can register to and use common code and register sets.
The peripherial devices may provide read/write and configuration> support of the IP.Signed-off-by Dan Murphy <[email protected]>---
v5 - Created ops struct, renamed header to
m_can.h, updated license and copyright addedMODULE_AUTHORand removed unneeded changes - https://lore.kernel.org/patchwork/patch/1033094/drivers/net/can/m_can/m_can.h | 159 ++++++++++++++++++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.cdrivers/net/can/m_can/m_can.h new file +97
-0@@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +#ifndef _CAN_M_CAN_H_ +#define _CAN_M_CAN_H_ + +#include <linux/can/core.h> +#include <linux/can/led.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/freezer.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/iopoll.h> +#include <linux/can/dev.h> +#include <linux/pinctrl/consumer.h> + +/* m_can lec values */ +enum m_can_lec_type { +LEC_NO_ERROR =0 , +LEC_STUFF_ERROR , +LEC_FORM_ERROR , +LEC_ACK_ERROR , +LEC_BIT1_ERROR , +LEC_BIT0_ERROR , +LEC_CRC_ERROR , +LEC_UNUSED , +}; + +enum m_can_mram_cfg { +MRAM_SIDF =0 , +MRAM_XIDF , +MRAM_RXF0 , +MRAM_RXF1 , +MRAM_RXB , +MRAM_TXE , +MRAM_TXB , +MRAM_CFG_NUM , +}; + +/* registers definition */ +enum m_can_reg { +M_CAN_CREL =0x0 , +M_CAN_ENDN =0x4 , +M_CAN_CUST =0x8 , +M_CAN_DBTP =0xc , +M_CAN_TEST =0x10 , +M_CAN_RWD =0x14 , +M_CAN_CCCR =0x18 , +M_CAN_NBTP =0x1c , +M_CAN_TSCC =0x20 , +M_CAN_TSCV =0x24 , +M_CAN_TOCC =0x28 , +M_CAN_TOCV =0x2c , +M_CAN_ECR =0x40 , +M_CAN_PSR =0x44 , +/* TDCR Register only available for version >=3.1.x */ +M_CAN_TDCR =0x48 , +M_CAN_IR =0x50 , +M_CAN_IE =0x54 , +M_CAN_ILS =0x58 , +M_CAN_ILE =0x5c , +M_CAN_GFC =0x80 , +M_CAN_SIDFC =0x84 , +M_CAN_XIDFC =0x88 , +M_CAN_XIDAM =0x90 , +M_CAN_HPMS =0x94 , +M_CAN_NDAT1 =0x98 , +M_CAN_NDAT2 =0x9c , +M_CAN_RXF0C =0xa0 , +M_CAN_RXF0S =0xa4 , +M_CAN_RXF0A =0xa8 , +M_CAN_RXBC =0xac , +M_CAN_RXF1C =0xb0 , +M_CAN_RXF1S =0xb4 , +M_CAN_RXF1A =0xb8 , +M_CAN_RXESC =0xbc , +M_CAN_TXBC =0xc0 , +M_CAN_TXFQS =0xc4 , +M_CAN_TXESC =0xc8 , +M_CAN_TXBRP =0xcc , +M_CAN_TXBAR =0xd0 , +M_CAN_TXBCR =0xd4 , +M_CAN_TXBTO =0xd8 , +M_CAN_TXBCF =0xdc , + M_CAN_TXBTIE = 0xe0,
Quoted 9 lines
drivers/net/can/m_can/m_can.h line 102
Quoted 5 lines
drivers/net/can/m_can/m_can.h new file +5
-0+M_CAN_TXBCIE =0xe4 , +M_CAN_TXEFC =0xf0 , +M_CAN_TXEFS =0xf4 , + M_CAN_TXEFA = 0xf8, +};You moved the register offsets here but not the register flags and masks. Why?
I can move this back to the m_can.c. I had this here for debugging so I can read the m_can registers. It is a debug artifact.
Quoted 254 lines
Quoted 254 lines
drivers/net/can/m_can/m_can.h new file +56
-0+/* address offset and element number for each FIFO/Buffer in the Message RAM */ +struct mram_cfg { +u16 off; +u8 num; +}; + +struct m_can_priv ; +struct m_can_ops { +/* Device specific call backs */ +int (*clr_dev_interrupts) (struct m_can_priv *m_can_class); +u32 (*read_reg) (struct m_can_priv *m_can_class,int reg); +int (*write_reg) (struct m_can_priv *m_can_class,int reg,int val); +u32 (*read_fifo) (struct m_can_priv *m_can_class,int addr_offset); +int (*write_fifo) (struct m_can_priv *m_can_class,int addr_offset,int val); +int (*device_init) (struct m_can_priv *m_can_class); +}; + +struct m_can_priv { +struct can_priv can; +struct napi_struct napi; +struct net_device *net; +struct device *dev; +struct clk *hclk; +struct clk *cclk; + +struct workqueue_struct *wq; +struct work_struct tx_work; +struct sk_buff *skb; + +struct can_bittiming_const *bit_timing; +struct can_bittiming_const *data_timing; + +struct m_can_ops *ops; + +void *device_data; + +int version; +int freq; +u32 irqstatus; + +int pm_clock_support; +bool is_peripherial; + +struct mram_cfg mcfg[MRAM_CFG_NUM ]; +}; + +struct m_can_priv *m_can_class_allocate_dev (struct device *dev); +int m_can_class_register (struct m_can_priv *m_can_dev); +void m_can_class_unregister (struct m_can_priv *m_can_dev); +int m_can_class_get_clocks (struct m_can_priv *m_can_dev); +void m_can_init_ram (struct m_can_priv *priv); +void m_can_config_endisable (struct m_can_priv *priv,bool enable); + +int m_can_class_suspend (struct device *dev); +int m_can_class_resume (struct device *dev); +#endif /* _CAN_M_H_ */ drivers/net/can/m_can/m_can_platform.c new file +192
-0@@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// IOMapped CAN bus driver for Bosch M_CAN controller +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Dong Aisheng <[email protected]> +// +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/platform_device.h> + +#include "m_can.h" + +struct m_can_plat_priv { +void __iomem *base; +void __iomem *mram_base; +}; + +static u32 iomap_read_reg (struct m_can_priv *m_can_class,int reg) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +return readl (priv->base + reg); +} + +static u32 iomap_read_fifo (struct m_can_priv *m_can_class,int offset) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +return readl (priv->mram_base + offset); +} + +static int iomap_write_reg (struct m_can_priv *m_can_class,int reg,int val) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +writel (val, priv->base + reg); + +return 0 ; +} + +static int iomap_write_fifo (struct m_can_priv *m_can_class,int offset,int val) +{ +struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data; + +writel (val, priv->mram_base + offset); + +return 0 ; +} + +static struct m_can_ops m_can_plat_ops = { + .read_reg = iomap_read_reg, + .write_reg = iomap_write_reg, + .write_fifo = iomap_write_fifo, + .read_fifo = iomap_read_fifo, +}; + +static int m_can_plat_probe (struct platform_device *pdev) +{ +struct m_can_priv *mcan_class; +struct m_can_plat_priv *priv; +struct resource *res; +void __iomem *addr; +void __iomem *mram_addr; +int irq, ret =0 ; + + mcan_class =m_can_class_allocate_dev (&pdev->dev); + priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); + + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"m_can" ); + addr =devm_ioremap_resource (&pdev->dev, res); + irq =platform_get_irq_byname (pdev,"int0" ); +if (IS_ERR (addr) || irq <0 ) { + ret = -EINVAL ; + goto failed_ret; + } + +/* message ram could be shared */ + res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"message_ram" ); +if (!res) { + ret = -ENODEV ; + goto failed_ret; + } + + mram_addr =devm_ioremap (&pdev->dev, res->start,resource_size (res)); +if (!mram_addr) { + ret = -ENOMEM ; + goto failed_ret; + } + + priv->base = addr; + priv->mram_base = mram_addr; + + mcan_class->net->irq = irq; + mcan_class->pm_clock_support =1 ; + mcan_class->can.clock.freq =clk_get_rate (mcan_class->cclk); + mcan_class->dev = &pdev->dev; + + mcan_class->ops = &m_can_plat_ops; + + mcan_class->is_peripherial = false; + +platform_set_drvdata (pdev, mcan_class->dev); + +m_can_init_ram (mcan_class); + + ret =m_can_class_register (mcan_class); + +failed_ret: +return ret; +} + +static __maybe_unused int m_can_suspend (struct device *dev) +{ +return m_can_class_suspend (dev); +} + +static __maybe_unused int m_can_resume (struct device *dev) +{ +return m_can_class_resume (dev); +} + +static int m_can_plat_remove (struct platform_device *pdev) +{ +struct net_device *dev =platform_get_drvdata (pdev); +struct m_can_priv *mcan_class =netdev_priv (dev); + +m_can_class_unregister (mcan_class); + +platform_set_drvdata (pdev,NULL ); + +return 0 ; +} + +static int __maybe_unused m_can_runtime_suspend (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct m_can_priv *mcan_class =netdev_priv (ndev); + +m_can_class_suspend (dev); + +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + +return 0 ; +} + +static int __maybe_unused m_can_runtime_resume (struct device *dev) +{ +struct net_device *ndev =dev_get_drvdata (dev); +struct m_can_priv *mcan_class =netdev_priv (ndev); +int err; + + err =clk_prepare_enable (mcan_class->hclk); +if (err) +return err; + + err =clk_prepare_enable (mcan_class->cclk); +if (err) +clk_disable_unprepare (mcan_class->hclk); + +m_can_class_resume (dev); + +return err; +} + +static const struct dev_pm_ops m_can_pmops = { + SET_RUNTIME_PM_OPS(m_can_runtime_suspend, + m_can_runtime_resume, NULL) +SET_SYSTEM_SLEEP_PM_OPS (m_can_suspend, m_can_resume) +}; + +static const struct of_device_id m_can_of_table[] = { + { .compatible ="bosch,m_can" , .data =NULL }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, m_can_of_table); + +static struct platform_driver m_can_plat_driver = { + .driver = { + .name =KBUILD_MODNAME , + .of_match_table = m_can_of_table, + .pm = &m_can_pmops, + }, + .probe = m_can_plat_probe, + .remove = m_can_plat_remove, +}; +
Quoted 8 lines
drivers/net/can/m_can/m_can_platform.c line 198
Quoted 6 lines
drivers/net/can/m_can/m_can_platform.c new file +6
-0+module_platform_driver (m_can_plat_driver); + +MODULE_AUTHOR ("Dong Aisheng <[email protected]>" ); +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_LICENSE ("GPL v2" ); +MODULE_DESCRIPTION ("CAN bus driver for Bosch M_CAN controller" );Please fix the description.
ACK
Quoted 3 lines
Wolfgang
Signature · 2 lines
------------------ Dan Murphy
PATCH v5 2/5 can: m_can: Migrate the m_can code to use the framework
In reply to Dan MurphyMigrate the m_can code to use the m_can_platform framework code.
---
v5 - Updated copyright, change m_can_classdev to m_can_priv, removed extra KCONFIG flag - https://lore.kernel.org/patchwork/patch/1033095/
drivers/net/can/m_can/Kconfig | 8 +- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/m_can.c | 745 ++++++++++++++++----------------- 3 files changed, 367 insertions(+), 387 deletions(-)
drivers/net/can/m_can/Kconfig +7 -1
@@ -1,5 +1,11 @@ config CAN_M_CAN + tristate "Bosch M_CAN support" + ---help--- + Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_PLATFORM + tristate "Bosch M_CAN support for io-mapped devices" depends on HAS_IOMEM - tristate "Bosch M_CAN devices" + depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller.
drivers/net/can/m_can/Makefile +1 -0
@@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_M_CAN) += m_can.o +obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o
drivers/net/can/m_can/m_can.c +359 -386
1,059 lines not on this page · raw message
Signature · 1 line
2.20.1.390.gb5101f9297
Re: [PATCH v5 2/5] can: m_can: Migrate the m_can code to use the framework
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 19 lines
Migrate the
m_cancode to use them_can_platformframework code.Signed-off-by Dan Murphy <[email protected]>---
v5 - Updated copyright, change
m_can_classdevtom_can_priv, removed extra KCONFIG flag - https://lore.kernel.org/patchwork/patch/1033095/drivers/net/can/m_can/Kconfig | 8 +- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/m_can.c | 745 ++++++++++++++++----------------- 3 files changed, 367 insertions(+), 387 deletions(-)drivers/net/can/m_can/Kconfig +0
-0
drivers/net/can/m_can/Kconfig line 4
Quoted 4 lines
drivers/net/can/m_can/Kconfig +3
-0@@ -1,5 +1,11 @@ config CAN_M_CAN + tristate "Bosch M_CAN support" + ---help--- + Say Y here if you want to support for Bosch M_CAN controller.
Typo?
drivers/net/can/m_can/Kconfig line 11
Quoted 8 lines
drivers/net/can/m_can/Kconfig +4
-1+ +config CAN_M_CAN_PLATFORM + tristate "Bosch M_CAN support for io-mapped devices" depends on HAS_IOMEM - tristate "Bosch M_CAN devices" + depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller.
Please update the help.
Quoted 169 lines
drivers/net/can/m_can/Makefile +1
-0@@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_M_CAN) += m_can.o +obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.odrivers/net/can/m_can/m_can.c +16
-107@@ -1,20 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// CAN bus driver for Bosch M_CAN controller +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Dong Aisheng <[email protected]> +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ +/* -* CAN bus driver for Bosch M_CAN controller -* -* Copyright (C) 2014 Freescale Semiconductor, Inc. -* Dong Aisheng <[email protected]> -* * Bosch M_CAN user manual can be obtained from: * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/ * mcan_users_manual_v302.pdf * -* This file is licensed under the terms of the GNU General Public -* License version 2. This program is licensed "as is" without any -* warranty of any kind, whether express or implied. */ -#include <linux/clk.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> @@ -28,87 +24,14 @@#include <linux/can/dev.h> #include <linux/pinctrl/consumer.h> +#include "m_can.h" +/* napi related */ #define M_CAN_NAPI_WEIGHT 64/* message ram configuration data length */ #define MRAM_CFG_LEN 8 -/* registers definition */ -enum m_can_reg { -M_CAN_CREL =0x0 , -M_CAN_ENDN =0x4 , -M_CAN_CUST =0x8 , -M_CAN_DBTP =0xc , -M_CAN_TEST =0x10 , -M_CAN_RWD =0x14 , -M_CAN_CCCR =0x18 , -M_CAN_NBTP =0x1c , -M_CAN_TSCC =0x20 , -M_CAN_TSCV =0x24 , -M_CAN_TOCC =0x28 , -M_CAN_TOCV =0x2c , -M_CAN_ECR =0x40 , -M_CAN_PSR =0x44 , -/* TDCR Register only available for version >=3.1.x */ -M_CAN_TDCR =0x48 , -M_CAN_IR =0x50 , -M_CAN_IE =0x54 , -M_CAN_ILS =0x58 , -M_CAN_ILE =0x5c , -M_CAN_GFC =0x80 , -M_CAN_SIDFC =0x84 , -M_CAN_XIDFC =0x88 , -M_CAN_XIDAM =0x90 , -M_CAN_HPMS =0x94 , -M_CAN_NDAT1 =0x98 , -M_CAN_NDAT2 =0x9c , -M_CAN_RXF0C =0xa0 , -M_CAN_RXF0S =0xa4 , -M_CAN_RXF0A =0xa8 , -M_CAN_RXBC =0xac , -M_CAN_RXF1C =0xb0 , -M_CAN_RXF1S =0xb4 , -M_CAN_RXF1A =0xb8 , -M_CAN_RXESC =0xbc , -M_CAN_TXBC =0xc0 , -M_CAN_TXFQS =0xc4 , -M_CAN_TXESC =0xc8 , -M_CAN_TXBRP =0xcc , -M_CAN_TXBAR =0xd0 , -M_CAN_TXBCR =0xd4 , -M_CAN_TXBTO =0xd8 , -M_CAN_TXBCF =0xdc , -M_CAN_TXBTIE =0xe0 , -M_CAN_TXBCIE =0xe4 , -M_CAN_TXEFC =0xf0 , -M_CAN_TXEFS =0xf4 , -M_CAN_TXEFA =0xf8 , -}; - -/* m_can lec values */ -enum m_can_lec_type { -LEC_NO_ERROR =0 , -LEC_STUFF_ERROR , -LEC_FORM_ERROR , -LEC_ACK_ERROR , -LEC_BIT1_ERROR , -LEC_BIT0_ERROR , -LEC_CRC_ERROR , -LEC_UNUSED , -}; - -enum m_can_mram_cfg { -MRAM_SIDF =0 , -MRAM_XIDF , -MRAM_RXF0 , -MRAM_RXF1 , -MRAM_RXB , -MRAM_TXE , -MRAM_TXB , -MRAM_CFG_NUM , -}; -/* Core Release Register (CREL) */ #define CREL_REL_SHIFT 28#define CREL_REL_MASK (0xF << CREL_REL_SHIFT)@@ -343,77 +266,89 @@ enum m_can_mram_cfg {#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)/* Tx event FIFO Element */ -/* E1 */ #define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) -/* address offset and element number for each FIFO/Buffer in the Message RAM */ -struct mram_cfg { -u16 off; -u8 num; -}; +static u32 m_can_read (struct m_can_priv *priv,enum m_can_reg reg) +{ +u32 ret = -EINVAL ; -/* m_can private data structure */ -struct m_can_priv { -struct can_priv can;/* must be the first member */ -struct napi_struct napi; -struct net_device *dev; -struct device *device; -struct clk *hclk; -struct clk *cclk; -void __iomem *base; -u32 irqstatus; -int version; - -/* message ram configuration */ -void __iomem *mram_base; -struct mram_cfg mcfg[MRAM_CFG_NUM ]; -}; +if (priv->ops->read_reg) + ret = priv->ops->read_reg (priv, reg); + +return ret; +}
drivers/net/can/m_can/m_can.c enum m_can_mram_cfg { · line 289
Quoted 10 lines
drivers/net/can/m_can/m_can.c +7
-2-static inline u32 m_can_read (const struct m_can_priv *priv,enum m_can_reg reg) +static int m_can_write (struct m_can_priv *priv,enum m_can_reg reg,u32 val) { -return readl (priv->base + reg); +int ret = -EINVAL ; + +if (priv->ops->write_reg) + ret = priv->ops->write_reg (priv, reg, val); + +return ret;
Why not just:
if (priv->ops->write_reg) return priv->ops->write_reg(priv, reg, val); else return -EINVAL;
Here and below.
Quoted 159 lines
drivers/net/can/m_can/m_can.c +61
-27} -static inline void m_can_write (const struct m_can_priv *priv, -enum m_can_reg reg,u32 val) +static u32 m_can_fifo_read (struct m_can_priv *priv, +u32 fgi,unsigned int offset) { -writel (val, priv->base + reg); +u32 addr_offset = priv->mcfg[MRAM_RXF0 ].off + fgi *RXF0_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->read_fifo) + ret = priv->ops->read_fifo (priv, addr_offset); + +return ret; } -static inline u32 m_can_fifo_read (const struct m_can_priv *priv, -u32 fgi,unsigned int offset) +static u32 m_can_fifo_write (struct m_can_priv *priv, +u32 fpi,unsigned int offset,u32 val) { -return readl (priv->mram_base + priv->mcfg[MRAM_RXF0 ].off + - fgi *RXF0_ELEMENT_SIZE + offset); +u32 addr_offset = priv->mcfg[MRAM_TXB ].off + fpi *TXB_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->write_fifo) + ret = priv->ops->write_fifo (priv, addr_offset, val); + +return ret; } -static inline void m_can_fifo_write (const struct m_can_priv *priv, -u32 fpi,unsigned int offset,u32 val) +static u32 m_can_fifo_write_no_off (struct m_can_priv *priv, +u32 fpi,u32 val) { -writel (val, priv->mram_base + priv->mcfg[MRAM_TXB ].off + - fpi *TXB_ELEMENT_SIZE + offset); +u32 ret =0 ; + +if (priv->ops->write_fifo) + ret = priv->ops->write_fifo (priv, fpi, val); + +return ret; } -static inline u32 m_can_txe_fifo_read (const struct m_can_priv *priv, -u32 fgi, -u32 offset) { -return readl (priv->mram_base + priv->mcfg[MRAM_TXE ].off + - fgi *TXE_ELEMENT_SIZE + offset); +static u32 m_can_txe_fifo_read (struct m_can_priv *priv,u32 fgi,u32 offset) +{ +u32 addr_offset = priv->mcfg[MRAM_TXE ].off + fgi *TXE_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->read_fifo) + ret = priv->ops->read_fifo (priv, addr_offset); + +return ret; } -static inline bool m_can_tx_fifo_full (const struct m_can_priv *priv) +static inline bool m_can_tx_fifo_full (struct m_can_priv *priv) {return !!(m_can_read (priv,M_CAN_TXFQS ) &TXFQS_TFQF ); } -static inline void m_can_config_endisable (const struct m_can_priv *priv, -bool enable) +void m_can_config_endisable (struct m_can_priv *priv,bool enable) {u32 cccr =m_can_read (priv,M_CAN_CCCR );u32 timeout =10 ;u32 val =0 ; +if (cccr &CCCR_CSR ) + cccr &= ~CCCR_CSR ; +if (enable) {/* enable m_can configuration */ m_can_write (priv,M_CAN_CCCR , cccr |CCCR_INIT );@@ -430,7 +365,7 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv,while ((m_can_read (priv,M_CAN_CCCR ) & (CCCR_INIT |CCCR_CCE )) != val) {if (timeout ==0 ) { -netdev_warn (priv->dev,"Failed to init module\n" ); +netdev_warn (priv->net,"Failed to init module\n" );return ; } timeout--;@@ -438,13 +373,13 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv, } } -static inline void m_can_enable_all_interrupts (const struct m_can_priv *priv) +static inline void m_can_enable_all_interrupts (struct m_can_priv *priv) {/* Only interrupt line 0 is used in this driver */ m_can_write (priv,M_CAN_ILE ,ILE_EINT0 ); } -static inline void m_can_disable_all_interrupts (const struct m_can_priv *priv) +static inline void m_can_disable_all_interrupts (struct m_can_priv *priv) {m_can_write (priv,M_CAN_ILE ,0x0 ); }@@ -633,9 +568,12 @@ static int m_can_clk_start(struct m_can_priv *priv) {int err; - err =pm_runtime_get_sync (priv->device); +if (priv->pm_clock_support ==0 ) +return 0 ; + + err =pm_runtime_get_sync (priv->dev);if (err <0 ) { -pm_runtime_put_noidle (priv->device); +pm_runtime_put_noidle (priv->dev);return err; }@@ -644,7 +582,8 @@ static int m_can_clk_start(struct m_can_priv *priv)static void m_can_clk_stop (struct m_can_priv *priv) { -pm_runtime_put_sync (priv->device); +if (priv->pm_clock_support) +pm_runtime_put_sync (priv->dev); } static int m_can_get_berr_counter(const struct net_device *dev,@@ -811,9 +750,8 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,return work_done; } -static int m_can_poll (struct napi_struct *napi,int quota) +static int m_can_rx_handler (struct net_device *dev,int quota) { -struct net_device *dev = napi->dev;struct m_can_priv *priv =netdev_priv (dev);int work_done =0 ;u32 irqstatus, psr;@@ -831,13 +769,33 @@ static int m_can_poll(struct napi_struct *napi, int quota)if (irqstatus &IR_RF0N ) work_done +=m_can_do_rx_poll (dev, (quota - work_done)); +end: +return work_done; +} + +static int m_can_rx_peripherial (struct net_device *dev) +{ +struct m_can_priv *priv =netdev_priv (dev); + +m_can_rx_handler (dev,1 ); +
drivers/net/can/m_can/m_can.c static int m_can_poll(struct napi_struct *napi, int quota) · line 791
Quoted 10 lines
drivers/net/can/m_can/m_can.c +10
-0+m_can_enable_all_interrupts (priv); + +return 0 ; +} + +static int m_can_poll (struct napi_struct *napi,int quota) +{ +struct net_device *dev = napi->dev; +struct m_can_priv *priv =netdev_priv (dev); +int work_done =0 ;
Is the pre-initialization needed?
Quoted 24 lines
drivers/net/can/m_can/m_can.c +5
-2+ work_done =m_can_rx_handler (dev, quota);if (work_done < quota) {napi_complete_done (napi, work_done);m_can_enable_all_interrupts (priv); } -end:return work_done; }@@ -902,7 +860,10 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)if ((ir &IR_RF0N ) || (ir &IR_ERR_ALL_30X )) { priv->irqstatus = ir;m_can_disable_all_interrupts (priv); -napi_schedule (&priv->napi); +if (!priv->is_peripherial) +napi_schedule (&priv->napi); +else +m_can_rx_peripherial (dev); }if (priv->version ==30 ) {
drivers/net/can/m_can/m_can.c static irqreturn_t m_can_isr(int irq, void *dev_id) · line 889
Quoted 5 lines
drivers/net/can/m_can/m_can.c +2
-0@@ -924,6 +885,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) } } +if (priv->ops->clr_dev_interrupts) + priv->ops->clr_dev_interrupts (priv);
post_irq _handler?
Quoted 52 lines
drivers/net/can/m_can/m_can.c +10
-8+return IRQ_HANDLED ; }@@ -1155,6 +1119,9 @@ static void m_can_chip_config(struct net_device *dev)m_can_set_bittiming (dev);m_can_config_endisable (priv, false); + +if (priv->ops->device_init) + priv->ops->device_init (priv); }static void m_can_start (struct net_device *dev)@@ -1188,20 +1155,17 @@ static int m_can_set_mode(struct net_device *dev, enum can_mode mode)* else it returns the release and step coded as: * return value = 10 * <release> + 1 * <step> */ -static int m_can_check_core_release (void __iomem *m_can_base) +static int m_can_check_core_release (struct m_can_priv *priv) {u32 crel_reg;u8 rel;u8 step;int res; -struct m_can_priv temp_priv = { - .base = m_can_base - };/* Read Core Release Version and split into version number * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1; */ - crel_reg =m_can_read (&temp_priv,M_CAN_CREL ); + crel_reg =m_can_read (priv,M_CAN_CREL ); rel = (u8)((crel_reg &CREL_REL_MASK ) >>CREL_REL_SHIFT ); step = (u8)((crel_reg &CREL_STEP_MASK ) >>CREL_STEP_SHIFT );@@ -1219,18 +1183,22 @@ static int m_can_check_core_release(void __iomem *m_can_base)/* Selectable Non ISO support only in version 3.2.x * This function checks if the bit is writable. */ -static bool m_can_niso_supported (const struct m_can_priv *priv) +static bool m_can_niso_supported (struct m_can_priv *priv) { -u32 cccr_reg, cccr_poll; -int niso_timeout; +u32 cccr_reg, cccr_poll =0 ; +int niso_timeout = -ETIMEDOUT ; +int i;m_can_config_endisable (priv, true); cccr_reg =m_can_read (priv,M_CAN_CCCR );
drivers/net/can/m_can/m_can.c static int m_can_check_core_release(void __iomem *m_can_base) · line 1201
Quoted 10 lines
drivers/net/can/m_can/m_can.c +5
-2cccr_reg |=CCCR_NISO ;m_can_write (priv,M_CAN_CCCR , cccr_reg); - niso_timeout =readl_poll_timeout ((priv->base +M_CAN_CCCR ), cccr_poll, - (cccr_poll == cccr_reg),0 ,10 ); +for (i =0 ; i <=10 ; i++) { + cccr_poll =m_can_read (priv,M_CAN_CCCR ); +if (cccr_poll == cccr_reg) + niso_timeout =0 ; + }
There is no break and delay in the loop? What was the reason why you can't use readl_poll_timeout()?
Quoted 96 lines
drivers/net/can/m_can/m_can.c +40
-20/* Clear NISO */ cccr_reg &= ~(CCCR_NISO );@@ -1242,107 +1210,95 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)return !niso_timeout; } -static int m_can_dev_setup (struct platform_device *pdev,struct net_device *dev, -void __iomem *addr) +static int m_can_dev_setup (struct m_can_priv *m_can_dev) { -struct m_can_priv *priv; +struct net_device *dev = m_can_dev->net;int m_can_version; - m_can_version =m_can_check_core_release (addr); + m_can_version =m_can_check_core_release (m_can_dev);/* return if unsupported version */ if (!m_can_version) { -dev_err (&pdev->dev,"Unsupported version number: %2d" , +dev_err (m_can_dev->dev,"Unsupported version number: %2d" , m_can_version);return -EINVAL ; } - priv =netdev_priv (dev); -netif_napi_add (dev, &priv->napi, m_can_poll,M_CAN_NAPI_WEIGHT ); +if (!m_can_dev->is_peripherial) +netif_napi_add (dev, &m_can_dev->napi, + m_can_poll,M_CAN_NAPI_WEIGHT );/* Shared properties of all M_CAN versions */ - priv->version = m_can_version; - priv->dev = dev; - priv->base = addr; - priv->can.do_set_mode = m_can_set_mode; - priv->can.do_get_berr_counter = m_can_get_berr_counter; + m_can_dev->version = m_can_version; + m_can_dev->can.do_set_mode = m_can_set_mode; + m_can_dev->can.do_get_berr_counter = m_can_get_berr_counter;/* Set M_CAN supported operations */ - priv->can.ctrlmode_supported =CAN_CTRLMODE_LOOPBACK | + m_can_dev->can.ctrlmode_supported =CAN_CTRLMODE_LOOPBACK |CAN_CTRLMODE_LISTENONLY |CAN_CTRLMODE_BERR_REPORTING |CAN_CTRLMODE_FD ;/* Set properties depending on M_CAN version */ -switch (priv->version) { +switch (m_can_dev->version) {case 30 :/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */ can_set_static_ctrlmode (dev,CAN_CTRLMODE_FD_NON_ISO ); - priv->can.bittiming_const = &m_can_bittiming_const_30X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_30X; +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const = + m_can_dev->data_timing; +else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;break ;case 31 :/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */ can_set_static_ctrlmode (dev,CAN_CTRLMODE_FD_NON_ISO ); - priv->can.bittiming_const = &m_can_bittiming_const_31X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_31X; +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const = + m_can_dev->data_timing; +else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;break ;case 32 : - priv->can.bittiming_const = &m_can_bittiming_const_31X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_31X; + +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const =
drivers/net/can/m_can/m_can.c static bool m_can_niso_supported(const struct m_can_priv *priv) · line 1290
Quoted 10 lines
drivers/net/can/m_can/m_can.c +6
-1+ m_can_dev->data_timing; + else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_31X; - priv->can.ctrlmode_supported |= (m_can_niso_supported (priv) + + m_can_dev->can.ctrlmode_supported |= + (m_can_niso_supported (m_can_dev) ?CAN_CTRLMODE_FD_NON_ISO :0 );
if (m_can_niso_supported(m_can_dev)) m_can_dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
Quoted 77 lines
drivers/net/can/m_can/m_can.c +12
-42break ;default : -dev_err (&pdev->dev,"Unsupported version number: %2d" , - priv->version); +dev_err (m_can_dev->dev,"Unsupported version number: %2d" , + m_can_dev->version);return -EINVAL ; } -return 0 ; -} - -static int m_can_open (struct net_device *dev) -{ -struct m_can_priv *priv =netdev_priv (dev); -int err; - - err =m_can_clk_start (priv); -if (err) -return err; - -/* open the can device */ - err =open_candev (dev); -if (err) { -netdev_err (dev,"failed to open can device\n" ); - goto exit_disable_clks; - } - -/* register interrupt handler */ - err =request_irq (dev->irq, m_can_isr,IRQF_SHARED , dev->name, - dev); -if (err <0 ) { -netdev_err (dev,"failed to request interrupt\n" ); - goto exit_irq_fail; - } - -/* start the m_can controller */ -m_can_start (dev); - -can_led_event (dev,CAN_LED_EVENT_OPEN ); -napi_enable (&priv->napi); -netif_start_queue (dev); +if (m_can_dev->ops->device_init) + m_can_dev->ops->device_init (m_can_dev);return 0 ; - -exit_irq_fail: -close_candev (dev); -exit_disable_clks: -m_can_clk_stop (priv); -return err; }static void m_can_stop (struct net_device *dev)@@ -1361,10 +1317,17 @@ static int m_can_close(struct net_device *dev)struct m_can_priv *priv =netdev_priv (dev);netif_stop_queue (dev); -napi_disable (&priv->napi); +if (!priv->is_peripherial) +napi_disable (&priv->napi);m_can_stop (dev);m_can_clk_stop (priv);free_irq (dev->irq, dev); + +if (priv->is_peripherial) { +destroy_workqueue (priv->wq); + priv->wq =NULL ; + } +close_candev (dev);can_led_event (dev,CAN_LED_EVENT_STOP );@@ -1385,18 +1348,15 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)return !!priv->can.echo_skb[next_idx]; }
drivers/net/can/m_can/m_can.c static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) · line 1355
Quoted 10 lines
drivers/net/can/m_can/m_can.c +4
-4-static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, -struct net_device *dev) +static void m_can_tx_handler (struct m_can_priv *priv) { -struct m_can_priv *priv =netdev_priv (dev); -struct canfd_frame *cf = (struct canfd_frame *)skb->data; +struct canfd_frame *cf = (struct canfd_frame *)priv->skb->data; +struct net_device *dev = priv->net; +struct sk_buff *skb = priv->skb;
Maybe "tx_skb" is a clearer member name..
Quoted 42 lines
drivers/net/can/m_can/m_can.c +17
-7u32 id, cccr, fdflags;int i;int putidx; -if (can_dropped_invalid_skb (dev, skb)) -return NETDEV_TX_OK ; -/* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id &CAN_EFF_FLAG ) {@@ -1451,7 +1411,7 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,netif_stop_queue (dev);netdev_warn (dev,"TX queue active although FIFO is full." ); -return NETDEV_TX_BUSY ; +return ; }/* get put index for frame */ @@ -1492,14 +1452,101 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,m_can_write (priv,M_CAN_TXBAR , (1 << putidx));/* stop network queue if fifo full */ -if (m_can_tx_fifo_full (priv) || -m_can_next_echo_skb_occupied (dev, putidx)) -netif_stop_queue (dev); +if (m_can_tx_fifo_full (priv) || +m_can_next_echo_skb_occupied (dev, putidx)) +netif_stop_queue (dev); + } +} + +static void m_can_tx_work_queue (struct work_struct *ws) +{ + struct m_can_priv *priv = container_of(ws, struct m_can_priv, + tx_work); +m_can_tx_handler (priv); +} + +static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, +struct net_device *dev) +{
drivers/net/can/m_can/m_can.c static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, · line 1480
Quoted 10 lines
drivers/net/can/m_can/m_can.c +10
-0+struct m_can_priv *priv =netdev_priv (dev); + + +if (can_dropped_invalid_skb (dev, skb)) +return NETDEV_TX_OK ; + + priv->skb = skb; +if (priv->is_peripherial) { +netif_stop_queue (priv->net); +queue_work (priv->wq, &priv->tx_work);
s/wq/tx_wq/ ?
Quoted 404 lines
drivers/net/can/m_can/m_can.c +152
-160+ }else { +m_can_tx_handler (priv); }return NETDEV_TX_OK ; } +static int m_can_open (struct net_device *dev) +{ +struct m_can_priv *priv =netdev_priv (dev); +int err; + + err =m_can_clk_start (priv); +if (err) +return err; + +/* open the can device */ + err =open_candev (dev); +if (err) { +netdev_err (dev,"failed to open can device\n" ); + goto exit_disable_clks; + } + +/* register interrupt handler */ +if (priv->is_peripherial) { + priv->wq =alloc_workqueue ("mcan_wq" , +WQ_FREEZABLE |WQ_MEM_RECLAIM ,0 ); +if (!priv->wq) { + err = -ENOMEM ; + goto out_wq_fail; + } + +INIT_WORK (&priv->tx_work, m_can_tx_work_queue); + + err =request_threaded_irq (dev->irq,NULL , m_can_isr, +IRQF_ONESHOT |IRQF_TRIGGER_FALLING , + dev->name, dev); + }else { + err =request_irq (dev->irq, m_can_isr,IRQF_SHARED , dev->name, + dev); + } + +if (err <0 ) { +netdev_err (dev,"failed to request interrupt\n" ); + goto exit_irq_fail; + } + +/* start the m_can controller */ +m_can_start (dev); + +can_led_event (dev,CAN_LED_EVENT_OPEN ); + +if (!priv->is_peripherial) +napi_enable (&priv->napi); + +netif_start_queue (dev); + +return 0 ; + +exit_irq_fail: +if (priv->is_peripherial) +destroy_workqueue (priv->wq); +out_wq_fail: +close_candev (dev); +exit_disable_clks: +m_can_clk_stop (priv); +return err; +} +static const struct net_device_ops m_can_netdev_ops = { .ndo_open = m_can_open, .ndo_stop = m_can_close,@@ -1515,20 +1562,6 @@ static int register_m_can_dev(struct net_device *dev)return register_candev (dev); } -static void m_can_init_ram (struct m_can_priv *priv) -{ -int end, i, start; - -/* initialize the entire Message RAM in use to avoid possible -* ECC/parity checksum errors when reading an uninitialized buffer -*/ - start = priv->mcfg[MRAM_SIDF ].off; - end = priv->mcfg[MRAM_TXB ].off + - priv->mcfg[MRAM_TXB ].num *TXB_ELEMENT_SIZE ; -for (i = start; i < end; i +=4 ) -writel (0x0 , priv->mram_base + i); -} -static void m_can_of_parse_mram (struct m_can_priv *priv,const u32 *mram_config_vals) {@@ -1556,9 +1589,8 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, priv->mcfg[MRAM_TXB ].num = mram_config_vals[7 ] & (TXBC_NDTB_MASK >>TXBC_NDTB_SHIFT ); - dev_dbg(priv->device, - "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n", - priv->mram_base, + dev_dbg(priv->dev, + "sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n", priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num, priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num, priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,@@ -1566,63 +1598,55 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, priv->mcfg[MRAM_RXB ].off, priv->mcfg[MRAM_RXB ].num, priv->mcfg[MRAM_TXE ].off, priv->mcfg[MRAM_TXE ].num, priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); - -m_can_init_ram (priv); } -static int m_can_plat_probe (struct platform_device *pdev) +void m_can_init_ram (struct m_can_priv *priv) { -struct net_device *dev; -struct m_can_priv *priv; -struct resource *res; -void __iomem *addr; -void __iomem *mram_addr; -struct clk *hclk, *cclk; -int irq, ret; -struct device_node *np; -u32 mram_config_vals[MRAM_CFG_LEN ]; -u32 tx_fifo_size; - - np = pdev->dev.of_node; +int end, i, start; - hclk =devm_clk_get (&pdev->dev,"hclk" ); - cclk =devm_clk_get (&pdev->dev,"cclk" ); +/* initialize the entire Message RAM in use to avoid possible +* ECC/parity checksum errors when reading an uninitialized buffer +*/ + start = priv->mcfg[MRAM_SIDF ].off; + end = priv->mcfg[MRAM_TXB ].off + + priv->mcfg[MRAM_TXB ].num *TXB_ELEMENT_SIZE ; -if (IS_ERR (hclk) ||IS_ERR (cclk)) { -dev_err (&pdev->dev,"no clock found\n" ); - ret = -ENODEV ; - goto failed_ret; - } +for (i = start; i < end; i +=4 ) +m_can_fifo_write_no_off (priv, i,0x0 ); +} +EXPORT_SYMBOL_GPL (m_can_init_ram); - res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"m_can" ); - addr =devm_ioremap_resource (&pdev->dev, res); - irq =platform_get_irq_byname (pdev,"int0" ); +int m_can_class_get_clocks (struct m_can_priv *m_can_dev) +{ +int ret =0 ; -if (IS_ERR (addr) || irq <0 ) { - ret = -EINVAL ; - goto failed_ret; - } + m_can_dev->hclk =devm_clk_get (m_can_dev->dev,"hclk" ); + m_can_dev->cclk =devm_clk_get (m_can_dev->dev,"cclk" ); -/* message ram could be shared */ - res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"message_ram" ); -if (!res) { +if (IS_ERR (m_can_dev->cclk)) { +dev_err (m_can_dev->dev,"no clock found\n" ); ret = -ENODEV ; - goto failed_ret; } - mram_addr =devm_ioremap (&pdev->dev, res->start,resource_size (res)); -if (!mram_addr) { - ret = -ENOMEM ; - goto failed_ret; - } +return ret; +} +EXPORT_SYMBOL_GPL (m_can_class_get_clocks); + +struct m_can_priv *m_can_class_allocate_dev (struct device *dev) +{ +struct m_can_priv *class_dev =NULL ; +u32 mram_config_vals[MRAM_CFG_LEN ]; +struct net_device *net_dev; +u32 tx_fifo_size; +int ret; -/* get message ram configuration */ - ret =of_property_read_u32_array (np,"bosch,mram-cfg" , - mram_config_vals, -sizeof (mram_config_vals) /4 ); + ret =fwnode_property_read_u32_array (dev_fwnode (dev), +"bosch,mram-cfg" , + mram_config_vals, +sizeof (mram_config_vals) /4 );if (ret) { -dev_err (&pdev->dev,"Could not get Message RAM configuration." ); - goto failed_ret; +dev_err (dev,"Could not get Message RAM configuration." ); + goto out; }/* Get TX FIFO size @@ -1631,66 +1655,74 @@ static int m_can_plat_probe(struct platform_device *pdev) tx_fifo_size = mram_config_vals[7 ];/* allocate the m_can device */ - dev =alloc_candev (sizeof (*priv), tx_fifo_size); -if (!dev) { - ret = -ENOMEM ; - goto failed_ret; + net_dev =alloc_candev (sizeof (*class_dev), tx_fifo_size); +if (!net_dev) { +dev_err (dev,"Failed to allocate CAN device" ); + goto out; } - priv =netdev_priv (dev); - dev->irq = irq; - priv->device = &pdev->dev; - priv->hclk = hclk; - priv->cclk = cclk; - priv->can.clock.freq =clk_get_rate (cclk); - priv->mram_base = mram_addr; + class_dev =netdev_priv (net_dev); +if (!class_dev) { +dev_err (dev,"Failed to init netdev private" ); + goto out; + } -platform_set_drvdata (pdev, dev); -SET_NETDEV_DEV (dev, &pdev->dev); + class_dev->net = net_dev; + class_dev->dev = dev; +SET_NETDEV_DEV (net_dev, dev); -/* Enable clocks. Necessary to read Core Release in order to determine -* M_CAN version -*/ -pm_runtime_enable (&pdev->dev); - ret =m_can_clk_start (priv); -if (ret) - goto pm_runtime_fail; +m_can_of_parse_mram (class_dev, mram_config_vals); +out: +return class_dev; +} +EXPORT_SYMBOL_GPL (m_can_class_allocate_dev); + +int m_can_class_register (struct m_can_priv *m_can_dev) +{ +int ret; - ret =m_can_dev_setup (pdev, dev, addr); +if (m_can_dev->pm_clock_support) { +pm_runtime_enable (m_can_dev->dev); + ret =m_can_clk_start (m_can_dev); +if (ret) + goto pm_runtime_fail; + } + + ret =m_can_dev_setup (m_can_dev);if (ret) goto clk_disable; - ret =register_m_can_dev (dev); + ret =register_m_can_dev (m_can_dev->net);if (ret) { -dev_err (&pdev->dev,"registering %s failed (err=%d)\n" , -KBUILD_MODNAME , ret); +dev_err (m_can_dev->dev,"registering %s failed (err=%d)\n" , + m_can_dev->net->name, ret); goto clk_disable; } -m_can_of_parse_mram (priv, mram_config_vals); - -devm_can_led_init (dev); +devm_can_led_init (m_can_dev->net); -of_can_transceiver (dev); +of_can_transceiver (m_can_dev->net); -dev_info (&pdev->dev,"%s device registered (irq=%d, version=%d)\n" , -KBUILD_MODNAME , dev->irq, priv->version); +dev_info (m_can_dev->dev,"%s device registered (irq=%d, version=%d)\n" , +KBUILD_MODNAME , m_can_dev->net->irq, m_can_dev->version);/* Probe finished * Stop clocks. They will be reactivated once the M_CAN device is opened */ clk_disable: -m_can_clk_stop (priv); +m_can_clk_stop (m_can_dev); pm_runtime_fail:if (ret) { -pm_runtime_disable (&pdev->dev); -free_candev (dev); +if (m_can_dev->pm_clock_support) +pm_runtime_disable (m_can_dev->dev); +free_candev (m_can_dev->net); } -failed_ret: +return ret; } +EXPORT_SYMBOL_GPL (m_can_class_register); -static __maybe_unused int m_can_suspend (struct device *dev) +int m_can_class_suspend (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev);struct m_can_priv *priv =netdev_priv (ndev);@@ -1708,8 +1740,9 @@ static __maybe_unused int m_can_suspend(struct device *dev)return 0 ; } +EXPORT_SYMBOL_GPL (m_can_class_suspend); -static __maybe_unused int m_can_resume (struct device *dev) +int m_can_class_resume (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev);struct m_can_priv *priv =netdev_priv (ndev);@@ -1733,79 +1766,19 @@ static __maybe_unused int m_can_resume(struct device *dev)return 0 ; } +EXPORT_SYMBOL_GPL (m_can_class_resume); -static void unregister_m_can_dev (struct net_device *dev) -{ -unregister_candev (dev); -} - -static int m_can_plat_remove (struct platform_device *pdev) -{ -struct net_device *dev =platform_get_drvdata (pdev); - -unregister_m_can_dev (dev); - -pm_runtime_disable (&pdev->dev); - -platform_set_drvdata (pdev,NULL ); - -free_candev (dev); - -return 0 ; -} - -static int __maybe_unused m_can_runtime_suspend (struct device *dev) -{ -struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *priv =netdev_priv (ndev); - -clk_disable_unprepare (priv->cclk); -clk_disable_unprepare (priv->hclk); - -return 0 ; -} - -static int __maybe_unused m_can_runtime_resume (struct device *dev) +void m_can_class_unregister (struct m_can_priv *m_can_dev) { -struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *priv =netdev_priv (ndev); -int err; - - err =clk_prepare_enable (priv->hclk); -if (err) -return err; +unregister_candev (m_can_dev->net); - err =clk_prepare_enable (priv->cclk); -if (err) -clk_disable_unprepare (priv->hclk); +m_can_clk_stop (m_can_dev); -return err; +free_candev (m_can_dev->net); } - -static const struct dev_pm_ops m_can_pmops = { - SET_RUNTIME_PM_OPS(m_can_runtime_suspend, - m_can_runtime_resume, NULL) -SET_SYSTEM_SLEEP_PM_OPS (m_can_suspend, m_can_resume) -}; - -static const struct of_device_id m_can_of_table[] = { - { .compatible ="bosch,m_can" , .data =NULL }, - {/* sentinel */ }, -}; -MODULE_DEVICE_TABLE (of, m_can_of_table); - -static struct platform_driver m_can_plat_driver = { - .driver = { - .name =KBUILD_MODNAME , - .of_match_table = m_can_of_table, - .pm = &m_can_pmops, - }, - .probe = m_can_plat_probe,
drivers/net/can/m_can/m_can.c static __maybe_unused int m_can_resume(struct device *dev) · line 1784
Quoted 10 lines
drivers/net/can/m_can/m_can.c +2
-4- .remove = m_can_plat_remove, -}; - -module_platform_driver (m_can_plat_driver); +EXPORT_SYMBOL_GPL (m_can_class_unregister);MODULE_AUTHOR ("Dong Aisheng <[email protected]>" ); +MODULE_AUTHOR ("Dan Murphy <[email protected]>" );MODULE_LICENSE ("GPL v2" );MODULE_DESCRIPTION ("CAN bus driver for Bosch M_CAN controller" );
Wolfgang
Re: [PATCH v5 2/5] can: m_can: Migrate the m_can code to use the framework
Wolfgang
Quoted 15 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 14 lines
Migrate the
m_cancode to use them_can_platformframework code.Signed-off-by Dan Murphy <[email protected]>---
v5 - Updated copyright, change
m_can_classdevtom_can_priv, removed extra KCONFIG flag - https://lore.kernel.org/patchwork/patch/1033095/drivers/net/can/m_can/Kconfig | 8 +- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/m_can.c | 745 ++++++++++++++++----------------- 3 files changed, 367 insertions(+), 387 deletions(-)
Quoted 12 lines
drivers/net/can/m_can/Kconfig line 4
Quoted 9 lines
drivers/net/can/m_can/Kconfig +3
-0@@ -1,5 +1,11 @@ config CAN_M_CAN + tristate "Bosch M_CAN support" + ---help--- + Say Y here if you want to support for Bosch M_CAN controller.Typo?
Maybe like you pointed out to update the help.
Quoted 10 lines
drivers/net/can/m_can/Kconfig line 11
Quoted 8 lines
drivers/net/can/m_can/Kconfig +4
-1+ +config CAN_M_CAN_PLATFORM + tristate "Bosch M_CAN support for io-mapped devices" depends on HAS_IOMEM - tristate "Bosch M_CAN devices" + depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller.Please update the help.
Ack
Quoted 183 lines
Quoted 170 lines
drivers/net/can/m_can/Makefile +1
-0@@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_M_CAN) += m_can.o +obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.odrivers/net/can/m_can/m_can.c +16
-107@@ -1,20 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// CAN bus driver for Bosch M_CAN controller +// Copyright (C) 2014 Freescale Semiconductor, Inc. +// Dong Aisheng <[email protected]> +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ +/* -* CAN bus driver for Bosch M_CAN controller -* -* Copyright (C) 2014 Freescale Semiconductor, Inc. -* Dong Aisheng <[email protected]> -* * Bosch M_CAN user manual can be obtained from: * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/ * mcan_users_manual_v302.pdf * -* This file is licensed under the terms of the GNU General Public -* License version 2. This program is licensed "as is" without any -* warranty of any kind, whether express or implied. */ -#include <linux/clk.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> @@ -28,87 +24,14 @@#include <linux/can/dev.h> #include <linux/pinctrl/consumer.h> +#include "m_can.h" +/* napi related */ #define M_CAN_NAPI_WEIGHT 64/* message ram configuration data length */ #define MRAM_CFG_LEN 8 -/* registers definition */ -enum m_can_reg { -M_CAN_CREL =0x0 , -M_CAN_ENDN =0x4 , -M_CAN_CUST =0x8 , -M_CAN_DBTP =0xc , -M_CAN_TEST =0x10 , -M_CAN_RWD =0x14 , -M_CAN_CCCR =0x18 , -M_CAN_NBTP =0x1c , -M_CAN_TSCC =0x20 , -M_CAN_TSCV =0x24 , -M_CAN_TOCC =0x28 , -M_CAN_TOCV =0x2c , -M_CAN_ECR =0x40 , -M_CAN_PSR =0x44 , -/* TDCR Register only available for version >=3.1.x */ -M_CAN_TDCR =0x48 , -M_CAN_IR =0x50 , -M_CAN_IE =0x54 , -M_CAN_ILS =0x58 , -M_CAN_ILE =0x5c , -M_CAN_GFC =0x80 , -M_CAN_SIDFC =0x84 , -M_CAN_XIDFC =0x88 , -M_CAN_XIDAM =0x90 , -M_CAN_HPMS =0x94 , -M_CAN_NDAT1 =0x98 , -M_CAN_NDAT2 =0x9c , -M_CAN_RXF0C =0xa0 , -M_CAN_RXF0S =0xa4 , -M_CAN_RXF0A =0xa8 , -M_CAN_RXBC =0xac , -M_CAN_RXF1C =0xb0 , -M_CAN_RXF1S =0xb4 , -M_CAN_RXF1A =0xb8 , -M_CAN_RXESC =0xbc , -M_CAN_TXBC =0xc0 , -M_CAN_TXFQS =0xc4 , -M_CAN_TXESC =0xc8 , -M_CAN_TXBRP =0xcc , -M_CAN_TXBAR =0xd0 , -M_CAN_TXBCR =0xd4 , -M_CAN_TXBTO =0xd8 , -M_CAN_TXBCF =0xdc , -M_CAN_TXBTIE =0xe0 , -M_CAN_TXBCIE =0xe4 , -M_CAN_TXEFC =0xf0 , -M_CAN_TXEFS =0xf4 , -M_CAN_TXEFA =0xf8 , -}; - -/* m_can lec values */ -enum m_can_lec_type { -LEC_NO_ERROR =0 , -LEC_STUFF_ERROR , -LEC_FORM_ERROR , -LEC_ACK_ERROR , -LEC_BIT1_ERROR , -LEC_BIT0_ERROR , -LEC_CRC_ERROR , -LEC_UNUSED , -}; - -enum m_can_mram_cfg { -MRAM_SIDF =0 , -MRAM_XIDF , -MRAM_RXF0 , -MRAM_RXF1 , -MRAM_RXB , -MRAM_TXE , -MRAM_TXB , -MRAM_CFG_NUM , -}; -/* Core Release Register (CREL) */ #define CREL_REL_SHIFT 28#define CREL_REL_MASK (0xF << CREL_REL_SHIFT)@@ -343,77 +266,89 @@ enum m_can_mram_cfg {#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT)/* Tx event FIFO Element */ -/* E1 */ #define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) -/* address offset and element number for each FIFO/Buffer in the Message RAM */ -struct mram_cfg { -u16 off; -u8 num; -}; +static u32 m_can_read (struct m_can_priv *priv,enum m_can_reg reg) +{ +u32 ret = -EINVAL ; -/* m_can private data structure */ -struct m_can_priv { -struct can_priv can;/* must be the first member */ -struct napi_struct napi; -struct net_device *dev; -struct device *device; -struct clk *hclk; -struct clk *cclk; -void __iomem *base; -u32 irqstatus; -int version; - -/* message ram configuration */ -void __iomem *mram_base; -struct mram_cfg mcfg[MRAM_CFG_NUM ]; -}; +if (priv->ops->read_reg) + ret = priv->ops->read_reg (priv, reg); + +return ret; +}drivers/net/can/m_can/m_can.c enum m_can_mram_cfg { · line 289
Quoted 10 lines
drivers/net/can/m_can/m_can.c +7
-2-static inline u32 m_can_read (const struct m_can_priv *priv,enum m_can_reg reg) +static int m_can_write (struct m_can_priv *priv,enum m_can_reg reg,u32 val) { -return readl (priv->base + reg); +int ret = -EINVAL ; + +if (priv->ops->write_reg) + ret = priv->ops->write_reg (priv, reg, val); + +return ret;Why not just:
Quoted 7 lines
if (priv->ops->write_reg) return priv->ops->write_reg(priv, reg, val); else return -EINVAL;Here and below.
ACK
Quoted 163 lines
Quoted 163 lines
drivers/net/can/m_can/m_can.c +65
-27} -static inline void m_can_write (const struct m_can_priv *priv, -enum m_can_reg reg,u32 val) +static u32 m_can_fifo_read (struct m_can_priv *priv, +u32 fgi,unsigned int offset) { -writel (val, priv->base + reg); +u32 addr_offset = priv->mcfg[MRAM_RXF0 ].off + fgi *RXF0_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->read_fifo) + ret = priv->ops->read_fifo (priv, addr_offset); + +return ret; } -static inline u32 m_can_fifo_read (const struct m_can_priv *priv, -u32 fgi,unsigned int offset) +static u32 m_can_fifo_write (struct m_can_priv *priv, +u32 fpi,unsigned int offset,u32 val) { -return readl (priv->mram_base + priv->mcfg[MRAM_RXF0 ].off + - fgi *RXF0_ELEMENT_SIZE + offset); +u32 addr_offset = priv->mcfg[MRAM_TXB ].off + fpi *TXB_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->write_fifo) + ret = priv->ops->write_fifo (priv, addr_offset, val); + +return ret; } -static inline void m_can_fifo_write (const struct m_can_priv *priv, -u32 fpi,unsigned int offset,u32 val) +static u32 m_can_fifo_write_no_off (struct m_can_priv *priv, +u32 fpi,u32 val) { -writel (val, priv->mram_base + priv->mcfg[MRAM_TXB ].off + - fpi *TXB_ELEMENT_SIZE + offset); +u32 ret =0 ; + +if (priv->ops->write_fifo) + ret = priv->ops->write_fifo (priv, fpi, val); + +return ret; } -static inline u32 m_can_txe_fifo_read (const struct m_can_priv *priv, -u32 fgi, -u32 offset) { -return readl (priv->mram_base + priv->mcfg[MRAM_TXE ].off + - fgi *TXE_ELEMENT_SIZE + offset); +static u32 m_can_txe_fifo_read (struct m_can_priv *priv,u32 fgi,u32 offset) +{ +u32 addr_offset = priv->mcfg[MRAM_TXE ].off + fgi *TXE_ELEMENT_SIZE + offset; +u32 ret = -EINVAL ; + +if (priv->ops->read_fifo) + ret = priv->ops->read_fifo (priv, addr_offset); + +return ret; } -static inline bool m_can_tx_fifo_full (const struct m_can_priv *priv) +static inline bool m_can_tx_fifo_full (struct m_can_priv *priv) {return !!(m_can_read (priv,M_CAN_TXFQS ) &TXFQS_TFQF ); } -static inline void m_can_config_endisable (const struct m_can_priv *priv, -bool enable) +void m_can_config_endisable (struct m_can_priv *priv,bool enable) {u32 cccr =m_can_read (priv,M_CAN_CCCR );u32 timeout =10 ;u32 val =0 ; +if (cccr &CCCR_CSR ) + cccr &= ~CCCR_CSR ; +if (enable) {/* enable m_can configuration */ m_can_write (priv,M_CAN_CCCR , cccr |CCCR_INIT );@@ -430,7 +365,7 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv,while ((m_can_read (priv,M_CAN_CCCR ) & (CCCR_INIT |CCCR_CCE )) != val) {if (timeout ==0 ) { -netdev_warn (priv->dev,"Failed to init module\n" ); +netdev_warn (priv->net,"Failed to init module\n" );return ; } timeout--;@@ -438,13 +373,13 @@ static inline void m_can_config_endisable(const struct m_can_priv *priv, } } -static inline void m_can_enable_all_interrupts (const struct m_can_priv *priv) +static inline void m_can_enable_all_interrupts (struct m_can_priv *priv) {/* Only interrupt line 0 is used in this driver */ m_can_write (priv,M_CAN_ILE ,ILE_EINT0 ); } -static inline void m_can_disable_all_interrupts (const struct m_can_priv *priv) +static inline void m_can_disable_all_interrupts (struct m_can_priv *priv) {m_can_write (priv,M_CAN_ILE ,0x0 ); }@@ -633,9 +568,12 @@ static int m_can_clk_start(struct m_can_priv *priv) {int err; - err =pm_runtime_get_sync (priv->device); +if (priv->pm_clock_support ==0 ) +return 0 ; + + err =pm_runtime_get_sync (priv->dev);if (err <0 ) { -pm_runtime_put_noidle (priv->device); +pm_runtime_put_noidle (priv->dev);return err; }@@ -644,7 +582,8 @@ static int m_can_clk_start(struct m_can_priv *priv)static void m_can_clk_stop (struct m_can_priv *priv) { -pm_runtime_put_sync (priv->device); +if (priv->pm_clock_support) +pm_runtime_put_sync (priv->dev); } static int m_can_get_berr_counter(const struct net_device *dev,@@ -811,9 +750,8 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,return work_done; } -static int m_can_poll (struct napi_struct *napi,int quota) +static int m_can_rx_handler (struct net_device *dev,int quota) { -struct net_device *dev = napi->dev;struct m_can_priv *priv =netdev_priv (dev);int work_done =0 ;u32 irqstatus, psr;@@ -831,13 +769,33 @@ static int m_can_poll(struct napi_struct *napi, int quota)if (irqstatus &IR_RF0N ) work_done +=m_can_do_rx_poll (dev, (quota - work_done)); +end: +return work_done; +} + +static int m_can_rx_peripherial (struct net_device *dev) +{ +struct m_can_priv *priv =netdev_priv (dev); + +m_can_rx_handler (dev,1 ); + +m_can_enable_all_interrupts (priv); + +return 0 ; +}
Quoted 9 lines
drivers/net/can/m_can/m_can.c static int m_can_poll(struct napi_struct *napi, int quota) · line 791
Quoted 6 lines
drivers/net/can/m_can/m_can.c +6
-0+ +static int m_can_poll (struct napi_struct *napi,int quota) +{ +struct net_device *dev = napi->dev; +struct m_can_priv *priv =netdev_priv (dev); +int work_done =0 ;Is the pre-initialization needed?
No when I copied the function the work_done was pre-initialized.
I can remove it.
Quoted 27 lines
Quoted 27 lines
drivers/net/can/m_can/m_can.c +5
-2+ work_done =m_can_rx_handler (dev, quota);if (work_done < quota) {napi_complete_done (napi, work_done);m_can_enable_all_interrupts (priv); } -end:return work_done; }@@ -902,7 +860,10 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)if ((ir &IR_RF0N ) || (ir &IR_ERR_ALL_30X )) { priv->irqstatus = ir;m_can_disable_all_interrupts (priv); -napi_schedule (&priv->napi); +if (!priv->is_peripherial) +napi_schedule (&priv->napi); +else +m_can_rx_peripherial (dev); }if (priv->version ==30 ) {@@ -924,6 +885,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) } }
Quoted 5 lines
drivers/net/can/m_can/m_can.c static irqreturn_t m_can_isr(int irq, void *dev_id) · line 889
Quoted 2 lines
drivers/net/can/m_can/m_can.c +2
-0+if (priv->ops->clr_dev_interrupts) + priv->ops->clr_dev_interrupts (priv);
post_irq_handler?
I can clear them on entry as well
Quoted 55 lines
Quoted 55 lines
drivers/net/can/m_can/m_can.c +10
-8+return IRQ_HANDLED ; }@@ -1155,6 +1119,9 @@ static void m_can_chip_config(struct net_device *dev)m_can_set_bittiming (dev);m_can_config_endisable (priv, false); + +if (priv->ops->device_init) + priv->ops->device_init (priv); }static void m_can_start (struct net_device *dev)@@ -1188,20 +1155,17 @@ static int m_can_set_mode(struct net_device *dev, enum can_mode mode)* else it returns the release and step coded as: * return value = 10 * <release> + 1 * <step> */ -static int m_can_check_core_release (void __iomem *m_can_base) +static int m_can_check_core_release (struct m_can_priv *priv) {u32 crel_reg;u8 rel;u8 step;int res; -struct m_can_priv temp_priv = { - .base = m_can_base - };/* Read Core Release Version and split into version number * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1; */ - crel_reg =m_can_read (&temp_priv,M_CAN_CREL ); + crel_reg =m_can_read (priv,M_CAN_CREL ); rel = (u8)((crel_reg &CREL_REL_MASK ) >>CREL_REL_SHIFT ); step = (u8)((crel_reg &CREL_STEP_MASK ) >>CREL_STEP_SHIFT );@@ -1219,18 +1183,22 @@ static int m_can_check_core_release(void __iomem *m_can_base)/* Selectable Non ISO support only in version 3.2.x * This function checks if the bit is writable. */ -static bool m_can_niso_supported (const struct m_can_priv *priv) +static bool m_can_niso_supported (struct m_can_priv *priv) { -u32 cccr_reg, cccr_poll; -int niso_timeout; +u32 cccr_reg, cccr_poll =0 ; +int niso_timeout = -ETIMEDOUT ; +int i;m_can_config_endisable (priv, true); cccr_reg =m_can_read (priv,M_CAN_CCCR ); cccr_reg |=CCCR_NISO ;m_can_write (priv,M_CAN_CCCR , cccr_reg);
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_check_core_release(void __iomem *m_can_base) · line 1201
Quoted 7 lines
drivers/net/can/m_can/m_can.c +5
-2- niso_timeout =readl_poll_timeout ((priv->base +M_CAN_CCCR ), cccr_poll, - (cccr_poll == cccr_reg),0 ,10 ); +for (i =0 ; i <=10 ; i++) { + cccr_poll =m_can_read (priv,M_CAN_CCCR ); +if (cccr_poll == cccr_reg) + niso_timeout =0 ; + }There is no break and delay in the loop? What was the reason why you can't use
readl_poll_timeout()?
OK a break if NISO is supported then and probably could add a 1us delay original code on line 1232 had no delay but timeout at 10us.
readl_poll_timeout is for iomapped devices. How would this work for peripherial devices?
Quoted 102 lines
Quoted 102 lines
drivers/net/can/m_can/m_can.c +44
-21/* Clear NISO */ cccr_reg &= ~(CCCR_NISO );@@ -1242,107 +1210,95 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)return !niso_timeout; } -static int m_can_dev_setup (struct platform_device *pdev,struct net_device *dev, -void __iomem *addr) +static int m_can_dev_setup (struct m_can_priv *m_can_dev) { -struct m_can_priv *priv; +struct net_device *dev = m_can_dev->net;int m_can_version; - m_can_version =m_can_check_core_release (addr); + m_can_version =m_can_check_core_release (m_can_dev);/* return if unsupported version */ if (!m_can_version) { -dev_err (&pdev->dev,"Unsupported version number: %2d" , +dev_err (m_can_dev->dev,"Unsupported version number: %2d" , m_can_version);return -EINVAL ; } - priv =netdev_priv (dev); -netif_napi_add (dev, &priv->napi, m_can_poll,M_CAN_NAPI_WEIGHT ); +if (!m_can_dev->is_peripherial) +netif_napi_add (dev, &m_can_dev->napi, + m_can_poll,M_CAN_NAPI_WEIGHT );/* Shared properties of all M_CAN versions */ - priv->version = m_can_version; - priv->dev = dev; - priv->base = addr; - priv->can.do_set_mode = m_can_set_mode; - priv->can.do_get_berr_counter = m_can_get_berr_counter; + m_can_dev->version = m_can_version; + m_can_dev->can.do_set_mode = m_can_set_mode; + m_can_dev->can.do_get_berr_counter = m_can_get_berr_counter;/* Set M_CAN supported operations */ - priv->can.ctrlmode_supported =CAN_CTRLMODE_LOOPBACK | + m_can_dev->can.ctrlmode_supported =CAN_CTRLMODE_LOOPBACK |CAN_CTRLMODE_LISTENONLY |CAN_CTRLMODE_BERR_REPORTING |CAN_CTRLMODE_FD ;/* Set properties depending on M_CAN version */ -switch (priv->version) { +switch (m_can_dev->version) {case 30 :/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */ can_set_static_ctrlmode (dev,CAN_CTRLMODE_FD_NON_ISO ); - priv->can.bittiming_const = &m_can_bittiming_const_30X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_30X; +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const = + m_can_dev->data_timing; +else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;break ;case 31 :/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */ can_set_static_ctrlmode (dev,CAN_CTRLMODE_FD_NON_ISO ); - priv->can.bittiming_const = &m_can_bittiming_const_31X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_31X; +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const = + m_can_dev->data_timing; +else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;break ;case 32 : - priv->can.bittiming_const = &m_can_bittiming_const_31X; - priv->can.data_bittiming_const = +if (m_can_dev->bit_timing) + m_can_dev->can.bittiming_const = m_can_dev->bit_timing; +else + m_can_dev->can.bittiming_const = + &m_can_bittiming_const_31X; + +if (m_can_dev->data_timing) + m_can_dev->can.data_bittiming_const = + m_can_dev->data_timing; +else + m_can_dev->can.data_bittiming_const = &m_can_data_bittiming_const_31X; - priv->can.ctrlmode_supported |= (m_can_niso_supported(priv) +
Quoted 9 lines
drivers/net/can/m_can/m_can.c static bool m_can_niso_supported(const struct m_can_priv *priv) · line 1290
Quoted 4 lines
drivers/net/can/m_can/m_can.c +2
-0+ m_can_dev->can.ctrlmode_supported |= + (m_can_niso_supported (m_can_dev) ?CAN_CTRLMODE_FD_NON_ISO :0 );if (m_can_niso_supported(m_can_dev)) m_can_dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
This would be a change from original source line 1295. Attempted to minimize deltas from original.
Quoted 78 lines
Quoted 78 lines
drivers/net/can/m_can/m_can.c +12
-42break ;default : -dev_err (&pdev->dev,"Unsupported version number: %2d" , - priv->version); +dev_err (m_can_dev->dev,"Unsupported version number: %2d" , + m_can_dev->version);return -EINVAL ; } -return 0 ; -} - -static int m_can_open (struct net_device *dev) -{ -struct m_can_priv *priv =netdev_priv (dev); -int err; - - err =m_can_clk_start (priv); -if (err) -return err; - -/* open the can device */ - err =open_candev (dev); -if (err) { -netdev_err (dev,"failed to open can device\n" ); - goto exit_disable_clks; - } - -/* register interrupt handler */ - err =request_irq (dev->irq, m_can_isr,IRQF_SHARED , dev->name, - dev); -if (err <0 ) { -netdev_err (dev,"failed to request interrupt\n" ); - goto exit_irq_fail; - } - -/* start the m_can controller */ -m_can_start (dev); - -can_led_event (dev,CAN_LED_EVENT_OPEN ); -napi_enable (&priv->napi); -netif_start_queue (dev); +if (m_can_dev->ops->device_init) + m_can_dev->ops->device_init (m_can_dev);return 0 ; - -exit_irq_fail: -close_candev (dev); -exit_disable_clks: -m_can_clk_stop (priv); -return err; }static void m_can_stop (struct net_device *dev)@@ -1361,10 +1317,17 @@ static int m_can_close(struct net_device *dev)struct m_can_priv *priv =netdev_priv (dev);netif_stop_queue (dev); -napi_disable (&priv->napi); +if (!priv->is_peripherial) +napi_disable (&priv->napi);m_can_stop (dev);m_can_clk_stop (priv);free_irq (dev->irq, dev); + +if (priv->is_peripherial) { +destroy_workqueue (priv->wq); + priv->wq =NULL ; + } +close_candev (dev);can_led_event (dev,CAN_LED_EVENT_STOP );@@ -1385,18 +1348,15 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)return !!priv->can.echo_skb[next_idx]; }
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) · line 1355
Quoted 9 lines
drivers/net/can/m_can/m_can.c +4
-4-static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, -struct net_device *dev) +static void m_can_tx_handler (struct m_can_priv *priv) { -struct m_can_priv *priv =netdev_priv (dev); -struct canfd_frame *cf = (struct canfd_frame *)skb->data; +struct canfd_frame *cf = (struct canfd_frame *)priv->skb->data; +struct net_device *dev = priv->net; +struct sk_buff *skb = priv->skb;Maybe "
tx_skb" is a clearer member name..
Again this was named skb to minimize deltas from original code.
skb was passed into the start_xmit function and used throughout the function.
Since there was little delta in this function I opt'd to keep the names as is.
Quoted 47 lines
Quoted 47 lines
drivers/net/can/m_can/m_can.c +21
-7u32 id, cccr, fdflags;int i;int putidx; -if (can_dropped_invalid_skb (dev, skb)) -return NETDEV_TX_OK ; -/* Generate ID field for TX buffer Element */ /* Common to all supported M_CAN versions */ if (cf->can_id &CAN_EFF_FLAG ) {@@ -1451,7 +1411,7 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,netif_stop_queue (dev);netdev_warn (dev,"TX queue active although FIFO is full." ); -return NETDEV_TX_BUSY ; +return ; }/* get put index for frame */ @@ -1492,14 +1452,101 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,m_can_write (priv,M_CAN_TXBAR , (1 << putidx));/* stop network queue if fifo full */ -if (m_can_tx_fifo_full (priv) || -m_can_next_echo_skb_occupied (dev, putidx)) -netif_stop_queue (dev); +if (m_can_tx_fifo_full (priv) || +m_can_next_echo_skb_occupied (dev, putidx)) +netif_stop_queue (dev); + } +} + +static void m_can_tx_work_queue (struct work_struct *ws) +{ + struct m_can_priv *priv = container_of(ws, struct m_can_priv, + tx_work); +m_can_tx_handler (priv); +} + +static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, +struct net_device *dev) +{ +struct m_can_priv *priv =netdev_priv (dev); + + +if (can_dropped_invalid_skb (dev, skb))
Quoted 8 lines
drivers/net/can/m_can/m_can.c static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, · line 1480
Quoted 6 lines
drivers/net/can/m_can/m_can.c +6
-0+return NETDEV_TX_OK ; + + priv->skb = skb; +if (priv->is_peripherial) { +netif_stop_queue (priv->net); +queue_work (priv->wq, &priv->tx_work);s/wq/tx_wq/ ?
This is fine.
Dan
<snip>>>
Quoted 3 lines
Wolfgang
Signature · 2 lines
------------------ Dan Murphy
Re: [PATCH v5 2/5] can: m_can: Migrate the m_can code to use the framework
Hello Dan,
Am 28.02.19 um 18:57 schrieb Dan Murphy:
Quoted 31 lines
Wolfgang
Quoted 15 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 14 lines
Migrate the
m_cancode to use them_can_platformframework code.Signed-off-by Dan Murphy <[email protected]>---
v5 - Updated copyright, change
m_can_classdevtom_can_priv, removed extra KCONFIG flag - https://lore.kernel.org/patchwork/patch/1033095/drivers/net/can/m_can/Kconfig | 8 +- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/m_can.c | 745 ++++++++++++++++----------------- 3 files changed, 367 insertions(+), 387 deletions(-)Quoted 12 lines
drivers/net/can/m_can/Kconfig line 4
Quoted 9 lines
drivers/net/can/m_can/Kconfig +3
-0@@ -1,5 +1,11 @@ config CAN_M_CAN + tristate "Bosch M_CAN support" + ---help--- + Say Y here if you want to support for Bosch M_CAN controller.Typo?
Quoted 1 line
Maybe like you pointed out to update the help.
I was just not sure if it's correct English... but you know better!
Quoted 27 lines
Quoted 11 lines
drivers/net/can/m_can/Kconfig line 11
Quoted 9 lines
drivers/net/can/m_can/Kconfig +4
-1+ +config CAN_M_CAN_PLATFORM + tristate "Bosch M_CAN support for io-mapped devices" depends on HAS_IOMEM - tristate "Bosch M_CAN devices" + depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller.Please update the help.
Ack
Quoted 14 lines
Quoted 14 lines
drivers/net/can/m_can/Makefile +1
-0@@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_M_CAN) += m_can.o +obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.odrivers/net/can/m_can/m_can.c +0
-0
... snip ...
Quoted 11 lines
Quoted 9 lines
drivers/net/can/m_can/m_can.c static irqreturn_t m_can_isr(int irq, void *dev_id) · line 889
Quoted 6 lines
drivers/net/can/m_can/m_can.c +2
-0@@ -924,6 +885,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) } } +if (priv->ops->clr_dev_interrupts) + priv->ops->clr_dev_interrupts (priv);
post_irq_handler?I can clear them on entry as well
OK!
...snip...
Quoted 12 lines
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_check_core_release(void __iomem *m_can_base) · line 1201
Quoted 7 lines
drivers/net/can/m_can/m_can.c +5
-2- niso_timeout =readl_poll_timeout ((priv->base +M_CAN_CCCR ), cccr_poll, - (cccr_poll == cccr_reg),0 ,10 ); +for (i =0 ; i <=10 ; i++) { + cccr_poll =m_can_read (priv,M_CAN_CCCR ); +if (cccr_poll == cccr_reg) + niso_timeout =0 ; + }There is no break and delay in the loop? What was the reason why you can't use
readl_poll_timeout()?
Quoted 4 lines
OK a break if NISO is supported then and probably could add a 1us delay original code on line 1232 had no delay but timeout at 10us.
readl_poll_timeoutis for iomapped devices. How would this work for peripherial devices?
Well, it takes much more time to read the register via SPI... maybe using
if (priv->is_peripherial) ...
to handle the different timings would make sense here.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/net/can/m_can/m_can.c +0
-0/* Clear NISO */ cccr_reg &= ~(CCCR_NISO );@@ -1242,107 +1210,95 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)return !niso_timeout; }
... snip...
Quoted 12 lines
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) · line 1355
Quoted 9 lines
drivers/net/can/m_can/m_can.c +4
-4-static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, -struct net_device *dev) +static void m_can_tx_handler (struct m_can_priv *priv) { -struct m_can_priv *priv =netdev_priv (dev); -struct canfd_frame *cf = (struct canfd_frame *)skb->data; +struct canfd_frame *cf = (struct canfd_frame *)priv->skb->data; +struct net_device *dev = priv->net; +struct sk_buff *skb = priv->skb;Maybe "
tx_skb" is a clearer member name..
Quoted 1 line
Again this was named skb to minimize deltas from original code.
I mean "priv->tx_skb"!
Quoted 4 lines
skb was passed into the
start_xmitfunction and used throughout the function.Since there was little delta in this function I opt'd to keep the names as is.
Wolfgang.
Re: [PATCH v5 2/5] can: m_can: Migrate the m_can code to use the framework
Hello
Quoted 34 lines · Wolfgang Grandegger
Hello Dan,
Am 28.02.19 um 18:57 schrieb Dan Murphy:
Quoted 31 lines
Wolfgang
Quoted 27 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 19 lines
Migrate the
m_cancode to use them_can_platformframework code.Signed-off-by Dan Murphy <[email protected]>---
v5 - Updated copyright, change
m_can_classdevtom_can_priv, removed extra KCONFIG flag - https://lore.kernel.org/patchwork/patch/1033095/drivers/net/can/m_can/Kconfig | 8 +- drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/m_can.c | 745 ++++++++++++++++----------------- 3 files changed, 367 insertions(+), 387 deletions(-)drivers/net/can/m_can/Kconfig +0
-0drivers/net/can/m_can/Kconfig line 4
Quoted 4 lines
drivers/net/can/m_can/Kconfig +3
-0@@ -1,5 +1,11 @@ config CAN_M_CAN + tristate "Bosch M_CAN support" + ---help--- + Say Y here if you want to support for Bosch M_CAN controller.Typo?
Quoted 4 lines
Quoted 1 line
Maybe like you pointed out to update the help.
I was just not sure if it's correct English... but you know better!
I actually added some additional content explaining what the flag was for and remove the "to"
Quoted 59 lines
Quoted 27 lines
Quoted 11 lines
drivers/net/can/m_can/Kconfig line 11
Quoted 9 lines
drivers/net/can/m_can/Kconfig +4
-1+ +config CAN_M_CAN_PLATFORM + tristate "Bosch M_CAN support for io-mapped devices" depends on HAS_IOMEM - tristate "Bosch M_CAN devices" + depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller.Please update the help.
Ack
Quoted 14 lines
Quoted 14 lines
drivers/net/can/m_can/Makefile +1
-0@@ -3,3 +3,4 @@ # obj-$(CONFIG_CAN_M_CAN) += m_can.o +obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.odrivers/net/can/m_can/m_can.c +0
-0... snip ...
Quoted 11 lines
Quoted 9 lines
drivers/net/can/m_can/m_can.c static irqreturn_t m_can_isr(int irq, void *dev_id) · line 889
Quoted 6 lines
drivers/net/can/m_can/m_can.c +2
-0@@ -924,6 +885,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) } } +if (priv->ops->clr_dev_interrupts) + priv->ops->clr_dev_interrupts (priv);
post_irq_handler?I can clear them on entry as well
OK!
...snip...
Quoted 15 lines
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_check_core_release(void __iomem *m_can_base) · line 1201
Quoted 7 lines
drivers/net/can/m_can/m_can.c +5
-2- niso_timeout =readl_poll_timeout ((priv->base +M_CAN_CCCR ), cccr_poll, - (cccr_poll == cccr_reg),0 ,10 ); +for (i =0 ; i <=10 ; i++) { + cccr_poll =m_can_read (priv,M_CAN_CCCR ); +if (cccr_poll == cccr_reg) + niso_timeout =0 ; + }There is no break and delay in the loop? What was the reason why you can't use
readl_poll_timeout()?OK a break if NISO is supported then and probably could add a 1us delay original code on line 1232 had no delay but timeout at 10us.
Quoted 8 lines
Quoted 1 line
readl_poll_timeoutis for iomapped devices. How would this work for peripherial devices?Well, it takes much more time to read the register via SPI... maybe using
if (priv->is_peripherial) ...to handle the different timings would make sense here.
We really should isolate IO access calls away from the framework and have the registrars perform all IO calls.
It may be better to create a call back to check for NISO support but I would think only IO mapped code is the only special case.
Also a call back may be a bit much since this NISO function is only called in setup which is a one and done function during registration.
Quoted 20 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/net/can/m_can/m_can.c +0
-0/* Clear NISO */ cccr_reg &= ~(CCCR_NISO );@@ -1242,107 +1210,95 @@ static bool m_can_niso_supported(const struct m_can_priv *priv)return !niso_timeout; }... snip...
Quoted 12 lines
Quoted 11 lines
drivers/net/can/m_can/m_can.c static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) · line 1355
Quoted 9 lines
drivers/net/can/m_can/m_can.c +4
-4-static netdev_tx_t m_can_start_xmit (struct sk_buff *skb, -struct net_device *dev) +static void m_can_tx_handler (struct m_can_priv *priv) { -struct m_can_priv *priv =netdev_priv (dev); -struct canfd_frame *cf = (struct canfd_frame *)skb->data; +struct canfd_frame *cf = (struct canfd_frame *)priv->skb->data; +struct net_device *dev = priv->net; +struct sk_buff *skb = priv->skb;Maybe "
tx_skb" is a clearer member name..
Quoted 4 lines
Quoted 1 line
Again this was named skb to minimize deltas from original code.
I mean "
priv->tx_skb"!
Ack. Changed for clarity I guess your point was made in my own confusion (heh).
Dan
Quoted 7 lines
Quoted 4 lines
skb was passed into the
start_xmitfunction and used throughout the function.Since there was little delta in this function I opt'd to keep the names as is.
Wolfgang.
Signature · 2 lines
------------------ Dan Murphy
PATCH v5 3/5 can: m_can: Rename m_can_priv to m_can_classdev
In reply to Dan MurphyRename the common m_can_priv class structure tom_can_classdev as this is more descriptive.
---
v5 - New patch per comment in v4 - https://lore.kernel.org/patchwork/patch/1033095/
drivers/net/can/m_can/m_can.c | 95 +++++++++++++------------- drivers/net/can/m_can/m_can.h | 28 ++++---- drivers/net/can/m_can/m_can_platform.c | 16 ++--- 3 files changed, 69 insertions(+), 70 deletions(-)
drivers/net/can/m_can/m_can.c +47 -48
@@ -269,7 +269,7 @@#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) -static u32 m_can_read (struct m_can_priv *priv,enum m_can_reg reg) +static u32 m_can_read (struct m_can_classdev *priv,enum m_can_reg reg) {u32 ret = -EINVAL ;
@@ -279,7 +279,7 @@ static u32 m_can_read(struct m_can_priv *priv, enum m_can_reg reg)return ret; } -static int m_can_write (struct m_can_priv *priv,enum m_can_reg reg,u32 val) +static int m_can_write (struct m_can_classdev *priv,enum m_can_reg reg,u32 val) {int ret = -EINVAL ;
@@ -289,7 +289,7 @@ static int m_can_write(struct m_can_priv *priv, enum m_can_reg reg, u32 val)return ret; } -static u32 m_can_fifo_read (struct m_can_priv *priv, +static u32 m_can_fifo_read (struct m_can_classdev *priv,u32 fgi,unsigned int offset) {u32 addr_offset = priv->mcfg[MRAM_RXF0 ].off + fgi *RXF0_ELEMENT_SIZE + offset;
@@ -301,7 +301,7 @@ static u32 m_can_fifo_read(struct m_can_priv *priv,return ret; } -static u32 m_can_fifo_write (struct m_can_priv *priv, +static u32 m_can_fifo_write (struct m_can_classdev *priv,u32 fpi,unsigned int offset,u32 val) {u32 addr_offset = priv->mcfg[MRAM_TXB ].off + fpi *TXB_ELEMENT_SIZE + offset;
@@ -313,7 +313,7 @@ static u32 m_can_fifo_write(struct m_can_priv *priv,return ret; } -static u32 m_can_fifo_write_no_off (struct m_can_priv *priv, +static u32 m_can_fifo_write_no_off (struct m_can_classdev *priv,u32 fpi,u32 val) {u32 ret =0 ;
@@ -324,7 +324,7 @@ static u32 m_can_fifo_write_no_off(struct m_can_priv *priv,return ret; } -static u32 m_can_txe_fifo_read (struct m_can_priv *priv,u32 fgi,u32 offset) +static u32 m_can_txe_fifo_read (struct m_can_classdev *priv,u32 fgi,u32 offset) {u32 addr_offset = priv->mcfg[MRAM_TXE ].off + fgi *TXE_ELEMENT_SIZE + offset;u32 ret = -EINVAL ;
@@ -335,12 +335,12 @@ static u32 m_can_txe_fifo_read(struct m_can_priv *priv, u32 fgi, u32 offset)return ret; } -static inline bool m_can_tx_fifo_full (struct m_can_priv *priv) +static inline bool m_can_tx_fifo_full (struct m_can_classdev *priv) {return !!(m_can_read (priv,M_CAN_TXFQS ) &TXFQS_TFQF ); } -void m_can_config_endisable (struct m_can_priv *priv,bool enable) +void m_can_config_endisable (struct m_can_classdev *priv,bool enable) {u32 cccr =m_can_read (priv,M_CAN_CCCR );u32 timeout =10 ;
@@ -373,13 +373,13 @@ void m_can_config_endisable(struct m_can_priv *priv, bool enable) } } -static inline void m_can_enable_all_interrupts (struct m_can_priv *priv) +static inline void m_can_enable_all_interrupts (struct m_can_classdev *priv) {/* Only interrupt line 0 is used in this driver */ m_can_write (priv,M_CAN_ILE ,ILE_EINT0 ); } -static inline void m_can_disable_all_interrupts (struct m_can_priv *priv) +static inline void m_can_disable_all_interrupts (struct m_can_classdev *priv) {m_can_write (priv,M_CAN_ILE ,0x0 ); }
@@ -387,7 +387,7 @@ static inline void m_can_disable_all_interrupts(struct m_can_priv *priv)static void m_can_read_fifo (struct net_device *dev,u32 rxfs) {struct net_device_stats *stats = &dev->stats; -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);struct canfd_frame *cf;struct sk_buff *skb;u32 id, fgi, dlc;
@@ -444,7 +444,7 @@ static void m_can_read_fifo(struct net_device *dev, u32 rxfs)static int m_can_do_rx_poll (struct net_device *dev,int quota) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);u32 pkts =0 ;u32 rxfs;
@@ -497,7 +497,7 @@ static int m_can_handle_lost_msg(struct net_device *dev)static int m_can_handle_lec_err (struct net_device *dev,enum m_can_lec_type lec_type) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);struct net_device_stats *stats = &dev->stats;struct can_frame *cf;struct sk_buff *skb;
@@ -554,7 +554,7 @@ static int m_can_handle_lec_err(struct net_device *dev,static int __m_can_get_berr_counter (const struct net_device *dev,struct can_berr_counter *bec) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);unsigned int ecr; ecr =m_can_read (priv,M_CAN_ECR );
@@ -564,7 +564,7 @@ static int __m_can_get_berr_counter(const struct net_device *dev,return 0 ; } -static int m_can_clk_start (struct m_can_priv *priv) +static int m_can_clk_start (struct m_can_classdev *priv) {int err;
@@ -580,7 +580,7 @@ static int m_can_clk_start(struct m_can_priv *priv)return 0 ; } -static void m_can_clk_stop (struct m_can_priv *priv) +static void m_can_clk_stop (struct m_can_classdev *priv) {if (priv->pm_clock_support)pm_runtime_put_sync (priv->dev);
@@ -589,7 +589,7 @@ static void m_can_clk_stop(struct m_can_priv *priv)static int m_can_get_berr_counter (const struct net_device *dev,struct can_berr_counter *bec) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int err; err =m_can_clk_start (priv);
@@ -606,7 +606,7 @@ static int m_can_get_berr_counter(const struct net_device *dev,static int m_can_handle_state_change (struct net_device *dev,enum can_state new_state) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);struct net_device_stats *stats = &dev->stats;struct can_frame *cf;struct sk_buff *skb;
@@ -680,7 +680,7 @@ static int m_can_handle_state_change(struct net_device *dev,static int m_can_handle_state_errors (struct net_device *dev,u32 psr) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int work_done =0 ; if ((psr & PSR_EW) &&
@@ -733,7 +733,7 @@ static inline bool is_lec_err(u32 psr)static int m_can_handle_bus_errors (struct net_device *dev,u32 irqstatus,u32 psr) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int work_done =0 ;if (irqstatus &IR_RF0L )
@@ -752,7 +752,7 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,static int m_can_rx_handler (struct net_device *dev,int quota) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int work_done =0 ;u32 irqstatus, psr;
@@ -775,7 +775,7 @@ static int m_can_rx_handler(struct net_device *dev, int quota)static int m_can_rx_peripherial (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);m_can_rx_handler (dev,1 );
@@ -787,7 +787,7 @@ static int m_can_rx_peripherial(struct net_device *dev)static int m_can_poll (struct napi_struct *napi,int quota) {struct net_device *dev = napi->dev; -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int work_done =0 ; work_done =m_can_rx_handler (dev, quota);
@@ -807,7 +807,7 @@ static void m_can_echo_tx_event(struct net_device *dev)int i =0 ;unsigned int msg_mark; -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);struct net_device_stats *stats = &dev->stats;/* read tx event fifo status */
@@ -840,7 +840,7 @@ static void m_can_echo_tx_event(struct net_device *dev)static irqreturn_t m_can_isr (int irq,void *dev_id) {struct net_device *dev = (struct net_device *)dev_id; -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);struct net_device_stats *stats = &dev->stats;u32 ir;
@@ -941,7 +941,7 @@ static const struct can_bittiming_const m_can_data_bittiming_const_31X = {static int m_can_set_bittiming (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);const struct can_bittiming *bt = &priv->can.bittiming;const struct can_bittiming *dbt = &priv->can.data_bittiming;u16 brp, sjw, tseg1, tseg2;
@@ -1014,7 +1014,7 @@ static int m_can_set_bittiming(struct net_device *dev)*/ static void m_can_chip_config (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);u32 cccr, test;m_can_config_endisable (priv, true);
@@ -1126,7 +1126,7 @@ static void m_can_chip_config(struct net_device *dev)static void m_can_start (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);/* basic m_can configuration */ m_can_chip_config (dev);
@@ -1155,7 +1155,7 @@ static int m_can_set_mode(struct net_device *dev, enum can_mode mode)* else it returns the release and step coded as: * return value = 10 * <release> + 1 * <step> */ -static int m_can_check_core_release (struct m_can_priv *priv) +static int m_can_check_core_release (struct m_can_classdev *priv) {u32 crel_reg;u8 rel;
@@ -1183,7 +1183,7 @@ static int m_can_check_core_release(struct m_can_priv *priv)/* Selectable Non ISO support only in version 3.2.x * This function checks if the bit is writable. */ -static bool m_can_niso_supported (struct m_can_priv *priv) +static bool m_can_niso_supported (struct m_can_classdev *priv) {u32 cccr_reg, cccr_poll =0 ;int niso_timeout = -ETIMEDOUT ;
@@ -1210,7 +1210,7 @@ static bool m_can_niso_supported(struct m_can_priv *priv)return !niso_timeout; } -static int m_can_dev_setup (struct m_can_priv *m_can_dev) +static int m_can_dev_setup (struct m_can_classdev *m_can_dev) {struct net_device *dev = m_can_dev->net;int m_can_version;
@@ -1303,7 +1303,7 @@ static int m_can_dev_setup(struct m_can_priv *m_can_dev)static void m_can_stop (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);/* disable all interrupts */ m_can_disable_all_interrupts (priv);
@@ -1314,7 +1314,7 @@ static void m_can_stop(struct net_device *dev)static int m_can_close (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);netif_stop_queue (dev);if (!priv->is_peripherial)
@@ -1336,7 +1336,7 @@ static int m_can_close(struct net_device *dev)static int m_can_next_echo_skb_occupied (struct net_device *dev,int putidx) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);/*get wrap around for loopback skb index */ unsigned int wrap = priv->can.echo_skb_max;int next_idx;
@@ -1348,7 +1348,7 @@ static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)return !!priv->can.echo_skb[next_idx]; } -static void m_can_tx_handler (struct m_can_priv *priv) +static void m_can_tx_handler (struct m_can_classdev *priv) {struct canfd_frame *cf = (struct canfd_frame *)priv->skb->data;struct net_device *dev = priv->net;
@@ -1460,7 +1460,7 @@ static void m_can_tx_handler(struct m_can_priv *priv)static void m_can_tx_work_queue (struct work_struct *ws) { - struct m_can_priv *priv = container_of(ws, struct m_can_priv, + struct m_can_classdev *priv = container_of(ws, struct m_can_classdev, tx_work);m_can_tx_handler (priv); }
@@ -1468,8 +1468,7 @@ static void m_can_tx_work_queue(struct work_struct *ws)static netdev_tx_t m_can_start_xmit (struct sk_buff *skb,struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); - +struct m_can_classdev *priv =netdev_priv (dev);if (can_dropped_invalid_skb (dev, skb))return NETDEV_TX_OK ;
@@ -1487,7 +1486,7 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,static int m_can_open (struct net_device *dev) { -struct m_can_priv *priv =netdev_priv (dev); +struct m_can_classdev *priv =netdev_priv (dev);int err; err =m_can_clk_start (priv);
@@ -1562,7 +1561,7 @@ static int register_m_can_dev(struct net_device *dev)return register_candev (dev); } -static void m_can_of_parse_mram (struct m_can_priv *priv, +static void m_can_of_parse_mram (struct m_can_classdev *priv,const u32 *mram_config_vals) { priv->mcfg[MRAM_SIDF ].off = mram_config_vals[0 ];
@@ -1600,7 +1599,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); } -void m_can_init_ram (struct m_can_priv *priv) +void m_can_init_ram (struct m_can_classdev *priv) {int end, i, start;
@@ -1616,7 +1615,7 @@ void m_can_init_ram(struct m_can_priv *priv) }EXPORT_SYMBOL_GPL (m_can_init_ram); -int m_can_class_get_clocks (struct m_can_priv *m_can_dev) +int m_can_class_get_clocks (struct m_can_classdev *m_can_dev) {int ret =0 ;
@@ -1632,9 +1631,9 @@ int m_can_class_get_clocks(struct m_can_priv *m_can_dev) }EXPORT_SYMBOL_GPL (m_can_class_get_clocks); -struct m_can_priv *m_can_class_allocate_dev (struct device *dev) +struct m_can_classdev *m_can_class_allocate_dev (struct device *dev) { -struct m_can_priv *class_dev =NULL ; +struct m_can_classdev *class_dev =NULL ;u32 mram_config_vals[MRAM_CFG_LEN ];struct net_device *net_dev;u32 tx_fifo_size;
@@ -1677,7 +1676,7 @@ struct m_can_priv *m_can_class_allocate_dev(struct device *dev) }EXPORT_SYMBOL_GPL (m_can_class_allocate_dev); -int m_can_class_register (struct m_can_priv *m_can_dev) +int m_can_class_register (struct m_can_classdev *m_can_dev) {int ret;
@@ -1725,7 +1724,7 @@ EXPORT_SYMBOL_GPL(m_can_class_register);int m_can_class_suspend (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *priv =netdev_priv (ndev); +struct m_can_classdev *priv =netdev_priv (ndev);if (netif_running (ndev)) {netif_stop_queue (ndev);
@@ -1745,7 +1744,7 @@ EXPORT_SYMBOL_GPL(m_can_class_suspend);int m_can_class_resume (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *priv =netdev_priv (ndev); +struct m_can_classdev *priv =netdev_priv (ndev);pinctrl_pm_select_default_state (dev);
@@ -1768,7 +1767,7 @@ int m_can_class_resume(struct device *dev) }EXPORT_SYMBOL_GPL (m_can_class_resume); -void m_can_class_unregister (struct m_can_priv *m_can_dev) +void m_can_class_unregister (struct m_can_classdev *m_can_dev) {unregister_candev (m_can_dev->net);
drivers/net/can/m_can/m_can.h +14 -14
@@ -107,18 +107,18 @@ struct mram_cfg {u8 num; }; -struct m_can_priv ; +struct m_can_classdev ;struct m_can_ops {/* Device specific call backs */ -int (*clr_dev_interrupts) (struct m_can_priv *m_can_class); -u32 (*read_reg) (struct m_can_priv *m_can_class,int reg); -int (*write_reg) (struct m_can_priv *m_can_class,int reg,int val); -u32 (*read_fifo) (struct m_can_priv *m_can_class,int addr_offset); -int (*write_fifo) (struct m_can_priv *m_can_class,int addr_offset,int val); -int (*device_init) (struct m_can_priv *m_can_class); +int (*clr_dev_interrupts) (struct m_can_classdev *m_can_class); +u32 (*read_reg) (struct m_can_classdev *m_can_class,int reg); +int (*write_reg) (struct m_can_classdev *m_can_class,int reg,int val); +u32 (*read_fifo) (struct m_can_classdev *m_can_class,int addr_offset); +int (*write_fifo) (struct m_can_classdev *m_can_class,int addr_offset,int val); +int (*device_init) (struct m_can_classdev *m_can_class); }; -struct m_can_priv { +struct m_can_classdev {struct can_priv can;struct napi_struct napi;struct net_device *net;
@@ -147,12 +147,12 @@ struct m_can_priv {struct mram_cfg mcfg[MRAM_CFG_NUM ]; }; -struct m_can_priv *m_can_class_allocate_dev (struct device *dev); -int m_can_class_register (struct m_can_priv *m_can_dev); -void m_can_class_unregister (struct m_can_priv *m_can_dev); -int m_can_class_get_clocks (struct m_can_priv *m_can_dev); -void m_can_init_ram (struct m_can_priv *priv); -void m_can_config_endisable (struct m_can_priv *priv,bool enable); +struct m_can_classdev *m_can_class_allocate_dev (struct device *dev); +int m_can_class_register (struct m_can_classdev *m_can_dev); +void m_can_class_unregister (struct m_can_classdev *m_can_dev); +int m_can_class_get_clocks (struct m_can_classdev *m_can_dev); +void m_can_init_ram (struct m_can_classdev *priv); +void m_can_config_endisable (struct m_can_classdev *priv,bool enable);int m_can_class_suspend (struct device *dev);int m_can_class_resume (struct device *dev);
drivers/net/can/m_can/m_can_platform.c +8 -8
@@ -14,21 +14,21 @@ struct m_can_plat_priv {void __iomem *mram_base; }; -static u32 iomap_read_reg (struct m_can_priv *m_can_class,int reg) +static u32 iomap_read_reg (struct m_can_classdev *m_can_class,int reg) {struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data;return readl (priv->base + reg); } -static u32 iomap_read_fifo (struct m_can_priv *m_can_class,int offset) +static u32 iomap_read_fifo (struct m_can_classdev *m_can_class,int offset) {struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data;return readl (priv->mram_base + offset); } -static int iomap_write_reg (struct m_can_priv *m_can_class,int reg,int val) +static int iomap_write_reg (struct m_can_classdev *m_can_class,int reg,int val) {struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data;
@@ -37,7 +37,7 @@ static int iomap_write_reg(struct m_can_priv *m_can_class, int reg, int val)return 0 ; } -static int iomap_write_fifo (struct m_can_priv *m_can_class,int offset,int val) +static int iomap_write_fifo (struct m_can_classdev *m_can_class,int offset,int val) {struct m_can_plat_priv *priv = (struct m_can_plat_priv *)m_can_class->device_data;
@@ -55,7 +55,7 @@ static struct m_can_ops m_can_plat_ops = {static int m_can_plat_probe (struct platform_device *pdev) { -struct m_can_priv *mcan_class; +struct m_can_classdev *mcan_class;struct m_can_plat_priv *priv;struct resource *res;void __iomem *addr;
@@ -127,7 +127,7 @@ static __maybe_unused int m_can_resume(struct device *dev)static int m_can_plat_remove (struct platform_device *pdev) {struct net_device *dev =platform_get_drvdata (pdev); -struct m_can_priv *mcan_class =netdev_priv (dev); +struct m_can_classdev *mcan_class =netdev_priv (dev);m_can_class_unregister (mcan_class);
@@ -139,7 +139,7 @@ static int m_can_plat_remove(struct platform_device *pdev)static int __maybe_unused m_can_runtime_suspend (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *mcan_class =netdev_priv (ndev); +struct m_can_classdev *mcan_class =netdev_priv (ndev);m_can_class_suspend (dev);
@@ -152,7 +152,7 @@ static int __maybe_unused m_can_runtime_suspend(struct device *dev)static int __maybe_unused m_can_runtime_resume (struct device *dev) {struct net_device *ndev =dev_get_drvdata (dev); -struct m_can_priv *mcan_class =netdev_priv (ndev); +struct m_can_classdev *mcan_class =netdev_priv (ndev);int err; err =clk_prepare_enable (mcan_class->hclk);
Signature · 1 line
2.20.1.390.gb5101f9297
PATCH v5 4/5 dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
In reply to Dan MurphyDT binding documentation for TI TCAN4x5x driver.
---
v5 - No changes - https://lore.kernel.org/patchwork/patch/1033097/
.../devicetree/bindings/net/can/tcan4x5x.txt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt
Documentation/devicetree/bindings/net/can/tcan4x5x.txt new file +37 -0
@@ -0,0 +1,37 @@ +Texas Instruments TCAN4x5x CAN Controller +================================================ + +This file provides device node information for the TCAN4x5x interface contains. + +Required properties: + - compatible: "ti,tcan4x5x" + - reg: 0 + - #address-cells: 1 + - #size-cells: 0 + - spi-max-frequency: Maximum frequency of the SPI bus the chip can + operate at should be less than or equal to 18 MHz. + - data-ready-gpios: Interrupt GPIO for data and error reporting. + - device-wake-gpios: Wake up GPIO to wake up the TCAN device. + - device-state-gpios: Input GPIO that indicates if the device is in + a sleep state or if the device is active. + +See Documentation/devicetree/bindings/net/can/m_can.txt for additional +required property details. + +Optional properties: + - reset-gpios: Hardwired output GPIO. If not defined then software + reset. + +Example: +tcan4x5x: tcan4x5x@0 { + compatible = "ti,tcan4x5x"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>; + data-ready-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>; +};
Signature · 1 line
2.20.1.390.gb5101f9297
PATCH v5 5/5 can: tcan4x5x: Add tcan4x5x driver to the kernel
In reply to Dan MurphyAdd the TCAN4x5x SPI CAN driver. This device
uses the Bosch MCAN IP core along with a SPI
interface map. Leverage the MCAN common core
code to manage the MCAN IP.
This device has a special method to indicate a
write/read operation on the data payload.
---
v5 - Changes to accomodate previous patches for functionality - https://lore.kernel.org/patchwork/patch/1033096/
drivers/net/can/m_can/Kconfig | 6 + drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x.c | 531 +++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 drivers/net/can/m_can/tcan4x5x.c
drivers/net/can/m_can/Kconfig +6 -0
@@ -9,3 +9,9 @@ config CAN_M_CAN_PLATFORM depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_TCAN4X5X + depends on CAN_M_CAN + tristate "TCAN4X5X M_CAN device" + ---help--- + Say Y here if you want to support for TI M_CAN controller.
drivers/net/can/m_can/Makefile +1 -0
@@ -4,3 +4,4 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o +obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.o
drivers/net/can/m_can/tcan4x5x.c new file +531 -0
531 lines not on this page · raw message
Signature · 1 line
2.20.1.390.gb5101f9297
Re: [PATCH v5 5/5] can: tcan4x5x: Add tcan4x5x driver to the kernel
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 7 lines
Add the TCAN4x5x SPI CAN driver. This device
uses the Bosch MCAN IP core along with a SPI
interface map. Leverage the MCAN common core
code to manage the MCAN IP.This device has a special method to indicate a
write/read operation on the data payload.
Please expand the text to approx. 72 lines.
Quoted 16 lines
Signed-off-by Dan Murphy <[email protected]>---
v5 - Changes to accomodate previous patches for functionality - https://lore.kernel.org/patchwork/patch/1033096/
drivers/net/can/m_can/Kconfig | 6 + drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x.c | 531 +++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 drivers/net/can/m_can/tcan4x5x.cdrivers/net/can/m_can/Kconfig +0
-0
drivers/net/can/m_can/Kconfig config CAN_M_CAN_PLATFORM · line 17
Quoted 9 lines
drivers/net/can/m_can/Kconfig +6
-0@@ -9,3 +9,9 @@ config CAN_M_CAN_PLATFORM depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_TCAN4X5X + depends on CAN_M_CAN + tristate "TCAN4X5X M_CAN device" + ---help--- + Say Y here if you want to support for TI M_CAN controller.
Could yo please be a bit more verbose here.
Quoted 171 lines
drivers/net/can/m_can/Makefile +1
-0@@ -4,3 +4,4 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o +obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.odrivers/net/can/m_can/tcan4x5x.c new file +156
-0@@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPI to CAN driver for the Texas Instruments TCAN4x5x +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> + +#include "m_can.h" + +#define DEVICE_NAME "tcan4x5x" +#define TCAN4X5X_EXT_CLK_DEF 40000000 + +#define TCAN4X5X_DEV_ID0 0x00 +#define TCAN4X5X_DEV_ID1 0x04 +#define TCAN4X5X_REV 0x08 +#define TCAN4X5X_STATUS 0x0C +#define TCAN4X5X_ERROR_STATUS 0x10 +#define TCAN4X5X_CONTROL 0x14 + +#define TCAN4X5X_CONFIG 0x800 +#define TCAN4X5X_TS_PRESCALE 0x804 +#define TCAN4X5X_TEST_REG 0x808 +#define TCAN4X5X_INT_FLAGS 0x820 +#define TCAN4X5X_MCAN_INT_REG 0x824 +#define TCAN4X5X_INT_EN 0x830 + + +/* Interrupt bits */ +#define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30) +#define TCAN4X5X_CANHCANL_INT_EN BIT(29) +#define TCAN4X5X_CANHBAT_INT_EN BIT(28) +#define TCAN4X5X_CANLGND_INT_EN BIT(27) +#define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26) +#define TCAN4X5X_CANBUSGND_INT_EN BIT(25) +#define TCAN4X5X_CANBUSBAT_INT_EN BIT(24) +#define TCAN4X5X_UVSUP_INT_EN BIT(22) +#define TCAN4X5X_UVIO_INT_EN BIT(21) +#define TCAN4X5X_TSD_INT_EN BIT(19) +#define TCAN4X5X_ECCERR_INT_EN BIT(16) +#define TCAN4X5X_CANINT_INT_EN BIT(15) +#define TCAN4X5X_LWU_INT_EN BIT(14) +#define TCAN4X5X_CANSLNT_INT_EN BIT(10) +#define TCAN4X5X_CANDOM_INT_EN BIT(8) +#define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5) +#define TCAN4X5X_BUS_FAULT BIT(4) +#define TCAN4X5X_MCAN_INT BIT(1) +#define TCAN4X5X_ENABLE_TCAN_INT (TCAN4X5X_MCAN_INT | \ + TCAN4X5X_BUS_FAULT | \ + TCAN4X5X_CANBUS_ERR_INT_EN | \ + TCAN4X5X_CANINT_INT_EN) + +/* MCAN Interrupt bits */ +#define TCAN4X5X_MCAN_IR_ARA BIT(29) +#define TCAN4X5X_MCAN_IR_PED BIT(28) +#define TCAN4X5X_MCAN_IR_PEA BIT(27) +#define TCAN4X5X_MCAN_IR_WD BIT(26) +#define TCAN4X5X_MCAN_IR_BO BIT(25) +#define TCAN4X5X_MCAN_IR_EW BIT(24) +#define TCAN4X5X_MCAN_IR_EP BIT(23) +#define TCAN4X5X_MCAN_IR_ELO BIT(22) +#define TCAN4X5X_MCAN_IR_BEU BIT(21) +#define TCAN4X5X_MCAN_IR_BEC BIT(20) +#define TCAN4X5X_MCAN_IR_DRX BIT(19) +#define TCAN4X5X_MCAN_IR_TOO BIT(18) +#define TCAN4X5X_MCAN_IR_MRAF BIT(17) +#define TCAN4X5X_MCAN_IR_TSW BIT(16) +#define TCAN4X5X_MCAN_IR_TEFL BIT(15) +#define TCAN4X5X_MCAN_IR_TEFF BIT(14) +#define TCAN4X5X_MCAN_IR_TEFW BIT(13) +#define TCAN4X5X_MCAN_IR_TEFN BIT(12) +#define TCAN4X5X_MCAN_IR_TFE BIT(11) +#define TCAN4X5X_MCAN_IR_TCF BIT(10) +#define TCAN4X5X_MCAN_IR_TC BIT(9) +#define TCAN4X5X_MCAN_IR_HPM BIT(8) +#define TCAN4X5X_MCAN_IR_RF1L BIT(7) +#define TCAN4X5X_MCAN_IR_RF1F BIT(6) +#define TCAN4X5X_MCAN_IR_RF1W BIT(5) +#define TCAN4X5X_MCAN_IR_RF1N BIT(4) +#define TCAN4X5X_MCAN_IR_RF0L BIT(3) +#define TCAN4X5X_MCAN_IR_RF0F BIT(2) +#define TCAN4X5X_MCAN_IR_RF0W BIT(1) +#define TCAN4X5X_MCAN_IR_RF0N BIT(0) +#define TCAN4X5X_ENABLE_MCAN_INT (TCAN4X5X_MCAN_IR_TC | \ + TCAN4X5X_MCAN_IR_RF0N | \ + TCAN4X5X_MCAN_IR_RF1N | \ + TCAN4X5X_MCAN_IR_RF0F | \ + TCAN4X5X_MCAN_IR_RF1F) +#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) +#define TCAN4X5X_MODE_NORMAL BIT(7) + +#define TCAN4X5X_SW_RESET BIT(2) + +#define TCAN4X5X_MCAN_CONFIGURED BIT(5) +#define TCAN4X5X_WATCHDOG_EN BIT(3) +#define TCAN4X5X_WD_60_MS_TIMER 0 +#define TCAN4X5X_WD_600_MS_TIMER BIT(28) +#define TCAN4X5X_WD_3_S_TIMER BIT(29) +#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29)) + +struct tcan4x5x_priv { +struct regmap *regmap; +struct spi_device *spi; +struct mutex tcan4x5x_lock;/* SPI device lock */ + +struct m_can_classdev *mcan_dev; + +struct gpio_desc *reset_gpio; +struct gpio_desc *interrupt_gpio; +struct gpio_desc *device_wake_gpio; +struct gpio_desc *device_state_gpio; +struct regulator *power; + +/* Register based ip */ +int mram_start; +int reg_offset; +}; + +static struct can_bittiming_const tcan4x5x_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =2 , + .tseg1_max =31 , + .tseg2_min =2 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static struct can_bittiming_const tcan4x5x_data_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =1 , + .tseg1_max =32 , + .tseg2_min =1 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; +
drivers/net/can/m_can/tcan4x5x.c line 166
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+static void tcan4x5x_check_wake (struct tcan4x5x_priv *priv) +{ +int wake_state =0 ; + +if (priv->device_state_gpio) + wake_state =gpiod_get_value (priv->device_state_gpio); + +if (priv->device_wake_gpio && wake_state) { +gpiod_set_value (priv->device_wake_gpio,1 ); +udelay (100 );
Do you need the setting above?
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+gpiod_set_value (priv->device_wake_gpio,0 ); +udelay (100 ); +gpiod_set_value (priv->device_wake_gpio,1 ); + } +} +
drivers/net/can/m_can/tcan4x5x.c line 182
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+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, },};
struct spi_transfer t[2] = {
{.tx_buf = &addr, .len = reg_len, .cs_change = 0,},
{.tx_buf = val, .len = val_len,},
};Quoted 124 lines
drivers/net/can/m_can/tcan4x5x.c new file +121
-0+ + addr =TCAN4X5X_WRITE_CMD | (*((u16 *)reg) <<8 ) | val_len >>3 ; + +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); +} + +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 *m_can_class,int reg) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->reg_offset + reg, &val); + +return val; +} + +static u32 tcan4x5x_read_fifo (struct m_can_classdev *m_can_class, +int addr_offset) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->mram_start + addr_offset, &val); + +return val; +} + +static int tcan4x5x_write_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->reg_offset + reg, val); +} + +static int tcan4x5x_write_fifo (struct m_can_classdev *m_can_class, +int addr_offset,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->mram_start + addr_offset, val); +} + +static int tcan4x5x_power_enable (struct regulator *reg,int enable) +{ +if (IS_ERR_OR_NULL (reg)) +return 0 ; + +if (enable) +return regulator_enable (reg); +else +return regulator_disable (reg); +} + +static int tcan4x5x_write_tcan_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, reg, val); +} + +static int tcan4x5x_clear_interrupts (struct m_can_classdev *class_dev)
drivers/net/can/m_can/tcan4x5x.c line 313
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ;
Does "ret" not return a proper error code?
Quoted 151 lines
drivers/net/can/m_can/tcan4x5x.c new file +151
-0+ + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_MCAN_INT_REG , +TCAN4X5X_ENABLE_MCAN_INT ); +if (ret) +return -EIO ; + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_INT_FLAGS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_ERROR_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + +return ret; +} + +static int tcan4x5x_init (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_clear_interrupts (class_dev); +if (ret) +return ret; + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_INT_EN , +TCAN4X5X_ENABLE_TCAN_INT ); +if (ret) +return -EIO ; + + ret =regmap_update_bits (tcan4x5x->regmap,TCAN4X5X_CONFIG , +TCAN4X5X_MODE_SEL_MASK ,TCAN4X5X_MODE_NORMAL ); +if (ret) +return -EIO ; + +/* Zero out the MCAN buffers */ +m_can_init_ram (class_dev); + +return ret; +} + +static int tcan4x5x_parse_config (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; + + tcan4x5x->reset_gpio =devm_gpiod_get_optional (class_dev->dev, +"reset" ,GPIOD_OUT_LOW ); +if (IS_ERR (tcan4x5x->reset_gpio)) + tcan4x5x->reset_gpio =NULL ; + + tcan4x5x->device_wake_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-wake" , +GPIOD_OUT_HIGH ); +if (IS_ERR (tcan4x5x->device_wake_gpio)) + tcan4x5x->device_wake_gpio =NULL ; + + tcan4x5x->device_state_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-state" , +GPIOD_IN ); +if (IS_ERR (tcan4x5x->device_state_gpio)) + tcan4x5x->device_state_gpio =NULL ; + + tcan4x5x->interrupt_gpio =devm_gpiod_get (class_dev->dev, +"data-ready" ,GPIOD_IN ); +if (IS_ERR (tcan4x5x->interrupt_gpio)) { +dev_err (class_dev->dev,"data-ready gpio not defined\n" ); +return -EINVAL ; + } + + class_dev->net->irq =gpiod_to_irq (tcan4x5x->interrupt_gpio); + + tcan4x5x->power =devm_regulator_get_optional (class_dev->dev, +"vsup" ); +if (PTR_ERR (tcan4x5x->power) == -EPROBE_DEFER ) +return -EPROBE_DEFER ; + +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 = { + .device_init = tcan4x5x_init, + .read_reg = tcan4x5x_read_reg, + .write_reg = tcan4x5x_write_reg, + .write_fifo = tcan4x5x_write_fifo, + .read_fifo = tcan4x5x_read_fifo, + .clr_dev_interrupts = tcan4x5x_clear_interrupts, +}; + +static int tcan4x5x_can_probe (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv; +struct m_can_classdev *mcan_class; +int freq, ret; + + mcan_class =m_can_class_allocate_dev (&spi->dev); + priv =devm_kzalloc (&spi->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); +if (IS_ERR (mcan_class->cclk)) { +dev_err (&spi->dev,"no CAN clock source defined\n" ); + freq =TCAN4X5X_EXT_CLK_DEF ; + }else { + freq =clk_get_rate (mcan_class->cclk); + } + +/* Sanity check */ +if (freq <20000000 || freq >TCAN4X5X_EXT_CLK_DEF ) +return -ERANGE ; + + priv->reg_offset =TCAN4X5X_MCAN_OFFSET ; + priv->mram_start =TCAN4X5X_MRAM_START ; + priv->spi = spi; + priv->mcan_dev = mcan_class; + + mcan_class->pm_clock_support =0 ; + mcan_class->can.clock.freq = freq; + mcan_class->dev = &spi->dev; + mcan_class->ops = &tcan4x5x_ops; + mcan_class->is_peripherial = true; + mcan_class->bit_timing = &tcan4x5x_bittiming_const; + mcan_class->data_timing = &tcan4x5x_data_bittiming_const; + +spi_set_drvdata (spi, priv); + + ret =tcan4x5x_parse_config (mcan_class); +if (ret) + goto out_clk; + +/* Configure the SPI bus */ + spi->bits_per_word =32 ; + ret =spi_setup (spi); +if (ret) + goto out_clk; +
drivers/net/can/m_can/tcan4x5x.c line 474
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ priv->regmap =devm_regmap_init (&spi->dev, &tcan4x5x_bus, + &spi->dev, &tcan4x5x_regmap); + +mutex_init (&priv->tcan4x5x_lock); + +tcan4x5x_power_enable (priv->power,1 ); + + ret =m_can_class_register (mcan_class); +if (ret) + goto reg_err;
out_power?
drivers/net/can/m_can/tcan4x5x.c line 487
Quoted 13 lines
drivers/net/can/m_can/tcan4x5x.c new file +13
-0+ +netdev_info (mcan_class->net,"TCAN4X5X successfully initialized.\n" ); +return 0 ; + +reg_err: +tcan4x5x_power_enable (priv->power,0 ); +out_clk: +if (!IS_ERR (mcan_class->cclk)) { +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + } + +dev_err (&spi->dev,"Probe failed, err=%d\n" , -ret);
Just "ret" is fine!
Quoted 35 lines
drivers/net/can/m_can/tcan4x5x.c new file +34
-0+return ret; +} + +static int tcan4x5x_can_remove (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv =spi_get_drvdata (spi); + +tcan4x5x_power_enable (priv->power,0 ); + +m_can_class_unregister (priv->mcan_dev); + +return 0 ; +} + +static const struct of_device_id tcan4x5x_of_match[] = { + { .compatible ="ti,tcan4x5x" , }, + { } +}; +MODULE_DEVICE_TABLE (of, tcan4x5x_of_match); + +static const struct spi_device_id tcan4x5x_id_table[] = { + { + .name ="tcan4x5x" , + .driver_data =0 , + }, + { } +}; +MODULE_DEVICE_TABLE (spi, tcan4x5x_id_table); + +static struct spi_driver tcan4x5x_can_driver = { + .driver = { + .name =DEVICE_NAME , + .of_match_table = tcan4x5x_of_match, + .pm =NULL ,
drivers/net/can/m_can/tcan4x5x.c line 531
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ }, + .id_table = tcan4x5x_id_table, + .probe = tcan4x5x_can_probe, + .remove = tcan4x5x_can_remove, +}; +module_spi_driver (tcan4x5x_can_driver); + +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_DESCRIPTION ("Texas Instruments TCAN4x5x CAN driver" ); +MODULE_LICENSE ("GPL v2" );
The changes to the io-mapped driver look good and non-critical... time to ask for beta-testers for the next version of the patch series.
Wolfgang.
Re: [PATCH v5 5/5] can: tcan4x5x: Add tcan4x5x driver to the kernel
Wolfgang
Quoted 8 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 5 lines
Add the TCAN4x5x SPI CAN driver. This device
uses the Bosch MCAN IP core along with a SPI
interface map. Leverage the MCAN common core
code to manage the MCAN IP.
Quoted 5 lines
Quoted 2 lines
This device has a special method to indicate a
write/read operation on the data payload.Please expand the text to approx. 72 lines.
72 lines or characters?
Quoted 11 lines
Quoted 11 lines
Signed-off-by Dan Murphy <[email protected]>---
v5 - Changes to accomodate previous patches for functionality - https://lore.kernel.org/patchwork/patch/1033096/
drivers/net/can/m_can/Kconfig | 6 + drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x.c | 531 +++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Quoted 16 lines
Quoted 5 lines
drivers/net/can/m_can/Kconfig +0
-0drivers/net/can/m_can/Kconfig config CAN_M_CAN_PLATFORM · line 17
Quoted 9 lines
drivers/net/can/m_can/Kconfig +6
-0@@ -9,3 +9,9 @@ config CAN_M_CAN_PLATFORM depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_TCAN4X5X + depends on CAN_M_CAN + tristate "TCAN4X5X M_CAN device" + ---help--- + Say Y here if you want to support for TI M_CAN controller.Could yo please be a bit more verbose here.
ACK
Quoted 176 lines
Quoted 176 lines
drivers/net/can/m_can/Makefile +1
-0@@ -4,3 +4,4 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o +obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.odrivers/net/can/m_can/tcan4x5x.c new file +160
-0@@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPI to CAN driver for the Texas Instruments TCAN4x5x +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> + +#include "m_can.h" + +#define DEVICE_NAME "tcan4x5x" +#define TCAN4X5X_EXT_CLK_DEF 40000000 + +#define TCAN4X5X_DEV_ID0 0x00 +#define TCAN4X5X_DEV_ID1 0x04 +#define TCAN4X5X_REV 0x08 +#define TCAN4X5X_STATUS 0x0C +#define TCAN4X5X_ERROR_STATUS 0x10 +#define TCAN4X5X_CONTROL 0x14 + +#define TCAN4X5X_CONFIG 0x800 +#define TCAN4X5X_TS_PRESCALE 0x804 +#define TCAN4X5X_TEST_REG 0x808 +#define TCAN4X5X_INT_FLAGS 0x820 +#define TCAN4X5X_MCAN_INT_REG 0x824 +#define TCAN4X5X_INT_EN 0x830 + + +/* Interrupt bits */ +#define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30) +#define TCAN4X5X_CANHCANL_INT_EN BIT(29) +#define TCAN4X5X_CANHBAT_INT_EN BIT(28) +#define TCAN4X5X_CANLGND_INT_EN BIT(27) +#define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26) +#define TCAN4X5X_CANBUSGND_INT_EN BIT(25) +#define TCAN4X5X_CANBUSBAT_INT_EN BIT(24) +#define TCAN4X5X_UVSUP_INT_EN BIT(22) +#define TCAN4X5X_UVIO_INT_EN BIT(21) +#define TCAN4X5X_TSD_INT_EN BIT(19) +#define TCAN4X5X_ECCERR_INT_EN BIT(16) +#define TCAN4X5X_CANINT_INT_EN BIT(15) +#define TCAN4X5X_LWU_INT_EN BIT(14) +#define TCAN4X5X_CANSLNT_INT_EN BIT(10) +#define TCAN4X5X_CANDOM_INT_EN BIT(8) +#define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5) +#define TCAN4X5X_BUS_FAULT BIT(4) +#define TCAN4X5X_MCAN_INT BIT(1) +#define TCAN4X5X_ENABLE_TCAN_INT (TCAN4X5X_MCAN_INT | \ + TCAN4X5X_BUS_FAULT | \ + TCAN4X5X_CANBUS_ERR_INT_EN | \ + TCAN4X5X_CANINT_INT_EN) + +/* MCAN Interrupt bits */ +#define TCAN4X5X_MCAN_IR_ARA BIT(29) +#define TCAN4X5X_MCAN_IR_PED BIT(28) +#define TCAN4X5X_MCAN_IR_PEA BIT(27) +#define TCAN4X5X_MCAN_IR_WD BIT(26) +#define TCAN4X5X_MCAN_IR_BO BIT(25) +#define TCAN4X5X_MCAN_IR_EW BIT(24) +#define TCAN4X5X_MCAN_IR_EP BIT(23) +#define TCAN4X5X_MCAN_IR_ELO BIT(22) +#define TCAN4X5X_MCAN_IR_BEU BIT(21) +#define TCAN4X5X_MCAN_IR_BEC BIT(20) +#define TCAN4X5X_MCAN_IR_DRX BIT(19) +#define TCAN4X5X_MCAN_IR_TOO BIT(18) +#define TCAN4X5X_MCAN_IR_MRAF BIT(17) +#define TCAN4X5X_MCAN_IR_TSW BIT(16) +#define TCAN4X5X_MCAN_IR_TEFL BIT(15) +#define TCAN4X5X_MCAN_IR_TEFF BIT(14) +#define TCAN4X5X_MCAN_IR_TEFW BIT(13) +#define TCAN4X5X_MCAN_IR_TEFN BIT(12) +#define TCAN4X5X_MCAN_IR_TFE BIT(11) +#define TCAN4X5X_MCAN_IR_TCF BIT(10) +#define TCAN4X5X_MCAN_IR_TC BIT(9) +#define TCAN4X5X_MCAN_IR_HPM BIT(8) +#define TCAN4X5X_MCAN_IR_RF1L BIT(7) +#define TCAN4X5X_MCAN_IR_RF1F BIT(6) +#define TCAN4X5X_MCAN_IR_RF1W BIT(5) +#define TCAN4X5X_MCAN_IR_RF1N BIT(4) +#define TCAN4X5X_MCAN_IR_RF0L BIT(3) +#define TCAN4X5X_MCAN_IR_RF0F BIT(2) +#define TCAN4X5X_MCAN_IR_RF0W BIT(1) +#define TCAN4X5X_MCAN_IR_RF0N BIT(0) +#define TCAN4X5X_ENABLE_MCAN_INT (TCAN4X5X_MCAN_IR_TC | \ + TCAN4X5X_MCAN_IR_RF0N | \ + TCAN4X5X_MCAN_IR_RF1N | \ + TCAN4X5X_MCAN_IR_RF0F | \ + TCAN4X5X_MCAN_IR_RF1F) +#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) +#define TCAN4X5X_MODE_NORMAL BIT(7) + +#define TCAN4X5X_SW_RESET BIT(2) + +#define TCAN4X5X_MCAN_CONFIGURED BIT(5) +#define TCAN4X5X_WATCHDOG_EN BIT(3) +#define TCAN4X5X_WD_60_MS_TIMER 0 +#define TCAN4X5X_WD_600_MS_TIMER BIT(28) +#define TCAN4X5X_WD_3_S_TIMER BIT(29) +#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29)) + +struct tcan4x5x_priv { +struct regmap *regmap; +struct spi_device *spi; +struct mutex tcan4x5x_lock;/* SPI device lock */ + +struct m_can_classdev *mcan_dev; + +struct gpio_desc *reset_gpio; +struct gpio_desc *interrupt_gpio; +struct gpio_desc *device_wake_gpio; +struct gpio_desc *device_state_gpio; +struct regulator *power; + +/* Register based ip */ +int mram_start; +int reg_offset; +}; + +static struct can_bittiming_const tcan4x5x_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =2 , + .tseg1_max =31 , + .tseg2_min =2 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static struct can_bittiming_const tcan4x5x_data_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =1 , + .tseg1_max =32 , + .tseg2_min =1 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static void tcan4x5x_check_wake (struct tcan4x5x_priv *priv) +{ +int wake_state =0 ; +
Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 166
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+if (priv->device_state_gpio) + wake_state =gpiod_get_value (priv->device_state_gpio); + +if (priv->device_wake_gpio && wake_state) { +gpiod_set_value (priv->device_wake_gpio,1 ); +udelay (100 );Do you need the setting above?
Do you mean do I need to set the reset line then delay?
Quoted 13 lines
Quoted 13 lines
drivers/net/can/m_can/tcan4x5x.c new file +13
-0+gpiod_set_value (priv->device_wake_gpio,0 ); +udelay (100 ); +gpiod_set_value (priv->device_wake_gpio,1 ); + } +} + +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;
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c line 182
Quoted 3 lines
drivers/net/can/m_can/tcan4x5x.c new file +3
-0+u32 addr; +struct spi_transfer t[2 ] = {{ .tx_buf = &addr, .len = reg_len, .cs_change =0 ,}, + { .tx_buf = val, .len = val_len, },};struct spi_transfer t[2] = { {.tx_buf = &addr, .len = reg_len, .cs_change = 0,}, {.tx_buf = val, .len = val_len,}, };
I am assuming LTL issue here.
Quoted 4 lines
drivers/net/can/m_can/tcan4x5x.c line 184
Quoted 2 lines
drivers/net/can/m_can/tcan4x5x.c new file +2
-0+ + addr =TCAN4X5X_WRITE_CMD | (*((u16 *)reg) <<8 ) | val_len >>3 ;
There is nothing here
Quoted 124 lines
Quoted 124 lines
drivers/net/can/m_can/tcan4x5x.c new file +123
-0+ +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); +} + +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 *m_can_class,int reg) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->reg_offset + reg, &val); + +return val; +} + +static u32 tcan4x5x_read_fifo (struct m_can_classdev *m_can_class, +int addr_offset) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->mram_start + addr_offset, &val); + +return val; +} + +static int tcan4x5x_write_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->reg_offset + reg, val); +} + +static int tcan4x5x_write_fifo (struct m_can_classdev *m_can_class, +int addr_offset,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->mram_start + addr_offset, val); +} + +static int tcan4x5x_power_enable (struct regulator *reg,int enable) +{ +if (IS_ERR_OR_NULL (reg)) +return 0 ; + +if (enable) +return regulator_enable (reg); +else +return regulator_disable (reg); +} + +static int tcan4x5x_write_tcan_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, reg, val); +} + +static int tcan4x5x_clear_interrupts (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; +
Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c line 313
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ;Does "ret" not return a proper error code?
I can change it to ret.
Quoted 33 lines
Quoted 33 lines
drivers/net/can/m_can/tcan4x5x.c new file +32
-0+ + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_MCAN_INT_REG , +TCAN4X5X_ENABLE_MCAN_INT ); +if (ret) +return -EIO ; + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_INT_FLAGS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_ERROR_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + +return ret; +} + +static int tcan4x5x_init (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_clear_interrupts (class_dev); +if (ret) +return ret; + + ret = tcan4x5x_write_tcan_reg(class_dev, TCAN4X5X_INT_EN,
Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c line 353
Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c new file +8
-0+ TCAN4X5X_ENABLE_TCAN_INT); +if (ret) +return -EIO ; + + ret =regmap_update_bits (tcan4x5x->regmap,TCAN4X5X_CONFIG , +TCAN4X5X_MODE_SEL_MASK ,TCAN4X5X_MODE_NORMAL ); +if (ret) +return -EIO ;
Same comment as above
Quoted 115 lines
Quoted 115 lines
drivers/net/can/m_can/tcan4x5x.c new file +115
-0+ +/* Zero out the MCAN buffers */ +m_can_init_ram (class_dev); + +return ret; +} + +static int tcan4x5x_parse_config (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; + + tcan4x5x->reset_gpio =devm_gpiod_get_optional (class_dev->dev, +"reset" ,GPIOD_OUT_LOW ); +if (IS_ERR (tcan4x5x->reset_gpio)) + tcan4x5x->reset_gpio =NULL ; + + tcan4x5x->device_wake_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-wake" , +GPIOD_OUT_HIGH ); +if (IS_ERR (tcan4x5x->device_wake_gpio)) + tcan4x5x->device_wake_gpio =NULL ; + + tcan4x5x->device_state_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-state" , +GPIOD_IN ); +if (IS_ERR (tcan4x5x->device_state_gpio)) + tcan4x5x->device_state_gpio =NULL ; + + tcan4x5x->interrupt_gpio =devm_gpiod_get (class_dev->dev, +"data-ready" ,GPIOD_IN ); +if (IS_ERR (tcan4x5x->interrupt_gpio)) { +dev_err (class_dev->dev,"data-ready gpio not defined\n" ); +return -EINVAL ; + } + + class_dev->net->irq =gpiod_to_irq (tcan4x5x->interrupt_gpio); + + tcan4x5x->power =devm_regulator_get_optional (class_dev->dev, +"vsup" ); +if (PTR_ERR (tcan4x5x->power) == -EPROBE_DEFER ) +return -EPROBE_DEFER ; + +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 = { + .device_init = tcan4x5x_init, + .read_reg = tcan4x5x_read_reg, + .write_reg = tcan4x5x_write_reg, + .write_fifo = tcan4x5x_write_fifo, + .read_fifo = tcan4x5x_read_fifo, + .clr_dev_interrupts = tcan4x5x_clear_interrupts, +}; + +static int tcan4x5x_can_probe (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv; +struct m_can_classdev *mcan_class; +int freq, ret; + + mcan_class =m_can_class_allocate_dev (&spi->dev); + priv =devm_kzalloc (&spi->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); +if (IS_ERR (mcan_class->cclk)) { +dev_err (&spi->dev,"no CAN clock source defined\n" ); + freq =TCAN4X5X_EXT_CLK_DEF ; + }else { + freq =clk_get_rate (mcan_class->cclk); + } + +/* Sanity check */ +if (freq <20000000 || freq >TCAN4X5X_EXT_CLK_DEF ) +return -ERANGE ; + + priv->reg_offset =TCAN4X5X_MCAN_OFFSET ; + priv->mram_start =TCAN4X5X_MRAM_START ; + priv->spi = spi; + priv->mcan_dev = mcan_class; + + mcan_class->pm_clock_support =0 ; + mcan_class->can.clock.freq = freq; + mcan_class->dev = &spi->dev; + mcan_class->ops = &tcan4x5x_ops; + mcan_class->is_peripherial = true; + mcan_class->bit_timing = &tcan4x5x_bittiming_const; + mcan_class->data_timing = &tcan4x5x_data_bittiming_const; + +spi_set_drvdata (spi, priv); + + ret =tcan4x5x_parse_config (mcan_class); +if (ret) + goto out_clk; + +/* Configure the SPI bus */ + spi->bits_per_word =32 ; + ret =spi_setup (spi); +if (ret) + goto out_clk; + + priv->regmap =devm_regmap_init (&spi->dev, &tcan4x5x_bus, + &spi->dev, &tcan4x5x_regmap); + +mutex_init (&priv->tcan4x5x_lock);
Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 474
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+ +tcan4x5x_power_enable (priv->power,1 ); + + ret =m_can_class_register (mcan_class); +if (ret) + goto reg_err;
out_power?
Not sure what you are asking?
Quoted 7 lines
Quoted 7 lines
drivers/net/can/m_can/tcan4x5x.c new file +7
-0+ +netdev_info (mcan_class->net,"TCAN4X5X successfully initialized.\n" ); +return 0 ; + +reg_err: +tcan4x5x_power_enable (priv->power,0 ); +out_clk:
Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 487
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+if (!IS_ERR (mcan_class->cclk)) { +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + } + +dev_err (&spi->dev,"Probe failed, err=%d\n" , -ret);Just "ret" is fine!
Ack
Quoted 40 lines
Quoted 40 lines
drivers/net/can/m_can/tcan4x5x.c new file +40
-0+return ret; +} + +static int tcan4x5x_can_remove (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv =spi_get_drvdata (spi); + +tcan4x5x_power_enable (priv->power,0 ); + +m_can_class_unregister (priv->mcan_dev); + +return 0 ; +} + +static const struct of_device_id tcan4x5x_of_match[] = { + { .compatible ="ti,tcan4x5x" , }, + { } +}; +MODULE_DEVICE_TABLE (of, tcan4x5x_of_match); + +static const struct spi_device_id tcan4x5x_id_table[] = { + { + .name ="tcan4x5x" , + .driver_data =0 , + }, + { } +}; +MODULE_DEVICE_TABLE (spi, tcan4x5x_id_table); + +static struct spi_driver tcan4x5x_can_driver = { + .driver = { + .name =DEVICE_NAME , + .of_match_table = tcan4x5x_of_match, + .pm =NULL , + }, + .id_table = tcan4x5x_id_table, + .probe = tcan4x5x_can_probe, + .remove = tcan4x5x_can_remove, +}; +module_spi_driver (tcan4x5x_can_driver);
Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 531
Quoted 5 lines
drivers/net/can/m_can/tcan4x5x.c new file +4
-0+ +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_DESCRIPTION ("Texas Instruments TCAN4x5x CAN driver" ); +MODULE_LICENSE ("GPL v2" );The changes to the io-mapped driver look good and non-critical... time to ask for beta-testers for the next version of the patch series.
OK. I also tested this here on one of our boards that use the iomapped code.
Quoted 2 lines
Wolfgang.
Signature · 2 lines
------------------ Dan Murphy
Re: [PATCH v5 5/5] can: tcan4x5x: Add tcan4x5x driver to the kernel
Am 28.02.19 um 19:03 schrieb Dan Murphy:
Quoted 12 lines
Wolfgang
Quoted 8 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 5 lines
Add the TCAN4x5x SPI CAN driver. This device
uses the Bosch MCAN IP core along with a SPI
interface map. Leverage the MCAN common core
code to manage the MCAN IP.
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
This device has a special method to indicate a
write/read operation on the data payload.Please expand the text to approx. 72 lines.>>
72 lines or characters?
Characters, of course!
Quoted 216 lines
Quoted 11 lines
Quoted 11 lines
Signed-off-by Dan Murphy <[email protected]>---
v5 - Changes to accomodate previous patches for functionality - https://lore.kernel.org/patchwork/patch/1033096/
drivers/net/can/m_can/Kconfig | 6 + drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x.c | 531 +++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 drivers/net/can/m_can/tcan4x5x.cQuoted 16 lines
Quoted 5 lines
drivers/net/can/m_can/Kconfig +0
-0drivers/net/can/m_can/Kconfig config CAN_M_CAN_PLATFORM · line 17
Quoted 9 lines
drivers/net/can/m_can/Kconfig +6
-0@@ -9,3 +9,9 @@ config CAN_M_CAN_PLATFORM depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_TCAN4X5X + depends on CAN_M_CAN + tristate "TCAN4X5X M_CAN device" + ---help--- + Say Y here if you want to support for TI M_CAN controller.Could yo please be a bit more verbose here.
ACK
Quoted 176 lines
Quoted 176 lines
drivers/net/can/m_can/Makefile +1
-0@@ -4,3 +4,4 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o +obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.odrivers/net/can/m_can/tcan4x5x.c new file +160
-0@@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPI to CAN driver for the Texas Instruments TCAN4x5x +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> + +#include "m_can.h" + +#define DEVICE_NAME "tcan4x5x" +#define TCAN4X5X_EXT_CLK_DEF 40000000 + +#define TCAN4X5X_DEV_ID0 0x00 +#define TCAN4X5X_DEV_ID1 0x04 +#define TCAN4X5X_REV 0x08 +#define TCAN4X5X_STATUS 0x0C +#define TCAN4X5X_ERROR_STATUS 0x10 +#define TCAN4X5X_CONTROL 0x14 + +#define TCAN4X5X_CONFIG 0x800 +#define TCAN4X5X_TS_PRESCALE 0x804 +#define TCAN4X5X_TEST_REG 0x808 +#define TCAN4X5X_INT_FLAGS 0x820 +#define TCAN4X5X_MCAN_INT_REG 0x824 +#define TCAN4X5X_INT_EN 0x830 + + +/* Interrupt bits */ +#define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30) +#define TCAN4X5X_CANHCANL_INT_EN BIT(29) +#define TCAN4X5X_CANHBAT_INT_EN BIT(28) +#define TCAN4X5X_CANLGND_INT_EN BIT(27) +#define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26) +#define TCAN4X5X_CANBUSGND_INT_EN BIT(25) +#define TCAN4X5X_CANBUSBAT_INT_EN BIT(24) +#define TCAN4X5X_UVSUP_INT_EN BIT(22) +#define TCAN4X5X_UVIO_INT_EN BIT(21) +#define TCAN4X5X_TSD_INT_EN BIT(19) +#define TCAN4X5X_ECCERR_INT_EN BIT(16) +#define TCAN4X5X_CANINT_INT_EN BIT(15) +#define TCAN4X5X_LWU_INT_EN BIT(14) +#define TCAN4X5X_CANSLNT_INT_EN BIT(10) +#define TCAN4X5X_CANDOM_INT_EN BIT(8) +#define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5) +#define TCAN4X5X_BUS_FAULT BIT(4) +#define TCAN4X5X_MCAN_INT BIT(1) +#define TCAN4X5X_ENABLE_TCAN_INT (TCAN4X5X_MCAN_INT | \ + TCAN4X5X_BUS_FAULT | \ + TCAN4X5X_CANBUS_ERR_INT_EN | \ + TCAN4X5X_CANINT_INT_EN) + +/* MCAN Interrupt bits */ +#define TCAN4X5X_MCAN_IR_ARA BIT(29) +#define TCAN4X5X_MCAN_IR_PED BIT(28) +#define TCAN4X5X_MCAN_IR_PEA BIT(27) +#define TCAN4X5X_MCAN_IR_WD BIT(26) +#define TCAN4X5X_MCAN_IR_BO BIT(25) +#define TCAN4X5X_MCAN_IR_EW BIT(24) +#define TCAN4X5X_MCAN_IR_EP BIT(23) +#define TCAN4X5X_MCAN_IR_ELO BIT(22) +#define TCAN4X5X_MCAN_IR_BEU BIT(21) +#define TCAN4X5X_MCAN_IR_BEC BIT(20) +#define TCAN4X5X_MCAN_IR_DRX BIT(19) +#define TCAN4X5X_MCAN_IR_TOO BIT(18) +#define TCAN4X5X_MCAN_IR_MRAF BIT(17) +#define TCAN4X5X_MCAN_IR_TSW BIT(16) +#define TCAN4X5X_MCAN_IR_TEFL BIT(15) +#define TCAN4X5X_MCAN_IR_TEFF BIT(14) +#define TCAN4X5X_MCAN_IR_TEFW BIT(13) +#define TCAN4X5X_MCAN_IR_TEFN BIT(12) +#define TCAN4X5X_MCAN_IR_TFE BIT(11) +#define TCAN4X5X_MCAN_IR_TCF BIT(10) +#define TCAN4X5X_MCAN_IR_TC BIT(9) +#define TCAN4X5X_MCAN_IR_HPM BIT(8) +#define TCAN4X5X_MCAN_IR_RF1L BIT(7) +#define TCAN4X5X_MCAN_IR_RF1F BIT(6) +#define TCAN4X5X_MCAN_IR_RF1W BIT(5) +#define TCAN4X5X_MCAN_IR_RF1N BIT(4) +#define TCAN4X5X_MCAN_IR_RF0L BIT(3) +#define TCAN4X5X_MCAN_IR_RF0F BIT(2) +#define TCAN4X5X_MCAN_IR_RF0W BIT(1) +#define TCAN4X5X_MCAN_IR_RF0N BIT(0) +#define TCAN4X5X_ENABLE_MCAN_INT (TCAN4X5X_MCAN_IR_TC | \ + TCAN4X5X_MCAN_IR_RF0N | \ + TCAN4X5X_MCAN_IR_RF1N | \ + TCAN4X5X_MCAN_IR_RF0F | \ + TCAN4X5X_MCAN_IR_RF1F) +#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) +#define TCAN4X5X_MODE_NORMAL BIT(7) + +#define TCAN4X5X_SW_RESET BIT(2) + +#define TCAN4X5X_MCAN_CONFIGURED BIT(5) +#define TCAN4X5X_WATCHDOG_EN BIT(3) +#define TCAN4X5X_WD_60_MS_TIMER 0 +#define TCAN4X5X_WD_600_MS_TIMER BIT(28) +#define TCAN4X5X_WD_3_S_TIMER BIT(29) +#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29)) + +struct tcan4x5x_priv { +struct regmap *regmap; +struct spi_device *spi; +struct mutex tcan4x5x_lock;/* SPI device lock */ + +struct m_can_classdev *mcan_dev; + +struct gpio_desc *reset_gpio; +struct gpio_desc *interrupt_gpio; +struct gpio_desc *device_wake_gpio; +struct gpio_desc *device_state_gpio; +struct regulator *power; + +/* Register based ip */ +int mram_start; +int reg_offset; +}; + +static struct can_bittiming_const tcan4x5x_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =2 , + .tseg1_max =31 , + .tseg2_min =2 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static struct can_bittiming_const tcan4x5x_data_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =1 , + .tseg1_max =32 , + .tseg2_min =1 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static void tcan4x5x_check_wake (struct tcan4x5x_priv *priv) +{ +int wake_state =0 ; +Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 166
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+if (priv->device_state_gpio) + wake_state =gpiod_get_value (priv->device_state_gpio); + +if (priv->device_wake_gpio && wake_state) { +gpiod_set_value (priv->device_wake_gpio,1 ); +udelay (100 );Do you need the setting above?
Quoted 1 line
Do you mean do I need to set the reset line then delay?
I mean, do you need to set the gpio value to 1 at the beginning? Is 0->1 not enough?
Quoted 25 lines
Quoted 14 lines
Quoted 14 lines
drivers/net/can/m_can/tcan4x5x.c new file +13
-0+gpiod_set_value (priv->device_wake_gpio,0 ); +udelay (100 ); +gpiod_set_value (priv->device_wake_gpio,1 ); + } +} + +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;Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c line 182
Quoted 3 lines
drivers/net/can/m_can/tcan4x5x.c new file +3
-0+u32 addr; +struct spi_transfer t[2 ] = {{ .tx_buf = &addr, .len = reg_len, .cs_change =0 ,}, + { .tx_buf = val, .len = val_len, },};struct spi_transfer t[2] = { {.tx_buf = &addr, .len = reg_len, .cs_change = 0,}, {.tx_buf = val, .len = val_len,}, };
Quoted 1 line
I am assuming LTL issue here.
LTL means? I just reformatted the declaration.
Quoted 7 lines
Quoted 5 lines
drivers/net/can/m_can/tcan4x5x.c line 184
Quoted 3 lines
drivers/net/can/m_can/tcan4x5x.c new file +2
-0+ + addr =TCAN4X5X_WRITE_CMD | (*((u16 *)reg) <<8 ) | val_len >>3 ;There is nothing here
It's OK.
Quoted 134 lines
Quoted 125 lines
Quoted 125 lines
drivers/net/can/m_can/tcan4x5x.c new file +123
-0+ +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); +} + +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 *m_can_class,int reg) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->reg_offset + reg, &val); + +return val; +} + +static u32 tcan4x5x_read_fifo (struct m_can_classdev *m_can_class, +int addr_offset) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->mram_start + addr_offset, &val); + +return val; +} + +static int tcan4x5x_write_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->reg_offset + reg, val); +} + +static int tcan4x5x_write_fifo (struct m_can_classdev *m_can_class, +int addr_offset,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->mram_start + addr_offset, val); +} + +static int tcan4x5x_power_enable (struct regulator *reg,int enable) +{ +if (IS_ERR_OR_NULL (reg)) +return 0 ; + +if (enable) +return regulator_enable (reg); +else +return regulator_disable (reg); +} + +static int tcan4x5x_write_tcan_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, reg, val); +} + +static int tcan4x5x_clear_interrupts (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; +Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c line 313
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ;Does "ret" not return a proper error code?
Quoted 1 line
I can change it to ret.
Browsing some kernel code, returning "ret" seems the usual approach (apart from ignoring the return code).
Quoted 170 lines
Quoted 34 lines
Quoted 34 lines
drivers/net/can/m_can/tcan4x5x.c new file +32
-0+ + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_MCAN_INT_REG , +TCAN4X5X_ENABLE_MCAN_INT ); +if (ret) +return -EIO ; + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_INT_FLAGS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_ERROR_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + +return ret; +} + +static int tcan4x5x_init (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_clear_interrupts (class_dev); +if (ret) +return ret; + + ret = tcan4x5x_write_tcan_reg(class_dev, TCAN4X5X_INT_EN,Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c line 353
Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c new file +8
-0+ TCAN4X5X_ENABLE_TCAN_INT); +if (ret) +return -EIO ; + + ret =regmap_update_bits (tcan4x5x->regmap,TCAN4X5X_CONFIG , +TCAN4X5X_MODE_SEL_MASK ,TCAN4X5X_MODE_NORMAL ); +if (ret) +return -EIO ;Same comment as above
Quoted 115 lines
Quoted 115 lines
drivers/net/can/m_can/tcan4x5x.c new file +115
-0+ +/* Zero out the MCAN buffers */ +m_can_init_ram (class_dev); + +return ret; +} + +static int tcan4x5x_parse_config (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; + + tcan4x5x->reset_gpio =devm_gpiod_get_optional (class_dev->dev, +"reset" ,GPIOD_OUT_LOW ); +if (IS_ERR (tcan4x5x->reset_gpio)) + tcan4x5x->reset_gpio =NULL ; + + tcan4x5x->device_wake_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-wake" , +GPIOD_OUT_HIGH ); +if (IS_ERR (tcan4x5x->device_wake_gpio)) + tcan4x5x->device_wake_gpio =NULL ; + + tcan4x5x->device_state_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-state" , +GPIOD_IN ); +if (IS_ERR (tcan4x5x->device_state_gpio)) + tcan4x5x->device_state_gpio =NULL ; + + tcan4x5x->interrupt_gpio =devm_gpiod_get (class_dev->dev, +"data-ready" ,GPIOD_IN ); +if (IS_ERR (tcan4x5x->interrupt_gpio)) { +dev_err (class_dev->dev,"data-ready gpio not defined\n" ); +return -EINVAL ; + } + + class_dev->net->irq =gpiod_to_irq (tcan4x5x->interrupt_gpio); + + tcan4x5x->power =devm_regulator_get_optional (class_dev->dev, +"vsup" ); +if (PTR_ERR (tcan4x5x->power) == -EPROBE_DEFER ) +return -EPROBE_DEFER ; + +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 = { + .device_init = tcan4x5x_init, + .read_reg = tcan4x5x_read_reg, + .write_reg = tcan4x5x_write_reg, + .write_fifo = tcan4x5x_write_fifo, + .read_fifo = tcan4x5x_read_fifo, + .clr_dev_interrupts = tcan4x5x_clear_interrupts, +}; + +static int tcan4x5x_can_probe (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv; +struct m_can_classdev *mcan_class; +int freq, ret; + + mcan_class =m_can_class_allocate_dev (&spi->dev); + priv =devm_kzalloc (&spi->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); +if (IS_ERR (mcan_class->cclk)) { +dev_err (&spi->dev,"no CAN clock source defined\n" ); + freq =TCAN4X5X_EXT_CLK_DEF ; + }else { + freq =clk_get_rate (mcan_class->cclk); + } + +/* Sanity check */ +if (freq <20000000 || freq >TCAN4X5X_EXT_CLK_DEF ) +return -ERANGE ; + + priv->reg_offset =TCAN4X5X_MCAN_OFFSET ; + priv->mram_start =TCAN4X5X_MRAM_START ; + priv->spi = spi; + priv->mcan_dev = mcan_class; + + mcan_class->pm_clock_support =0 ; + mcan_class->can.clock.freq = freq; + mcan_class->dev = &spi->dev; + mcan_class->ops = &tcan4x5x_ops; + mcan_class->is_peripherial = true; + mcan_class->bit_timing = &tcan4x5x_bittiming_const; + mcan_class->data_timing = &tcan4x5x_data_bittiming_const; + +spi_set_drvdata (spi, priv); + + ret =tcan4x5x_parse_config (mcan_class); +if (ret) + goto out_clk; + +/* Configure the SPI bus */ + spi->bits_per_word =32 ; + ret =spi_setup (spi); +if (ret) + goto out_clk; + + priv->regmap =devm_regmap_init (&spi->dev, &tcan4x5x_bus, + &spi->dev, &tcan4x5x_regmap); + +mutex_init (&priv->tcan4x5x_lock);Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 474
Quoted 6 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+ +tcan4x5x_power_enable (priv->power,1 ); + + ret =m_can_class_register (mcan_class); +if (ret) + goto reg_err;
out_power?
Quoted 1 line
Not sure what you are asking?
"reg_err" stands for what? Above you use "out_clk" to disable clock settings. Therefore "out_power" does make sense to me (or something similar). Next time I will be a bit more verbose, sorry!
Quoted 70 lines
Quoted 17 lines
Quoted 4 lines
drivers/net/can/m_can/tcan4x5x.c new file +3
-0+ +netdev_info (mcan_class->net,"TCAN4X5X successfully initialized.\n" ); +return 0 ;drivers/net/can/m_can/tcan4x5x.c line 487
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ +reg_err: +tcan4x5x_power_enable (priv->power,0 ); +out_clk: +if (!IS_ERR (mcan_class->cclk)) { +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + } + +dev_err (&spi->dev,"Probe failed, err=%d\n" , -ret);Just "ret" is fine!
Ack
Quoted 40 lines
Quoted 40 lines
drivers/net/can/m_can/tcan4x5x.c new file +40
-0+return ret; +} + +static int tcan4x5x_can_remove (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv =spi_get_drvdata (spi); + +tcan4x5x_power_enable (priv->power,0 ); + +m_can_class_unregister (priv->mcan_dev); + +return 0 ; +} + +static const struct of_device_id tcan4x5x_of_match[] = { + { .compatible ="ti,tcan4x5x" , }, + { } +}; +MODULE_DEVICE_TABLE (of, tcan4x5x_of_match); + +static const struct spi_device_id tcan4x5x_id_table[] = { + { + .name ="tcan4x5x" , + .driver_data =0 , + }, + { } +}; +MODULE_DEVICE_TABLE (spi, tcan4x5x_id_table); + +static struct spi_driver tcan4x5x_can_driver = { + .driver = { + .name =DEVICE_NAME , + .of_match_table = tcan4x5x_of_match, + .pm =NULL , + }, + .id_table = tcan4x5x_id_table, + .probe = tcan4x5x_can_probe, + .remove = tcan4x5x_can_remove, +}; +module_spi_driver (tcan4x5x_can_driver);Quoted 9 lines
drivers/net/can/m_can/tcan4x5x.c line 531
Quoted 5 lines
drivers/net/can/m_can/tcan4x5x.c new file +4
-0+ +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_DESCRIPTION ("Texas Instruments TCAN4x5x CAN driver" ); +MODULE_LICENSE ("GPL v2" );The changes to the io-mapped driver look good and non-critical... time to ask for beta-testers for the next version of the patch series.
Quoted 1 line
OK. I also tested this here on one of our boards that use the iomapped code.
I know, you are testing on a dra76x from?
https://www.spinics.net/lists/linux-can/msg00886.html
More testing would be nice.
Wolfgang.
Re: [PATCH v5 5/5] can: tcan4x5x: Add tcan4x5x driver to the kernel
Wolfgang
Quoted 14 lines · Wolfgang Grandegger
Am 28.02.19 um 19:03 schrieb Dan Murphy:
Quoted 12 lines
Wolfgang
Quoted 8 lines · Wolfgang Grandegger
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 5 lines
Add the TCAN4x5x SPI CAN driver. This device
uses the Bosch MCAN IP core along with a SPI
interface map. Leverage the MCAN common core
code to manage the MCAN IP.
Quoted 9 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
This device has a special method to indicate a
write/read operation on the data payload.Please expand the text to approx. 72 lines.>>
72 lines or characters?
Characters, of course!
OK. Just clarifying. I did not think you were asking me to write a book here
Quoted 216 lines
Quoted 216 lines
Quoted 11 lines
Quoted 11 lines
Signed-off-by Dan Murphy <[email protected]>---
v5 - Changes to accomodate previous patches for functionality - https://lore.kernel.org/patchwork/patch/1033096/
drivers/net/can/m_can/Kconfig | 6 + drivers/net/can/m_can/Makefile | 1 + drivers/net/can/m_can/tcan4x5x.c | 531 +++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 drivers/net/can/m_can/tcan4x5x.cQuoted 16 lines
Quoted 5 lines
drivers/net/can/m_can/Kconfig +0
-0drivers/net/can/m_can/Kconfig config CAN_M_CAN_PLATFORM · line 17
Quoted 9 lines
drivers/net/can/m_can/Kconfig +6
-0@@ -9,3 +9,9 @@ config CAN_M_CAN_PLATFORM depends on CAN_M_CAN ---help--- Say Y here if you want to support for Bosch M_CAN controller. + +config CAN_M_CAN_TCAN4X5X + depends on CAN_M_CAN + tristate "TCAN4X5X M_CAN device" + ---help--- + Say Y here if you want to support for TI M_CAN controller.Could yo please be a bit more verbose here.
ACK
Quoted 185 lines
Quoted 172 lines
drivers/net/can/m_can/Makefile +1
-0@@ -4,3 +4,4 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o +obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.odrivers/net/can/m_can/tcan4x5x.c new file +156
-0@@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPI to CAN driver for the Texas Instruments TCAN4x5x +// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ + +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> + +#include "m_can.h" + +#define DEVICE_NAME "tcan4x5x" +#define TCAN4X5X_EXT_CLK_DEF 40000000 + +#define TCAN4X5X_DEV_ID0 0x00 +#define TCAN4X5X_DEV_ID1 0x04 +#define TCAN4X5X_REV 0x08 +#define TCAN4X5X_STATUS 0x0C +#define TCAN4X5X_ERROR_STATUS 0x10 +#define TCAN4X5X_CONTROL 0x14 + +#define TCAN4X5X_CONFIG 0x800 +#define TCAN4X5X_TS_PRESCALE 0x804 +#define TCAN4X5X_TEST_REG 0x808 +#define TCAN4X5X_INT_FLAGS 0x820 +#define TCAN4X5X_MCAN_INT_REG 0x824 +#define TCAN4X5X_INT_EN 0x830 + + +/* Interrupt bits */ +#define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30) +#define TCAN4X5X_CANHCANL_INT_EN BIT(29) +#define TCAN4X5X_CANHBAT_INT_EN BIT(28) +#define TCAN4X5X_CANLGND_INT_EN BIT(27) +#define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26) +#define TCAN4X5X_CANBUSGND_INT_EN BIT(25) +#define TCAN4X5X_CANBUSBAT_INT_EN BIT(24) +#define TCAN4X5X_UVSUP_INT_EN BIT(22) +#define TCAN4X5X_UVIO_INT_EN BIT(21) +#define TCAN4X5X_TSD_INT_EN BIT(19) +#define TCAN4X5X_ECCERR_INT_EN BIT(16) +#define TCAN4X5X_CANINT_INT_EN BIT(15) +#define TCAN4X5X_LWU_INT_EN BIT(14) +#define TCAN4X5X_CANSLNT_INT_EN BIT(10) +#define TCAN4X5X_CANDOM_INT_EN BIT(8) +#define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5) +#define TCAN4X5X_BUS_FAULT BIT(4) +#define TCAN4X5X_MCAN_INT BIT(1) +#define TCAN4X5X_ENABLE_TCAN_INT (TCAN4X5X_MCAN_INT | \ + TCAN4X5X_BUS_FAULT | \ + TCAN4X5X_CANBUS_ERR_INT_EN | \ + TCAN4X5X_CANINT_INT_EN) + +/* MCAN Interrupt bits */ +#define TCAN4X5X_MCAN_IR_ARA BIT(29) +#define TCAN4X5X_MCAN_IR_PED BIT(28) +#define TCAN4X5X_MCAN_IR_PEA BIT(27) +#define TCAN4X5X_MCAN_IR_WD BIT(26) +#define TCAN4X5X_MCAN_IR_BO BIT(25) +#define TCAN4X5X_MCAN_IR_EW BIT(24) +#define TCAN4X5X_MCAN_IR_EP BIT(23) +#define TCAN4X5X_MCAN_IR_ELO BIT(22) +#define TCAN4X5X_MCAN_IR_BEU BIT(21) +#define TCAN4X5X_MCAN_IR_BEC BIT(20) +#define TCAN4X5X_MCAN_IR_DRX BIT(19) +#define TCAN4X5X_MCAN_IR_TOO BIT(18) +#define TCAN4X5X_MCAN_IR_MRAF BIT(17) +#define TCAN4X5X_MCAN_IR_TSW BIT(16) +#define TCAN4X5X_MCAN_IR_TEFL BIT(15) +#define TCAN4X5X_MCAN_IR_TEFF BIT(14) +#define TCAN4X5X_MCAN_IR_TEFW BIT(13) +#define TCAN4X5X_MCAN_IR_TEFN BIT(12) +#define TCAN4X5X_MCAN_IR_TFE BIT(11) +#define TCAN4X5X_MCAN_IR_TCF BIT(10) +#define TCAN4X5X_MCAN_IR_TC BIT(9) +#define TCAN4X5X_MCAN_IR_HPM BIT(8) +#define TCAN4X5X_MCAN_IR_RF1L BIT(7) +#define TCAN4X5X_MCAN_IR_RF1F BIT(6) +#define TCAN4X5X_MCAN_IR_RF1W BIT(5) +#define TCAN4X5X_MCAN_IR_RF1N BIT(4) +#define TCAN4X5X_MCAN_IR_RF0L BIT(3) +#define TCAN4X5X_MCAN_IR_RF0F BIT(2) +#define TCAN4X5X_MCAN_IR_RF0W BIT(1) +#define TCAN4X5X_MCAN_IR_RF0N BIT(0) +#define TCAN4X5X_ENABLE_MCAN_INT (TCAN4X5X_MCAN_IR_TC | \ + TCAN4X5X_MCAN_IR_RF0N | \ + TCAN4X5X_MCAN_IR_RF1N | \ + TCAN4X5X_MCAN_IR_RF0F | \ + TCAN4X5X_MCAN_IR_RF1F) +#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) +#define TCAN4X5X_MODE_NORMAL BIT(7) + +#define TCAN4X5X_SW_RESET BIT(2) + +#define TCAN4X5X_MCAN_CONFIGURED BIT(5) +#define TCAN4X5X_WATCHDOG_EN BIT(3) +#define TCAN4X5X_WD_60_MS_TIMER 0 +#define TCAN4X5X_WD_600_MS_TIMER BIT(28) +#define TCAN4X5X_WD_3_S_TIMER BIT(29) +#define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29)) + +struct tcan4x5x_priv { +struct regmap *regmap; +struct spi_device *spi; +struct mutex tcan4x5x_lock;/* SPI device lock */ + +struct m_can_classdev *mcan_dev; + +struct gpio_desc *reset_gpio; +struct gpio_desc *interrupt_gpio; +struct gpio_desc *device_wake_gpio; +struct gpio_desc *device_state_gpio; +struct regulator *power; + +/* Register based ip */ +int mram_start; +int reg_offset; +}; + +static struct can_bittiming_const tcan4x5x_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =2 , + .tseg1_max =31 , + .tseg2_min =2 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; + +static struct can_bittiming_const tcan4x5x_data_bittiming_const = { + .name =DEVICE_NAME , + .tseg1_min =1 , + .tseg1_max =32 , + .tseg2_min =1 , + .tseg2_max =16 , + .sjw_max =16 , + .brp_min =1 , + .brp_max =32 , + .brp_inc =1 , +}; +drivers/net/can/m_can/tcan4x5x.c line 166
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+static void tcan4x5x_check_wake (struct tcan4x5x_priv *priv) +{ +int wake_state =0 ; + +if (priv->device_state_gpio) + wake_state =gpiod_get_value (priv->device_state_gpio); + +if (priv->device_wake_gpio && wake_state) { +gpiod_set_value (priv->device_wake_gpio,1 ); +udelay (100 );Do you need the setting above?
Quoted 5 lines
Quoted 1 line
Do you mean do I need to set the reset line then delay?
I mean, do you need to set the gpio value to 1 at the beginning? Is 0->1 not enough?
The data sheet indicates it needs to see a rising edge to wake up.
The hw engineer asked me to put it this way. But after digging into the data sheet I am not seeing the HW reason.
I will remove it and see if there is any effect on the operation. If we need it I will add a comment why.
Quoted 25 lines
Quoted 25 lines
Quoted 24 lines
Quoted 7 lines
drivers/net/can/m_can/tcan4x5x.c new file +6
-0+gpiod_set_value (priv->device_wake_gpio,0 ); +udelay (100 ); +gpiod_set_value (priv->device_wake_gpio,1 ); + } +} +drivers/net/can/m_can/tcan4x5x.c line 182
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+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, },};struct spi_transfer t[2] = { {.tx_buf = &addr, .len = reg_len, .cs_change = 0,}, {.tx_buf = val, .len = val_len,}, };
Quoted 4 lines
Quoted 1 line
I am assuming LTL issue here.
LTL means? I just reformatted the declaration.
Line to Long. But I changed it so it looks better.
Quoted 144 lines
Quoted 7 lines
Quoted 5 lines
drivers/net/can/m_can/tcan4x5x.c line 184
Quoted 3 lines
drivers/net/can/m_can/tcan4x5x.c new file +2
-0+ + addr =TCAN4X5X_WRITE_CMD | (*((u16 *)reg) <<8 ) | val_len >>3 ;There is nothing here
It's OK.
Quoted 134 lines
Quoted 133 lines
Quoted 121 lines
drivers/net/can/m_can/tcan4x5x.c new file +119
-0+ +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); +} + +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 *m_can_class,int reg) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->reg_offset + reg, &val); + +return val; +} + +static u32 tcan4x5x_read_fifo (struct m_can_classdev *m_can_class, +int addr_offset) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; +u32 val; + +tcan4x5x_check_wake (priv); + +regmap_read (priv->regmap, priv->mram_start + addr_offset, &val); + +return val; +} + +static int tcan4x5x_write_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->reg_offset + reg, val); +} + +static int tcan4x5x_write_fifo (struct m_can_classdev *m_can_class, +int addr_offset,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, priv->mram_start + addr_offset, val); +} + +static int tcan4x5x_power_enable (struct regulator *reg,int enable) +{ +if (IS_ERR_OR_NULL (reg)) +return 0 ; + +if (enable) +return regulator_enable (reg); +else +return regulator_disable (reg); +} + +static int tcan4x5x_write_tcan_reg (struct m_can_classdev *m_can_class, +int reg,int val) +{ +struct tcan4x5x_priv *priv = (struct tcan4x5x_priv *)m_can_class->device_data; + +tcan4x5x_check_wake (priv); + +return regmap_write (priv->regmap, reg, val); +} + +static int tcan4x5x_clear_interrupts (struct m_can_classdev *class_dev)drivers/net/can/m_can/tcan4x5x.c line 313
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ;Does "ret" not return a proper error code?
Quoted 5 lines
Quoted 1 line
I can change it to ret.
Browsing some kernel code, returning "ret" seems the usual approach (apart from ignoring the return code).
Changed
Quoted 170 lines
Quoted 170 lines
Quoted 34 lines
Quoted 34 lines
drivers/net/can/m_can/tcan4x5x.c new file +32
-0+ + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_MCAN_INT_REG , +TCAN4X5X_ENABLE_MCAN_INT ); +if (ret) +return -EIO ; + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_INT_FLAGS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + + + ret =tcan4x5x_write_tcan_reg (class_dev,TCAN4X5X_ERROR_STATUS , +TCAN4X5X_CLEAR_ALL_INT ); +if (ret) +return -EIO ; + +return ret; +} + +static int tcan4x5x_init (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; +int ret; + +tcan4x5x_check_wake (tcan4x5x); + + ret =tcan4x5x_clear_interrupts (class_dev); +if (ret) +return ret; + + ret = tcan4x5x_write_tcan_reg(class_dev, TCAN4X5X_INT_EN,Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c line 353
Quoted 8 lines
drivers/net/can/m_can/tcan4x5x.c new file +8
-0+ TCAN4X5X_ENABLE_TCAN_INT); +if (ret) +return -EIO ; + + ret =regmap_update_bits (tcan4x5x->regmap,TCAN4X5X_CONFIG , +TCAN4X5X_MODE_SEL_MASK ,TCAN4X5X_MODE_NORMAL ); +if (ret) +return -EIO ;Same comment as above
Quoted 124 lines
Quoted 111 lines
drivers/net/can/m_can/tcan4x5x.c new file +111
-0+ +/* Zero out the MCAN buffers */ +m_can_init_ram (class_dev); + +return ret; +} + +static int tcan4x5x_parse_config (struct m_can_classdev *class_dev) +{ +struct tcan4x5x_priv *tcan4x5x = (struct tcan4x5x_priv *)class_dev->device_data; + + tcan4x5x->reset_gpio =devm_gpiod_get_optional (class_dev->dev, +"reset" ,GPIOD_OUT_LOW ); +if (IS_ERR (tcan4x5x->reset_gpio)) + tcan4x5x->reset_gpio =NULL ; + + tcan4x5x->device_wake_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-wake" , +GPIOD_OUT_HIGH ); +if (IS_ERR (tcan4x5x->device_wake_gpio)) + tcan4x5x->device_wake_gpio =NULL ; + + tcan4x5x->device_state_gpio =devm_gpiod_get_optional (class_dev->dev, +"device-state" , +GPIOD_IN ); +if (IS_ERR (tcan4x5x->device_state_gpio)) + tcan4x5x->device_state_gpio =NULL ; + + tcan4x5x->interrupt_gpio =devm_gpiod_get (class_dev->dev, +"data-ready" ,GPIOD_IN ); +if (IS_ERR (tcan4x5x->interrupt_gpio)) { +dev_err (class_dev->dev,"data-ready gpio not defined\n" ); +return -EINVAL ; + } + + class_dev->net->irq =gpiod_to_irq (tcan4x5x->interrupt_gpio); + + tcan4x5x->power =devm_regulator_get_optional (class_dev->dev, +"vsup" ); +if (PTR_ERR (tcan4x5x->power) == -EPROBE_DEFER ) +return -EPROBE_DEFER ; + +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 = { + .device_init = tcan4x5x_init, + .read_reg = tcan4x5x_read_reg, + .write_reg = tcan4x5x_write_reg, + .write_fifo = tcan4x5x_write_fifo, + .read_fifo = tcan4x5x_read_fifo, + .clr_dev_interrupts = tcan4x5x_clear_interrupts, +}; + +static int tcan4x5x_can_probe (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv; +struct m_can_classdev *mcan_class; +int freq, ret; + + mcan_class =m_can_class_allocate_dev (&spi->dev); + priv =devm_kzalloc (&spi->dev,sizeof (*priv),GFP_KERNEL ); +if (!priv) +return -ENOMEM ; + + mcan_class->device_data = priv; + +m_can_class_get_clocks (mcan_class); +if (IS_ERR (mcan_class->cclk)) { +dev_err (&spi->dev,"no CAN clock source defined\n" ); + freq =TCAN4X5X_EXT_CLK_DEF ; + }else { + freq =clk_get_rate (mcan_class->cclk); + } + +/* Sanity check */ +if (freq <20000000 || freq >TCAN4X5X_EXT_CLK_DEF ) +return -ERANGE ; + + priv->reg_offset =TCAN4X5X_MCAN_OFFSET ; + priv->mram_start =TCAN4X5X_MRAM_START ; + priv->spi = spi; + priv->mcan_dev = mcan_class; + + mcan_class->pm_clock_support =0 ; + mcan_class->can.clock.freq = freq; + mcan_class->dev = &spi->dev; + mcan_class->ops = &tcan4x5x_ops; + mcan_class->is_peripherial = true; + mcan_class->bit_timing = &tcan4x5x_bittiming_const; + mcan_class->data_timing = &tcan4x5x_data_bittiming_const; + +spi_set_drvdata (spi, priv); + + ret =tcan4x5x_parse_config (mcan_class); +if (ret) + goto out_clk; + +/* Configure the SPI bus */ + spi->bits_per_word =32 ; + ret =spi_setup (spi); +if (ret) + goto out_clk; +drivers/net/can/m_can/tcan4x5x.c line 474
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ priv->regmap =devm_regmap_init (&spi->dev, &tcan4x5x_bus, + &spi->dev, &tcan4x5x_regmap); + +mutex_init (&priv->tcan4x5x_lock); + +tcan4x5x_power_enable (priv->power,1 ); + + ret =m_can_class_register (mcan_class); +if (ret) + goto reg_err;
out_power?
Quoted 6 lines
Quoted 1 line
Not sure what you are asking?
"
reg_err" stands for what? Above you use "out_clk" to disable clock settings. Therefore "out_power" does make sense to me (or something similar). Next time I will be a bit more verbose, sorry!
Yeah that makes more sense. reg_err was registration error.
Quoted 70 lines
Quoted 70 lines
Quoted 17 lines
Quoted 4 lines
drivers/net/can/m_can/tcan4x5x.c new file +3
-0+ +netdev_info (mcan_class->net,"TCAN4X5X successfully initialized.\n" ); +return 0 ;drivers/net/can/m_can/tcan4x5x.c line 487
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ +reg_err: +tcan4x5x_power_enable (priv->power,0 ); +out_clk: +if (!IS_ERR (mcan_class->cclk)) { +clk_disable_unprepare (mcan_class->cclk); +clk_disable_unprepare (mcan_class->hclk); + } + +dev_err (&spi->dev,"Probe failed, err=%d\n" , -ret);Just "ret" is fine!
Ack
Quoted 49 lines
Quoted 35 lines
drivers/net/can/m_can/tcan4x5x.c new file +34
-0+return ret; +} + +static int tcan4x5x_can_remove (struct spi_device *spi) +{ +struct tcan4x5x_priv *priv =spi_get_drvdata (spi); + +tcan4x5x_power_enable (priv->power,0 ); + +m_can_class_unregister (priv->mcan_dev); + +return 0 ; +} + +static const struct of_device_id tcan4x5x_of_match[] = { + { .compatible ="ti,tcan4x5x" , }, + { } +}; +MODULE_DEVICE_TABLE (of, tcan4x5x_of_match); + +static const struct spi_device_id tcan4x5x_id_table[] = { + { + .name ="tcan4x5x" , + .driver_data =0 , + }, + { } +}; +MODULE_DEVICE_TABLE (spi, tcan4x5x_id_table); + +static struct spi_driver tcan4x5x_can_driver = { + .driver = { + .name =DEVICE_NAME , + .of_match_table = tcan4x5x_of_match, + .pm =NULL ,drivers/net/can/m_can/tcan4x5x.c line 531
Quoted 10 lines
drivers/net/can/m_can/tcan4x5x.c new file +10
-0+ }, + .id_table = tcan4x5x_id_table, + .probe = tcan4x5x_can_probe, + .remove = tcan4x5x_can_remove, +}; +module_spi_driver (tcan4x5x_can_driver); + +MODULE_AUTHOR ("Dan Murphy <[email protected]>" ); +MODULE_DESCRIPTION ("Texas Instruments TCAN4x5x CAN driver" ); +MODULE_LICENSE ("GPL v2" );The changes to the io-mapped driver look good and non-critical... time to ask for beta-testers for the next version of the patch series.
Quoted 8 lines
Quoted 1 line
OK. I also tested this here on one of our boards that use the iomapped code.
I know, you are testing on a dra76x from?
https://www.spinics.net/lists/linux-can/msg00886.html
More testing would be nice.
OK. I know we will be testing both the io mapped and we have a couple customers using the TCAN code with this change.
Dan
Quoted 2 lines
Wolfgang.
Signature · 2 lines
------------------ Dan Murphy
Bump
Quoted 44 lines · Dan Murphy
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Signature · 2 lines
------------------ Dan Murphy
Hello Dan,
I will have a closer look end of this week!
Wolfgang.
Am 21.02.19 um 17:24 schrieb Dan Murphy:
Quoted 49 lines
Bump
Quoted 44 lines · Dan Murphy
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Hello Dan,
what kernel version is that patch series for. I have problems to apply it!
Wolfgang.
Am 21.02.19 um 17:41 schrieb Wolfgang Grandegger:
Quoted 56 lines
Hello Dan,
I will have a closer look end of this week!
Wolfgang.
Am 21.02.19 um 17:24 schrieb Dan Murphy:
Quoted 49 lines
Bump
Quoted 44 lines · Dan Murphy
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Wolfgang
Quoted 4 lines · Wolfgang Grandegger
Hello Dan,
what kernel version is that patch series for. I have problems to apply it!
It is based off of Master
commit 2137397c92aec3713fa10be3c9b830f9a1674e60 (linux_master/master)
And I successfully rebased on top of
commit 8a61716ff2ab23eddd1f7a05a075a374e4d0c3d4 (linux_master/master) Merge tag 'ceph-for-5.0-rc8' of git://github.com/ceph/ceph-client
Dan
Quoted 59 lines
Wolfgang.
Am 21.02.19 um 17:41 schrieb Wolfgang Grandegger:
Quoted 56 lines
Hello Dan,
I will have a closer look end of this week!
Wolfgang.
Am 21.02.19 um 17:24 schrieb Dan Murphy:
Quoted 49 lines
Bump
Quoted 44 lines · Dan Murphy
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Signature · 2 lines
------------------ Dan Murphy
Wolfgang
Quoted 8 lines · Dan Murphy
Wolfgang
Quoted 4 lines · Wolfgang Grandegger
Hello Dan,
what kernel version is that patch series for. I have problems to apply it!
Quoted 9 lines
It is based off of Master
commit
2137397c92aec3713fa10be3c9b830f9a1674e60(linux_master/master)And I successfully rebased on top of
commit
8a61716ff2ab23eddd1f7a05a075a374e4d0c3d4(linux_master/master) Merge tag 'ceph-for-5.0-rc8' ofgit://github.com/ceph/ceph-client
I just pulled these patches and they applied fine to the top commit of linux master
Do I need to rebase on top of a for-next branch for you?
Dan
Quoted 63 lines
Dan
Quoted 59 lines
Wolfgang.
Am 21.02.19 um 17:41 schrieb Wolfgang Grandegger:
Quoted 56 lines
Hello Dan,
I will have a closer look end of this week!
Wolfgang.
Am 21.02.19 um 17:24 schrieb Dan Murphy:
Quoted 49 lines
Bump
Quoted 44 lines · Dan Murphy
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.Again the first 3 patches here are all just for readability and review purposes.
Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Signature · 2 lines
------------------ Dan Murphy
Hello Dan,
Am 22.02.19 um 18:05 schrieb Dan Murphy:
Quoted 17 lines
Wolfgang
Quoted 14 lines · Dan Murphy
Wolfgang
Quoted 4 lines · Wolfgang Grandegger
Hello Dan,
what kernel version is that patch series for. I have problems to apply it!
It is based off of Master
commit
2137397c92aec3713fa10be3c9b830f9a1674e60(linux_master/master)And I successfully rebased on top of
Quoted 7 lines
Quoted 3 lines
commit
8a61716ff2ab23eddd1f7a05a075a374e4d0c3d4(linux_master/master) Merge tag 'ceph-for-5.0-rc8' ofgit://github.com/ceph/ceph-clientI just pulled these patches and they applied fine to the top commit of linux master
Do I need to rebase on top of a for-next branch for you?
No, I can apply the series now as well.
Wolfgang,
Wolfgang
Quoted 24 lines · Wolfgang Grandegger
Hello Dan,
Am 22.02.19 um 18:05 schrieb Dan Murphy:
Quoted 21 lines
Wolfgang
Quoted 17 lines · Dan Murphy
Wolfgang
Quoted 4 lines · Wolfgang Grandegger
Hello Dan,
what kernel version is that patch series for. I have problems to apply it!
It is based off of Master
commit
2137397c92aec3713fa10be3c9b830f9a1674e60(linux_master/master)And I successfully rebased on top of
commit
8a61716ff2ab23eddd1f7a05a075a374e4d0c3d4(linux_master/master) Merge tag 'ceph-for-5.0-rc8' ofgit://github.com/ceph/ceph-client
Quoted 6 lines
Quoted 3 lines
I just pulled these patches and they applied fine to the top commit of linux master
Do I need to rebase on top of a for-next branch for you?
No, I can apply the series now as well.
Good. Just commenting to bump this in my email list.
Waiting on comments.
Dan
Quoted 2 lines
Wolfgang,
Signature · 2 lines
------------------ Dan Murphy
Hello,
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 9 lines
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.
For git bisection, the code must compile!
Quoted 9 lines
The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.
For the reason above, I would squash patch 1 and 2.
Quoted 11 lines
Again the first 3 patches here are all just for readability and review purposes.> Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernel
Quoted 12 lines
.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
There are plenty of coding-style errors, e.g. white-space, indention, line too long, etc. Please use "checkpatch" to find and fix.
Wolfgang.
Wolfgang
Quoted 8 lines · Wolfgang Grandegger
Hello,
Am 14.02.19 um 19:27 schrieb Dan Murphy:
Quoted 5 lines
Hello
OK I did not give up on this patch series just got a little preoccupied with some other kernel work. But here is the update per the comments.
Quoted 7 lines
Quoted 4 lines
It should be understood I broke these out for reviewability.
For instance the first patch does not compile on its own as including this patch should not change the current functionality and it pulls all the io-mapped code from them_canbase file to a platfrom file.For git bisection, the code must compile!
So I can squash patch 1 and 2 then.
Quoted 36 lines
Quoted 9 lines
The next patch "Migrate the
m_cancode to use the framework"
is the change to the kernel for the io-mapped conversion from a flat file to use the framework. Finally the rename patch just renames them_can_privtom_can_classdev. I broke this change out specifically for readability of the migration patch per comments on the code.AFAIC the first 3 patches can all be squashed into a single patch. Or the first 2 patches in the series can be re-arranged but then
m_canfunctionality is affected in the migration patch.For the reason above, I would squash patch 1 and 2.
Quoted 11 lines
Again the first 3 patches here are all just for readability and review purposes.> Dan
Dan Murphy (5):
can:m_can: Create am_canplatform framework
can:m_can: Migrate them_cancode to use the framework
can:m_can: Renamem_can_privtom_can_classdev
dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
can: tcan4x5x: Add tcan4x5x driver to the kernelQuoted 12 lines
.../devicetree/bindings/net/can/tcan4x5x.txt | 37 + drivers/net/can/m_can/Kconfig | 14 +- drivers/net/can/m_can/Makefile | 2 + drivers/net/can/m_can/m_can.c | 788 +++++++++--------- drivers/net/can/m_can/m_can.h | 159 ++++ drivers/net/can/m_can/m_can_platform.c | 198 +++++ drivers/net/can/m_can/tcan4x5x.c | 531 ++++++++++++ 7 files changed, 1320 insertions(+), 409 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt create mode 100644 drivers/net/can/m_can/m_can.h create mode 100644 drivers/net/can/m_can/m_can_platform.c create mode 100644 drivers/net/can/m_can/tcan4x5x.c
Quoted 3 lines
There are plenty of coding-style errors, e.g. white-space, indention, line too long, etc. Please use "checkpatch" to find and fix.
Ack. I missed running it on v5. I will update in v6.
Quoted 4 lines
Wolfgang.
Signature · 2 lines
------------------ Dan Murphy