2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 #include <linux/can/platform/flexcan.h>
10 #include <linux/gpio.h>
11 #include <linux/irqchip.h>
12 #include <linux/of_gpio.h>
13 #include <linux/of_platform.h>
14 #include <linux/pm_opp.h>
15 #include <asm/mach/arch.h>
16 #include <asm/mach/map.h>
20 static struct flexcan_platform_data flexcan_pdata[2];
21 static int flexcan_en_gpio;
22 static int flexcan_stby_gpio;
23 static int flexcan0_en;
24 static int flexcan1_en;
25 static void mx6sx_flexcan_switch(void)
27 if (flexcan0_en || flexcan1_en) {
28 gpio_set_value_cansleep(flexcan_en_gpio, 0);
29 gpio_set_value_cansleep(flexcan_stby_gpio, 0);
30 gpio_set_value_cansleep(flexcan_en_gpio, 1);
31 gpio_set_value_cansleep(flexcan_stby_gpio, 1);
34 * avoid to disable CAN xcvr if any of the CAN interfaces
35 * are down. XCRV will be disabled only if both CAN2
36 * interfaces are DOWN.
38 gpio_set_value_cansleep(flexcan_en_gpio, 0);
39 gpio_set_value_cansleep(flexcan_stby_gpio, 0);
43 static void imx6sx_arm2_flexcan0_switch(int enable)
46 mx6sx_flexcan_switch();
49 static void imx6sx_arm2_flexcan1_switch(int enable)
52 mx6sx_flexcan_switch();
55 static int __init imx6sx_arm2_flexcan_fixup(void)
57 struct device_node *np;
59 np = of_find_node_by_path("/soc/aips-bus@02000000/can@02090000");
63 flexcan_en_gpio = of_get_named_gpio(np, "trx-en-gpio", 0);
64 flexcan_stby_gpio = of_get_named_gpio(np, "trx-stby-gpio", 0);
65 if (gpio_is_valid(flexcan_en_gpio) && gpio_is_valid(flexcan_stby_gpio) &&
66 !gpio_request_one(flexcan_en_gpio, GPIOF_DIR_OUT, "flexcan-trx-en") &&
67 !gpio_request_one(flexcan_stby_gpio, GPIOF_DIR_OUT, "flexcan-trx-stby")) {
68 /* flexcan 0 & 1 are using the same GPIOs for transceiver */
69 flexcan_pdata[0].transceiver_switch = imx6sx_arm2_flexcan0_switch;
70 flexcan_pdata[1].transceiver_switch = imx6sx_arm2_flexcan1_switch;
76 /* Add auxdata to pass platform data */
77 static const struct of_dev_auxdata imx6sx_auxdata_lookup[] __initconst = {
78 OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02090000, NULL, &flexcan_pdata[0]),
79 OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02094000, NULL, &flexcan_pdata[1]),
83 static void __init imx6sx_init_machine(void)
85 struct device *parent;
87 mxc_arch_reset_init_dt();
89 parent = imx_soc_device_init();
91 pr_warn("failed to initialize soc device\n");
93 of_platform_populate(NULL, of_default_bus_match_table,
94 imx6sx_auxdata_lookup, parent);
100 static void __init imx6sx_init_irq(void)
102 imx_init_revision_from_anatop();
109 static const char *imx6sx_dt_compat[] __initdata = {
114 static void __init imx6sx_opp_init(struct device *cpu_dev)
116 struct device_node *np;
118 np = of_find_node_by_path("/cpus/cpu@0");
120 pr_warn("failed to find cpu0 node\n");
124 cpu_dev->of_node = np;
125 if (of_init_opp_table(cpu_dev))
126 pr_warn("failed to init OPP table\n");
131 static struct platform_device imx6sx_cpufreq_pdev = {
132 .name = "imx6q-cpufreq",
135 static void __init imx6sx_init_late(void)
137 if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
138 imx6sx_opp_init(&imx6sx_cpufreq_pdev.dev);
139 platform_device_register(&imx6sx_cpufreq_pdev);
142 if (of_machine_is_compatible("fsl,imx6sx-sdb"))
143 imx6sx_arm2_flexcan_fixup();
146 DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)")
147 .map_io = debug_ll_io_init,
148 .init_irq = imx6sx_init_irq,
149 .init_machine = imx6sx_init_machine,
150 .init_late = imx6sx_init_late,
151 .dt_compat = imx6sx_dt_compat,
152 .restart = mxc_restart,