const:ipms,can
reg:
- minItems: 1
+ maxItems: 1
items:
- description:CAN controller registers
- - description:sys_syscon is used to enable canfd controller
-
- reg-names:
- minItems: 1
- items:
- - const:reg_base
- - const:sys_syscon
interrupts:
maxItems: 1
clocks:
minItems: 1
items:
- - description:ipms_can_clk clock
- description:apb_clk clock
- description:core_clk clock
- description:timer_clk clock
clock-names:
minItems: 1
items:
- - const:ipms_can_clk
- const:apb_clk
- const:core_clk
- const:timer_clk
- const:rst_apb
- const:rst_core
- const:rst_timer
- syscon,canfd-enable:
- type:boolean
- description:
- Use syscon,canfd-enable to control whether to enable the canfd controller.
- When the canfd controller needs to be enabled,
- the syscon,canfd-enable,syscon,canfd-offset, and syscon,canfd-mask attributes must be configured at the same time.
- It is meaningless to set one of the properties separately.
- syscon,canfd-offset:
+ starfive,sys-syscon:
+ format:
+ starfive,sys-syscon = <&arg0 arg1 arg2 arg3>
description:
- syscon,canfd-offset is a constant, can0 is 0x10, can1 is 0x88
- syscon,canfd-mask:
+ arg0:arg0 is sys_syscon.
+ arg1:arg1 is syscon register offset, used to enable can2.0/canfd function, can0 is 0x10, can1 is 0x88.
+ arg2:arg2 is used to enable the register shift of the can2.0/canfd function, can0 is 0x3, can1 is 0x12.
+ arg3:arg3 is used to enable the register mask of the can2.0/canfd function, can0 is 0x8, can1 is 0x40000
+
+ syscon,can_or_canfd:
description:
- syscon,canfd-mask is a constant,can0 is 0x8,can1 is 0x40000
+ IPMS CAN-CTRL core is a serial communications controller that performs serial communication according to the CAN protocol.
+ This CAN bus interface uses the basic CAN principle and meets all constraints of the CAN-specification 2.0B active.
+ Furthermore this CAN core can be configured to meet the specification of CAN with flexible data rate CAN FD.
+ When syscon,can_or_canfd is set to 0, use CAN2.0B.
+ when syscon,can_or_canfd is set to 1, use CAN FD.
required:
- compatible
- reg
- clock-names
- resets
- reset-names
-
-additionalProperties:
- - syscon,canfd-enable
- - syscon,canfd-offset
- - syscon,canfd-mask
+ - starfive,sys-syscon
+ - syscon,can_or_canfd
+additionalProperties:false
examples:
- |
- ipmscan0: can@130d0000{
+ can0: can@130d0000{
compatible = "ipms,can";
- reg = <0x0 0x130d0000 0x0 0x1000>,
- <0x0 0x13030000 0x0 0x10000>;
- reg-names = "reg_base","sys_syscon";
+ reg = <0x0 0x130d0000 0x0 0x1000>;
interrupts = <112>;
interrupt-parent = <&plic>;
- clocks = <&canclk>,
- <&clkgen JH7110_CAN0_CTRL_CLK_APB>,
+ clocks = <&clkgen JH7110_CAN0_CTRL_CLK_APB>,
<&clkgen JH7110_CAN0_CTRL_CLK_CAN>,
<&clkgen JH7110_CAN0_CTRL_CLK_TIMER>;
- clock-names = "ipms_can_clk",
- "apb_clk",
+ clock-names = "apb_clk",
"core_clk",
"timer_clk";
resets = <&rstgen RSTN_U0_CAN_CTRL_APB>,
reset-names = "rst_apb",
"rst_core",
"rst_timer";
+ starfive,sys-syscon = <&sys_syscon, 0x10 0x3 0x8>;
+ syscon,can_or_canfd = <0>;
};
...
status = "okay";
};
-&ipmscan0 {
+&can0 {
status = "okay";
};
-&ipmscan1 {
+&can1 {
status = "okay";
};
};
};
};
-};
\ No newline at end of file
+};
/ {
model = "StarFive JH7110 EVB";
compatible = "starfive,jh7110-evb", "starfive,jh7110";
+};
+
+&timer {
+ clock-frequency = <24000000>;
};
\ No newline at end of file
/ {
model = "StarFive JH7110 FPGA";
compatible = "starfive,jh7110-fpga", "starfive,jh7110";
+};
+
+&timer {
+ clock-frequency = <2000000>;
+};
+
+&wdog {
+ clock-frequency = <2000000>;
};
\ No newline at end of file
/ {
model = "StarFive VisionFive V2";
compatible = "starfive,visionfive-v2", "starfive,jh7110";
+};
+
+&timer {
+ clock-frequency = <24000000>;
};
\ No newline at end of file
compatible = "starfive,si5-timers";
reg = <0x0 0x13050000 0x0 0x10000>;
interrupts = <69>, <70>, <71> ,<72>;
- interrupt-names = "timer0", "timer1", "timer2", "timer3";
+ interrupt-names = "timer0", "timer1",
+ "timer2", "timer3";
+ clocks = <&clkgen JH7110_TIMER_CLK_TIMER0>,
+ <&clkgen JH7110_TIMER_CLK_TIMER1>,
+ <&clkgen JH7110_TIMER_CLK_TIMER2>,
+ <&clkgen JH7110_TIMER_CLK_TIMER3>,
+ <&clkgen JH7110_TIMER_CLK_APB>;
+ clock-names = "timer0", "timer1",
+ "timer2", "timer3", "apb_clk";
clock-frequency = <2000000>;
- status = "disabled";
+ status = "okay";
};
wdog: wdog@13070000 {
interrupt-names = "wdog";
clock-frequency = <2000000>;
clocks = <&clkgen JH7110_DSKIT_WDT_CLK_WDT>,
- <&clkgen JH7110_DSKIT_WDT_CLK_APB>;
+ <&clkgen JH7110_DSKIT_WDT_CLK_APB>;
clock-names = "core_clk", "apb_clk";
resets = <&rstgen RSTN_U0_DSKIT_WDT_APB>,
- <&rstgen RSTN_U0_DSKIT_WDT_CORE>;
+ <&rstgen RSTN_U0_DSKIT_WDT_CORE>;
reset-names = "rst_apb", "rst_core";
timeout-sec = <15>;
status = "okay";
i2c6: i2c@12060000 {
compatible = "snps,designware-i2c";
reg = <0x0 0x12060000 0x0 0x10000>;
+ clocks = <&clkgen JH7110_I2C6_CLK_CORE>,
+ <&clkgen JH7110_I2C6_CLK_APB>;
+ clock-names = "ref", "pclk";
+ resets = <&rstgen RSTN_U6_DW_I2C_APB>;
interrupts = <51>;
#address-cells = <1>;
#size-cells = <0>;
i2c0: i2c@10030000 {
compatible = "snps,designware-i2c";
reg = <0x0 0x10030000 0x0 0x10000>;
+ clocks = <&clkgen JH7110_I2C0_CLK_CORE>,
+ <&clkgen JH7110_I2C0_CLK_APB>;
+ clock-names = "ref", "pclk";
+ resets = <&rstgen RSTN_U0_DW_I2C_APB>;
interrupts = <35>;
#address-cells = <1>;
#size-cells = <0>;
i2c1: i2c@10040000 {
compatible = "snps,designware-i2c";
reg = <0x0 0x10040000 0x0 0x10000>;
+ clocks = <&clkgen JH7110_I2C1_CLK_CORE>,
+ <&clkgen JH7110_I2C1_CLK_APB>;
+ clock-names = "ref", "pclk";
+ resets = <&rstgen RSTN_U1_DW_I2C_APB>;
interrupts = <36>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
- ipmscan0: can@130d0000 {
+ can0: can@130d0000 {
compatible = "ipms,can";
- reg = <0x0 0x130d0000 0x0 0x1000>,
- <0x0 0x13030000 0x0 0x10000>;
- reg-names = "reg_base","sys_syscon";
+ reg = <0x0 0x130d0000 0x0 0x1000>;
interrupts = <112>;
- clocks = <&canclk>,
- <&clkgen JH7110_CAN0_CTRL_CLK_APB>,
+ clocks = <&clkgen JH7110_CAN0_CTRL_CLK_APB>,
<&clkgen JH7110_CAN0_CTRL_CLK_CAN>,
<&clkgen JH7110_CAN0_CTRL_CLK_TIMER>;
- clock-names = "ipms_can_clk",
- "apb_clk",
+ clock-names = "apb_clk",
"core_clk",
"timer_clk";
resets = <&rstgen RSTN_U0_CAN_CTRL_APB>,
reset-names = "rst_apb",
"rst_core",
"rst_timer";
+ starfive,sys-syscon = <&sys_syscon 0x10 0x3 0x8>;
+ syscon,can_or_canfd = <0>;
status = "disabled";
};
- ipmscan1: can@130c0000 {
+ can1: can@130e0000 {
compatible = "ipms,can";
- reg = <0x0 0x130c0000 0x0 0x1000>,
- <0x0 0x13030000 0x0 0x10000>;
- reg-names = "reg_base","sys_syscon";
+ reg = <0x0 0x130e0000 0x0 0x1000>;
interrupts = <113>;
- clocks = <&canclk>,
- <&clkgen JH7110_CAN1_CTRL_CLK_APB>,
+ clocks = <&clkgen JH7110_CAN1_CTRL_CLK_APB>,
<&clkgen JH7110_CAN1_CTRL_CLK_CAN>,
<&clkgen JH7110_CAN1_CTRL_CLK_TIMER>;
- clock-names = "ipms_can_clk",
- "apb_clk",
+ clock-names = "apb_clk",
"core_clk",
"timer_clk";
resets = <&rstgen RSTN_U1_CAN_CTRL_APB>,
reset-names = "rst_apb",
"rst_core",
"rst_timer";
+ starfive,sys-syscon = <&sys_syscon 0x88 0x12 0x40000>;
+ syscon,can_or_canfd = <0>;
status = "disabled";
};
pinctrl-0 = <&gmac1_pins>;
};
+&i2c6 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c6_pins>;
+ status = "okay";
+};
+
&i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
status = "okay";
};
-&ipmscan0 {
+&can0 {
pinctrl-names = "default";
pinctrl-0 = <&can0_pins>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
status = "okay";
-};
\ No newline at end of file
+};
0, JH7110_OSC),
//TIMER
JH7110_GATE(JH7110_TIMER_CLK_APB, "u0_si5_timer_clk_apb",
- 0, JH7110_APB12),
+ CLK_IGNORE_UNUSED, JH7110_APB12),
JH7110_GATE(JH7110_TIMER_CLK_TIMER0, "u0_si5_timer_clk_timer0",
- 0, JH7110_OSC),
+ CLK_IGNORE_UNUSED, JH7110_OSC),
JH7110_GATE(JH7110_TIMER_CLK_TIMER1, "u0_si5_timer_clk_timer1",
- 0, JH7110_OSC),
+ CLK_IGNORE_UNUSED, JH7110_OSC),
JH7110_GATE(JH7110_TIMER_CLK_TIMER2, "u0_si5_timer_clk_timer2",
- 0, JH7110_OSC),
+ CLK_IGNORE_UNUSED, JH7110_OSC),
JH7110_GATE(JH7110_TIMER_CLK_TIMER3, "u0_si5_timer_clk_timer3",
- 0, JH7110_OSC),
+ CLK_IGNORE_UNUSED, JH7110_OSC),
//TEMP SENSOR
JH7110_GATE(JH7110_TEMP_SENSOR_CLK_APB, "u0_temp_sensor_clk_apb",
0, JH7110_APB12),
#include <linux/can/led.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#define DRIVER_NAME "ipms_canfd"
#define XMIT_SEP_PRIO 2
#define XMIT_PTB_MODE 3
+enum IPMS_CAN_TYPE {
+ IPMS_CAN_TYPY_CAN = 0,
+ IPMS_CAN_TYPE_CANFD,
+};
+
struct ipms_canfd_priv {
struct can_priv can;
struct napi_struct napi;
struct device *dev;
+ struct regmap *reg_syscon;
void __iomem *reg_base;
- void __iomem *syscon_base;
u32 (*read_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg);
void (*write_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg, u32 val);
struct clk *can_clk;
- unsigned int tx_mode;
+ u32 tx_mode;
+ struct reset_control *resets;
struct clk_bulk_data *clks;
int nr_clks;
- struct reset_control_bulk_data *resets;
- int nr_rstcs;
- unsigned int syscon_offset;
- unsigned int syscon_mask;
- bool enable_canfd;
+ u32 can_or_canfd;
};
static struct can_bittiming_const canfd_bittiming_const = {
.brp_inc = 1,
};
-struct reset_control_bulk_data can_resets[] = {
- { .id = "rst_apb" },
- { .id = "rst_core" },
- { .id = "rst_timer" },
-};
-
-struct clk_bulk_data can_clks[] = {
- { .id = "apb_clk" },
- { .id = "core_clk" },
- { .id = "timer_clk" },
-};
-
static void canfd_write_reg_le(const struct ipms_canfd_priv *priv,
enum canfd_device_reg reg, u32 val)
{
priv->write_reg(priv, CANFD_S_SEG_1_OFFSET, bittiming_temp);
- if (priv->enable_canfd) {
+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
dat_bittiming = ((dbt->phase_seg1 + dbt->prop_seg + 1 - 2) << SEG_1_SHIFT) |
((dbt->phase_seg2 - 1) << SEG_2_SHIFT) |
((dbt->sjw - 1) << SJW_SHIFT) |
ctl = can_fd_len2dlc(cf->len);
/* transmit can fd frame */
- if (priv->enable_canfd) {
+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
if (can_is_canfd_skb(skb)) {
if (cf->can_id & CAN_EFF_FLAG)
ctl |= CAN_FD_SET_IDE_MASK;
/* Register interrupt handler */
ret = request_irq(ndev->irq, canfd_interrupt, IRQF_SHARED, ndev->name, ndev);
if (ret) {
- netdev_err(ndev, "request_irq err: %d\n", ret);
+ netdev_err(ndev, "Request_irq err: %d\n", ret);
goto exit_irq;
}
return ret;
}
-static int canfd_control_enable(struct ipms_canfd_priv *priv)
+static int canfd_control_parse_dt(struct ipms_canfd_priv *priv)
{
- u32 value;
-
- value = readl(priv->syscon_base + priv->syscon_offset);
- writel(value | priv->syscon_mask, priv->syscon_base + priv->syscon_offset);
-
- return 0;
-}
+ struct of_phandle_args args;
+ u32 syscon_mask, syscon_shift;
+ u32 can_or_canfd;
+ u32 syscon_offset, regval;
+ int ret;
-static int canfd_control_parse_dt(struct platform_device *pdev, struct ipms_canfd_priv *priv)
-{
- struct resource *res_syscon;
+ ret = of_parse_phandle_with_fixed_args(priv->dev->of_node,
+ "starfive,sys-syscon", 3, 0, &args);
+ if (ret) {
+ dev_err(priv->dev, "Failed to parse starfive,sys-syscon\n");
+ return -EINVAL;
+ }
- priv->enable_canfd = false;
- res_syscon = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sys_syscon");
- priv->syscon_base = ioremap(res_syscon->start, resource_size(res_syscon));
- if (IS_ERR(priv->syscon_base))
- return PTR_ERR(priv->syscon_base);
+ priv->reg_syscon = syscon_node_to_regmap(args.np);
+ of_node_put(args.np);
+ if (IS_ERR(priv->reg_syscon))
+ return PTR_ERR(priv->reg_syscon);
- if (!(device_property_read_u32(priv->dev, "syscon,canfd-offset", &priv->syscon_offset)))
- priv->enable_canfd = true;
+ syscon_offset = args.args[0];
+ syscon_shift = args.args[1];
+ syscon_mask = args.args[2];
- if (!(device_property_read_u32(priv->dev, "syscon,canfd-mask", &priv->syscon_mask)))
- priv->enable_canfd = priv->enable_canfd && true;
+ ret = device_property_read_u32(priv->dev, "syscon,can_or_canfd", &can_or_canfd);
+ if (ret)
+ goto exit_parse;
- if (device_property_read_bool(priv->dev, "syscon,canfd-enable"))
- priv->enable_canfd = priv->enable_canfd && true;
- else
- priv->enable_canfd = priv->enable_canfd && false;
+ priv->can_or_canfd = can_or_canfd;
+ /* enable can2.0/canfd function */
+ regval = can_or_canfd << syscon_shift;
+ ret = regmap_update_bits(priv->reg_syscon, syscon_offset, syscon_mask, regval);
+ if (ret)
+ return ret;
return 0;
+exit_parse:
+ return ret;
}
static const struct net_device_ops canfd_netdev_ops = {
void __iomem *addr;
int ret;
- addr = devm_platform_ioremap_resource_byname(pdev, "reg_base");
+ addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(addr)) {
ret = PTR_ERR(addr);
goto exit;
priv = netdev_priv(ndev);
priv->dev = &pdev->dev;
- ret = canfd_control_parse_dt(pdev, priv);
+ ret = canfd_control_parse_dt(priv);
if (ret)
- goto exit;
-
- if (priv->enable_canfd)
- canfd_control_enable(priv);
-
- priv->clks = can_clks;
- priv->resets = can_resets;
- priv->nr_clks = ARRAY_SIZE(can_clks);
- priv->nr_rstcs = ARRAY_SIZE(can_resets);
- ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, priv->nr_rstcs, priv->resets);
- if (ret) {
- dev_err(priv->dev, "failed to get can reset controls\n");
goto free_exit;
- }
- ret = devm_clk_bulk_get(&pdev->dev, priv->nr_clks, priv->clks);
- if (ret) {
- dev_err(priv->dev, "failed to get can clk controls\n");
+ priv->nr_clks = devm_clk_bulk_get_all(priv->dev, &priv->clks);
+ if (priv->nr_clks < 0) {
+ dev_err(priv->dev, "Failed to get can clocks\n");
+ ret = -ENODEV;
goto free_exit;
}
ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
if (ret) {
- dev_err(priv->dev, "enable clk error.\n");
+ dev_err(priv->dev, "Failed to enable clocks\n");
goto free_exit;
}
- ret = reset_control_bulk_deassert(priv->nr_rstcs, priv->resets);
- if (ret) {
- dev_err(priv->dev, "deassert can error.\n");
+ priv->resets = devm_reset_control_array_get_exclusive(priv->dev);
+ if (IS_ERR(priv->resets)) {
+ ret = PTR_ERR(priv->resets);
+ dev_err(priv->dev, "Failed to get can resets");
goto clk_exit;
}
+ ret = reset_control_deassert(priv->resets);
+ if (ret)
+ goto clk_exit;
priv->can.bittiming_const = &canfd_bittiming_const;
priv->can.data_bittiming_const = &canfd_data_bittiming_const;
priv->can.do_set_mode = canfd_do_set_mode;
/* in user space the execution mode can be chosen */
- if (priv->enable_canfd)
+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD)
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_FD;
else
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK;
-
priv->reg_base = addr;
priv->write_reg = canfd_write_reg_le;
priv->read_reg = canfd_read_reg_le;
- priv->can_clk = devm_clk_get(&pdev->dev, "ipms_can_clk");
+ priv->can_clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(priv->can_clk)) {
dev_err(&pdev->dev, "Device clock not found.\n");
ret = PTR_ERR(priv->can_clk);
}
priv->can.clock.freq = clk_get_rate(priv->can_clk);
-
ndev->irq = platform_get_irq(pdev, 0);
/* we support local echo */
SET_NETDEV_DEV(ndev, &pdev->dev);
netif_napi_add(ndev, &priv->napi, canfd_rx_poll, 16);
-
ret = register_candev(ndev);
if (ret) {
dev_err(&pdev->dev, "Fail to register failed (err=%d)\n", ret);
return 0;
reset_exit:
- reset_control_bulk_assert(priv->nr_rstcs, priv->resets);
+ reset_control_assert(priv->resets);
clk_exit:
clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
free_exit:
- iounmap(priv->syscon_base);
free_candev(ndev);
exit:
return ret;
struct net_device *ndev = platform_get_drvdata(pdev);
struct ipms_canfd_priv *priv = netdev_priv(ndev);
- reset_control_bulk_assert(priv->nr_rstcs, priv->resets);
+ reset_control_assert(priv->resets);
clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
- iounmap(priv->syscon_base);
unregister_candev(ndev);
netif_napi_del(&priv->napi);
free_candev(ndev);