// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2023, 2024 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
//
// Rockchip CANFD driver
//
// Copyright (c) 2020 Rockchip Electronics Co. Ltd.
//
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/string.h>
#include "rockchip_canfd.h"
static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v2 = {
.model = RKCANFD_MODEL_RK3568V2,
.quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
RKCANFD_QUIRK_RK3568_ERRATUM_3 | RKCANFD_QUIRK_RK3568_ERRATUM_4 |
RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_6 |
RKCANFD_QUIRK_RK3568_ERRATUM_7 | RKCANFD_QUIRK_RK3568_ERRATUM_8 |
RKCANFD_QUIRK_RK3568_ERRATUM_9 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
RKCANFD_QUIRK_CANFD_BROKEN,
};
/* The rk3568 CAN-FD errata sheet as of Tue 07 Nov 2023 11:25:31 +08:00
* states that only the rk3568v2 is affected by erratum 5, but tests
* with the rk3568v2 and rk3568v3 show that the RX_FIFO_CNT is
* sometimes too high. In contrast to the errata sheet mark rk3568v3
* as effected by erratum 5, too.
*/
static const struct rkcanfd_devtype_data rkcanfd_devtype_data_rk3568v3 = {
.model = RKCANFD_MODEL_RK3568V3,
.quirks = RKCANFD_QUIRK_RK3568_ERRATUM_1 | RKCANFD_QUIRK_RK3568_ERRATUM_2 |
RKCANFD_QUIRK_RK3568_ERRATUM_5 | RKCANFD_QUIRK_RK3568_ERRATUM_7 |
RKCANFD_QUIRK_RK3568_ERRATUM_8 | RKCANFD_QUIRK_RK3568_ERRATUM_10 |
RKCANFD_QUIRK_RK3568_ERRATUM_11 | RKCANFD_QUIRK_RK3568_ERRATUM_12 |
RKCANFD_QUIRK_CANFD_BROKEN,
};
static const char *__rkcanfd_get_model_str(enum rkcanfd_model model)
{
switch (model) {
case RKCANFD_MODEL_RK3568V2:
return "rk3568v2";
case RKCANFD_MODEL_RK3568V3:
return "rk3568v3";
}
return "<unknown>";
}
static inline const char *
rkcanfd_get_model_str(const struct rkcanfd_priv *priv)
{
return __rkcanfd_get_model_str(priv->devtype_data.model);
}
/* Note:
*
* The formula to calculate the CAN System Clock is:
*
* Tsclk = 2 x Tclk x (brp + 1)
*
* Double the data sheet's brp_min, brp_max and brp_inc values (both
* for the arbitration and data bit timing) to take the "2 x" into
* account.
*/
static const struct can_bittiming_const rkcanfd_bittiming_const = {
.name = DEVICE_NAME,
.tseg1_min = 1,
.tseg1_max = 256,
.tseg2_min = 1,
.tseg2_max = 128,
.sjw_max = 128,
.brp_min = 2, /* value from data sheet x2 */
.brp_max = 512, /* value from data sheet x2 */
.brp_inc = 2, /* value from data sheet x2 */
};
static const struct can_bittiming_const rkcanfd_data_bittiming_const = {
.name = DEVICE_NAME,
.tseg1_min = 1,
.tseg1_max = 32,
.tseg2_min = 1,
.tseg2_max = 16,
.sjw_max = 16,
.brp_min = 2, /* value from data sheet x2 */
.brp_max = 512, /* value from data sheet x2 */
.brp_inc = 2, /* value from data sheet x2 */
};
static void rkcanfd_chip_set_reset_mode(const struct rkcanfd_priv *priv)
{
reset_control_assert(priv->reset);
udelay(2);
reset_control_deassert(priv->reset);
rkcanfd_write(priv, RKCANFD_REG_MODE, 0x0);
}
static void rkcanfd_chip_set_work_mode(const struct rkcanfd_priv *priv)
{
rkcanfd_write(priv, RKCANFD_REG_MODE, priv->reg_mode_default);
}
static int rkcanfd_set_bittiming(struct rkcanfd_priv *priv)
{
const struct can_bittiming *dbt = &priv->can.fd.data_bittiming;
const struct can_bittiming *bt = &priv->can.bittiming;
u32 reg_nbt, reg_dbt, reg_tdc;
u32 tdco;
reg_nbt = FIELD_PREP(RKCANFD_REG_FD_NOMINAL_BITTIMING_SJW,
bt->sjw - 1) |
FIELD_PREP(RKCANFD_REG_FD_NOMINAL_BITTIMING_BRP,
(bt->brp / 2) - 1) |
FIELD_PREP(RKCANFD_REG_FD_NOMINAL_BITTIMING_TSEG2,
bt->phase_seg2 - 1) |
FIELD_PREP(RKCANFD_REG_FD_NOMINAL_BITTIMING_TSEG1,
bt->prop_seg + bt->phase_seg1 - 1);
rkcanfd_write(priv, RKCANFD_REG_FD_NOMINAL_BITTIMING, reg_nbt);
if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD))
return 0;
reg_dbt = FIELD_PREP(RKCANFD_REG_FD_DATA_BITTIMING_SJW,
dbt->sjw - 1) |
FIELD_PREP(RKCANFD_REG_FD_DATA_BITTIMING_BRP,
(dbt->brp / 2) - 1) |
FIELD_PREP(RKCANFD_REG_FD_DATA_BITTIMING_TSEG2,
dbt->phase_seg2 - 1) |
FIELD_PREP(RKCANFD_REG_FD_DATA_BITTIMING_TSEG1,
dbt->prop_seg + dbt->phase_seg1 - <