]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/arm/mach-imx/mach-imx6sx.c
ENGR00302227-8 dts: imx6sx-sdb: add flexcan support
[karo-tx-linux.git] / arch / arm / mach-imx / mach-imx6sx.c
1 /*
2  * Copyright (C) 2014 Freescale Semiconductor, Inc.
3  *
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.
7  */
8
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>
17
18 #include "common.h"
19
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)
26 {
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);
32         } else {
33                 /*
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.
37                 */
38                 gpio_set_value_cansleep(flexcan_en_gpio, 0);
39                 gpio_set_value_cansleep(flexcan_stby_gpio, 0);
40         }
41 }
42
43 static void imx6sx_arm2_flexcan0_switch(int enable)
44 {
45         flexcan0_en = enable;
46         mx6sx_flexcan_switch();
47 }
48
49 static void imx6sx_arm2_flexcan1_switch(int enable)
50 {
51         flexcan1_en = enable;
52         mx6sx_flexcan_switch();
53 }
54
55 static int __init imx6sx_arm2_flexcan_fixup(void)
56 {
57         struct device_node *np;
58
59         np = of_find_node_by_path("/soc/aips-bus@02000000/can@02090000");
60         if (!np)
61                 return -ENODEV;
62
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;
71         }
72
73         return 0;
74 }
75
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]),
80         { /* sentinel */ }
81 };
82
83 static void __init imx6sx_init_machine(void)
84 {
85         struct device *parent;
86
87         mxc_arch_reset_init_dt();
88
89         parent = imx_soc_device_init();
90         if (parent == NULL)
91                 pr_warn("failed to initialize soc device\n");
92
93         of_platform_populate(NULL, of_default_bus_match_table,
94                                         imx6sx_auxdata_lookup, parent);
95
96         imx_anatop_init();
97         imx6sx_pm_init();
98 }
99
100 static void __init imx6sx_init_irq(void)
101 {
102         imx_init_revision_from_anatop();
103         imx_init_l2cache();
104         imx_src_init();
105         imx_gpc_init();
106         irqchip_init();
107 }
108
109 static const char *imx6sx_dt_compat[] __initdata = {
110         "fsl,imx6sx",
111         NULL,
112 };
113
114 static void __init imx6sx_opp_init(struct device *cpu_dev)
115 {
116         struct device_node *np;
117
118         np = of_find_node_by_path("/cpus/cpu@0");
119         if (!np) {
120                 pr_warn("failed to find cpu0 node\n");
121                 return;
122         }
123
124         cpu_dev->of_node = np;
125         if (of_init_opp_table(cpu_dev))
126                 pr_warn("failed to init OPP table\n");
127
128         of_node_put(np);
129 }
130
131 static struct platform_device imx6sx_cpufreq_pdev = {
132         .name = "imx6q-cpufreq",
133 };
134
135 static void __init imx6sx_init_late(void)
136 {
137         if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
138                 imx6sx_opp_init(&imx6sx_cpufreq_pdev.dev);
139                 platform_device_register(&imx6sx_cpufreq_pdev);
140         }
141
142         if (of_machine_is_compatible("fsl,imx6sx-sdb"))
143                 imx6sx_arm2_flexcan_fixup();
144 }
145
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,
153 MACHINE_END