drivers: can: sam: use UPLL clock instead of PLLA clock
Use the UPLLCK clock for the CAN controller as recommended by the Atmel SAM
E70 data sheet.
Move the configuration of the clock prescaler from Kconfig to devicetree
and limit it to the values recommended by the SAM E70 datasheet.
Fixes: #45012
Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
diff --git a/drivers/can/Kconfig.sam b/drivers/can/Kconfig.sam
index 919a733..8952f4d 100644
--- a/drivers/can/Kconfig.sam
+++ b/drivers/can/Kconfig.sam
@@ -8,15 +8,3 @@
bool "Atmel SAM CAN driver"
default $(dt_compat_enabled,$(DT_COMPAT_ATMEL_SAM_CAN))
select CAN_MCAN
-
-if CAN_SAM
-
-config CAN_SAM_CKDIV
- int "Clock divider"
- range 0 255
- default 0
- depends on CAN_SAM
- help
- Clock divider for the MCAN core clock.
-
-endif #CAN_SAM
diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c
index 6309d4b..56aef49 100644
--- a/drivers/can/can_sam.c
+++ b/drivers/can/can_sam.c
@@ -21,6 +21,7 @@
void (*config_irq)(void);
const struct pinctrl_dev_config *pcfg;
uint8_t pmc_id;
+ int divider;
};
struct can_sam_data {
@@ -29,18 +30,20 @@
static int can_sam_get_core_clock(const struct device *dev, uint32_t *rate)
{
- ARG_UNUSED(dev);
+ const struct can_mcan_config *mcan_cfg = dev->config;
+ const struct can_sam_config *sam_cfg = mcan_cfg->custom;
- *rate = SOC_ATMEL_SAM_MCK_FREQ_HZ / (CONFIG_CAN_SAM_CKDIV + 1);
+ *rate = SOC_ATMEL_SAM_UPLLCK_FREQ_HZ / (sam_cfg->divider);
return 0;
}
-static void can_sam_clock_enable(const struct can_sam_config *cfg)
+static void can_sam_clock_enable(const struct can_sam_config *sam_cfg)
{
- REG_PMC_PCK5 = PMC_PCK_CSS_PLLA_CLK | PMC_PCK_PRES(CONFIG_CAN_SAM_CKDIV);
+ REG_PMC_PCK5 = PMC_PCK_CSS_UPLL_CLK | PMC_PCK_PRES(sam_cfg->divider - 1);
PMC->PMC_SCER |= PMC_SCER_PCK5;
- soc_pmc_peripheral_enable(cfg->pmc_id);
+
+ soc_pmc_peripheral_enable(sam_cfg->pmc_id);
}
static int can_sam_init(const struct device *dev)
@@ -129,6 +132,7 @@
#define CAN_SAM_CFG_INST(inst) \
static const struct can_sam_config can_sam_cfg_##inst = { \
.pmc_id = DT_INST_PROP(inst, peripheral_id), \
+ .divider = DT_INST_PROP(inst, divider), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
.config_irq = config_can_##inst##_irq, \
}; \
diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi
index df4e85e..273de94 100644
--- a/dts/arm/atmel/same70.dtsi
+++ b/dts/arm/atmel/same70.dtsi
@@ -445,6 +445,7 @@
interrupts = <35 0>, <36 0>;
interrupt-names = "LINE_0", "LINE_1";
peripheral-id = <35>;
+ divider = <6>;
sjw = <1>;
sample-point = <875>;
sjw-data = <1>;
@@ -462,6 +463,7 @@
interrupts = <37 0>, <38 0>;
interrupt-names = "LINE_0", "LINE_1";
peripheral-id = <37>;
+ divider = <6>;
sjw = <1>;
sample-point = <875>;
sjw-data = <1>;
diff --git a/dts/bindings/can/atmel,sam-can.yaml b/dts/bindings/can/atmel,sam-can.yaml
index e441a2d..837c861 100644
--- a/dts/bindings/can/atmel,sam-can.yaml
+++ b/dts/bindings/can/atmel,sam-can.yaml
@@ -17,3 +17,12 @@
type: int
required: true
description: peripheral ID
+
+ divider:
+ type: int
+ required: true
+ enum:
+ - 6
+ - 12
+ - 24
+ description: Clock divider for the CAN core clock