diff options
author | Koen Kooi <koen@dominion.thruhere.net> | 2011-11-10 15:43:47 +0100 |
---|---|---|
committer | Koen Kooi <koen@dominion.thruhere.net> | 2011-11-10 15:43:47 +0100 |
commit | 7915ef6f0e44e3368d9add842f4c2cd5d56d2e29 (patch) | |
tree | c51507b088b6df056aac2799391165dd77355942 /recipes-kernel | |
parent | 0839c9df6a553b09fa08faf560857c0add5faffd (diff) | |
download | meta-ti-7915ef6f0e44e3368d9add842f4c2cd5d56d2e29.tar.gz |
linux-ti335x-psp 3.1: add CAN bus patches
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
Diffstat (limited to 'recipes-kernel')
8 files changed, 2320 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/beaglebone/defconfig b/recipes-kernel/linux/linux-ti33x-psp-3.1/beaglebone/defconfig index 22227337..f1a014cb 100644 --- a/recipes-kernel/linux/linux-ti33x-psp-3.1/beaglebone/defconfig +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/beaglebone/defconfig | |||
@@ -786,6 +786,8 @@ CONFIG_CAN_TI_HECC=m | |||
786 | # CONFIG_CAN_MCP251X is not set | 786 | # CONFIG_CAN_MCP251X is not set |
787 | # CONFIG_CAN_SJA1000 is not set | 787 | # CONFIG_CAN_SJA1000 is not set |
788 | # CONFIG_CAN_C_CAN is not set | 788 | # CONFIG_CAN_C_CAN is not set |
789 | CONFIG_CAN_D_CAN=m | ||
790 | CONFIG_CAN_D_CAN_PLATFORM=m | ||
789 | 791 | ||
790 | # | 792 | # |
791 | # CAN USB interfaces | 793 | # CAN USB interfaces |
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch new file mode 100644 index 00000000..79bac4eb --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch | |||
@@ -0,0 +1,1839 @@ | |||
1 | From 7fedac525f38a0b47d27d959d1325945d188d787 Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Sun, 6 Nov 2011 13:56:35 +0530 | ||
4 | Subject: [PATCH 1/7] can: d_can: Added support for Bosch D_CAN controller | ||
5 | |||
6 | Bosch D_CAN controller is a full-CAN implementation which is compliant | ||
7 | to CAN protocol version 2.0 part A and B. Bosch D_CAN user manual can be | ||
8 | obtained from: | ||
9 | |||
10 | http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/d_can_users_manual_111.pdf | ||
11 | |||
12 | This patch adds the support for this controller. | ||
13 | The following are the design choices made while writing the controller | ||
14 | driver: | ||
15 | 1. Interface Register set IF1 has be used for transmit and IF2 is used for | ||
16 | receive message objects. | ||
17 | 2. Out of the total Message objects available, half of it are kept aside for RX | ||
18 | purposes and the rest for TX purposes. | ||
19 | 3. NAPI implementation is such that both the TX and RX paths functions | ||
20 | in polling mode. | ||
21 | |||
22 | This patch adds the dcan driver support to am335x chip. | ||
23 | |||
24 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
25 | --- | ||
26 | drivers/net/can/Kconfig | 2 + | ||
27 | drivers/net/can/Makefile | 1 + | ||
28 | drivers/net/can/d_can/Kconfig | 14 + | ||
29 | drivers/net/can/d_can/Makefile | 8 + | ||
30 | drivers/net/can/d_can/d_can.c | 1336 ++++++++++++++++++++++++++++++++ | ||
31 | drivers/net/can/d_can/d_can.h | 67 ++ | ||
32 | drivers/net/can/d_can/d_can_platform.c | 256 ++++++ | ||
33 | include/linux/can/platform/d_can.h | 53 ++ | ||
34 | 8 files changed, 1737 insertions(+), 0 deletions(-) | ||
35 | create mode 100644 drivers/net/can/d_can/Kconfig | ||
36 | create mode 100644 drivers/net/can/d_can/Makefile | ||
37 | create mode 100644 drivers/net/can/d_can/d_can.c | ||
38 | create mode 100644 drivers/net/can/d_can/d_can.h | ||
39 | create mode 100644 drivers/net/can/d_can/d_can_platform.c | ||
40 | create mode 100644 include/linux/can/platform/d_can.h | ||
41 | |||
42 | diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig | ||
43 | index f6c98fb..6851445 100644 | ||
44 | --- a/drivers/net/can/Kconfig | ||
45 | +++ b/drivers/net/can/Kconfig | ||
46 | @@ -116,6 +116,8 @@ source "drivers/net/can/sja1000/Kconfig" | ||
47 | |||
48 | source "drivers/net/can/c_can/Kconfig" | ||
49 | |||
50 | +source "drivers/net/can/d_can/Kconfig" | ||
51 | + | ||
52 | source "drivers/net/can/usb/Kconfig" | ||
53 | |||
54 | source "drivers/net/can/softing/Kconfig" | ||
55 | diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile | ||
56 | index 24ebfe8..3377679 100644 | ||
57 | --- a/drivers/net/can/Makefile | ||
58 | +++ b/drivers/net/can/Makefile | ||
59 | @@ -14,6 +14,7 @@ obj-y += softing/ | ||
60 | obj-$(CONFIG_CAN_SJA1000) += sja1000/ | ||
61 | obj-$(CONFIG_CAN_MSCAN) += mscan/ | ||
62 | obj-$(CONFIG_CAN_C_CAN) += c_can/ | ||
63 | +obj-$(CONFIG_CAN_D_CAN) += d_can/ | ||
64 | obj-$(CONFIG_CAN_AT91) += at91_can.o | ||
65 | obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o | ||
66 | obj-$(CONFIG_CAN_MCP251X) += mcp251x.o | ||
67 | diff --git a/drivers/net/can/d_can/Kconfig b/drivers/net/can/d_can/Kconfig | ||
68 | new file mode 100644 | ||
69 | index 0000000..e5e9dcf | ||
70 | --- /dev/null | ||
71 | +++ b/drivers/net/can/d_can/Kconfig | ||
72 | @@ -0,0 +1,14 @@ | ||
73 | +menuconfig CAN_D_CAN | ||
74 | + tristate "Bosch D_CAN devices" | ||
75 | + depends on CAN_DEV && HAS_IOMEM | ||
76 | + | ||
77 | +if CAN_D_CAN | ||
78 | + | ||
79 | +config CAN_D_CAN_PLATFORM | ||
80 | + tristate "Generic Platform Bus based D_CAN driver" | ||
81 | + ---help--- | ||
82 | + This driver adds support for the D_CAN chips connected to | ||
83 | + the "platform bus" (Linux abstraction for directly to the | ||
84 | + processor attached devices) which can be found on am335x | ||
85 | + and dm814x boards from TI (http://www.ti.com). | ||
86 | +endif | ||
87 | diff --git a/drivers/net/can/d_can/Makefile b/drivers/net/can/d_can/Makefile | ||
88 | new file mode 100644 | ||
89 | index 0000000..80560c5 | ||
90 | --- /dev/null | ||
91 | +++ b/drivers/net/can/d_can/Makefile | ||
92 | @@ -0,0 +1,8 @@ | ||
93 | +# | ||
94 | +# Makefile for the Bosch D_CAN controller drivers. | ||
95 | +# | ||
96 | + | ||
97 | +obj-$(CONFIG_CAN_D_CAN) += d_can.o | ||
98 | +obj-$(CONFIG_CAN_D_CAN_PLATFORM) += d_can_platform.o | ||
99 | + | ||
100 | +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG | ||
101 | diff --git a/drivers/net/can/d_can/d_can.c b/drivers/net/can/d_can/d_can.c | ||
102 | new file mode 100644 | ||
103 | index 0000000..e001db0 | ||
104 | --- /dev/null | ||
105 | +++ b/drivers/net/can/d_can/d_can.c | ||
106 | @@ -0,0 +1,1336 @@ | ||
107 | +/* | ||
108 | + * CAN bus driver for Bosch D_CAN controller | ||
109 | + * | ||
110 | + * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/ | ||
111 | + * Anil Kumar Ch <anilkumar@ti.com> | ||
112 | + * | ||
113 | + * Base taken from C_CAN driver | ||
114 | + * Copyright (C) 2010 ST Microelectronics | ||
115 | + * - Bhupesh Sharma <bhupesh.sharma@st.com> | ||
116 | + * | ||
117 | + * Borrowed heavily from the C_CAN driver originally written by: | ||
118 | + * Copyright (C) 2007 | ||
119 | + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> | ||
120 | + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> | ||
121 | + * | ||
122 | + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B. | ||
123 | + * Bosch D_CAN user manual can be obtained from: | ||
124 | + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/ | ||
125 | + * d_can_users_manual_111.pdf | ||
126 | + * | ||
127 | + * This program is free software; you can redistribute it and/or | ||
128 | + * modify it under the terms of the GNU General Public License as | ||
129 | + * published by the Free Software Foundation version 2. | ||
130 | + * | ||
131 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
132 | + * kind, whether express or implied; without even the implied warranty | ||
133 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
134 | + * GNU General Public License for more details. | ||
135 | + */ | ||
136 | + | ||
137 | +#include <linux/kernel.h> | ||
138 | +#include <linux/module.h> | ||
139 | +#include <linux/interrupt.h> | ||
140 | +#include <linux/delay.h> | ||
141 | +#include <linux/netdevice.h> | ||
142 | +#include <linux/if_arp.h> | ||
143 | +#include <linux/if_ether.h> | ||
144 | +#include <linux/list.h> | ||
145 | +#include <linux/io.h> | ||
146 | + | ||
147 | +#include <linux/can.h> | ||
148 | +#include <linux/can/dev.h> | ||
149 | +#include <linux/can/error.h> | ||
150 | + | ||
151 | +#include "d_can.h" | ||
152 | + | ||
153 | +/* TI D_CAN module registers */ | ||
154 | +#define D_CAN_CTL 0x0 /* CAN control register */ | ||
155 | +#define D_CAN_ES 0x4 /* Error and status */ | ||
156 | +#define D_CAN_PEEOI_REG 0x4 /* Parity error EOI */ | ||
157 | +#define D_CAN_ERRC 0x8 /* Error counter */ | ||
158 | +#define D_CAN_BTR 0xC /* Bit timing */ | ||
159 | +#define D_CAN_INT 0x10 /* Interrupt register */ | ||
160 | +#define D_CAN_TEST 0x14 /* Test register */ | ||
161 | +#define D_CAN_PERR 0x1C /* Parity Error Code */ | ||
162 | +#define D_CAN_ABOTR 0x80 /* Auto-Bus-On Time */ | ||
163 | +#define D_CAN_TXRQ_X 0x84 /* Transmission Request X */ | ||
164 | +#define D_CAN_TXRQ(n) (0x88 + (n * 4)) /* Transmission request */ | ||
165 | +#define D_CAN_NWDAT_X 0x98 /* New data X register */ | ||
166 | +#define D_CAN_NWDAT(n) (0x9C + (n * 4)) /* New data */ | ||
167 | +#define D_CAN_INTPND_X 0xAC /* Interrupt Pending X */ | ||
168 | +#define D_CAN_INTPND(n) (0xB0 + (n * 4)) /* Interrupt Pending */ | ||
169 | +#define D_CAN_MSGVAL_X 0xC0 /* Message Valid X */ | ||
170 | +#define D_CAN_MSGVAL(n) (0xC4 + (n * 4)) /* Message Valid */ | ||
171 | +#define D_CAN_INTMUX(n) (0xD8 + (n * 4)) /* Interrupt Multiplexer */ | ||
172 | +#define D_CAN_IFCMD(n) (0x100 + (n * 0x20)) /* Command */ | ||
173 | +#define D_CAN_IFMSK(n) (0x104 + (n * 0x20)) /* Mask */ | ||
174 | +#define D_CAN_IFARB(n) (0x108 + (n * 0x20)) /* Arbitration */ | ||
175 | +#define D_CAN_IFMCTL(n) (0x10c + (n * 0x20)) /* Message ctl */ | ||
176 | +#define D_CAN_IFDATA(n) (0x110 + (n * 0x20)) /* DATA A */ | ||
177 | +#define D_CAN_IFDATB(n) (0x114 + (n * 0x20)) /* DATA B */ | ||
178 | +#define D_CAN_IF3OBS 0x140 /* IF3 Observation */ | ||
179 | +#define D_CAN_IF3UPD(n) (0x160 + (n * 4)) /* Update enable */ | ||
180 | +#define D_CAN_TIOC 0x1E0 /* CAN TX IO Control */ | ||
181 | +#define D_CAN_RIOC 0x1E4 /* CAN RX IO Control */ | ||
182 | + | ||
183 | +/* Control register Bit fields */ | ||
184 | +#define D_CAN_CTL_WUBA BIT(26) /* Automatic wake-up on bus activity */ | ||
185 | +#define D_CAN_CTL_PDR BIT(24) /* Request for local low power mode */ | ||
186 | +#define D_CAN_CTL_DE3 BIT(20) /* Enable DMA request line for IF3 */ | ||
187 | +#define D_CAN_CTL_DE2 BIT(19) /* Enable DMA request line for IF2 */ | ||
188 | +#define D_CAN_CTL_DE1 BIT(18) /* Enable DMA request line for IF1 */ | ||
189 | +#define D_CAN_CTL_IE1 BIT(17) /* Interrupt line 1 enable */ | ||
190 | +#define D_CAN_CTL_INITDBG BIT(16) /* Init state for debug access */ | ||
191 | +#define D_CAN_CTL_SWR BIT(15) /* S/W reset enable */ | ||
192 | +#define D_CAN_CTL_PMD (0xF << 10) /* Parity on/off */ | ||
193 | +#define D_CAN_CTL_ABO BIT(9) /* Auto bus on enable */ | ||
194 | +#define D_CAN_CTL_IDS BIT(8) /* Interruption debug support enable */ | ||
195 | +#define D_CAN_CTL_TEST BIT(7) /* Test mode enable */ | ||
196 | +#define D_CAN_CTL_CCE BIT(6) /* Configuration change enable */ | ||
197 | +#define D_CAN_CTL_DISABLE_AR BIT(5) /* Disable automatic retransmission */ | ||
198 | +#define D_CAN_CTL_ENABLE_AR (0 << 5) | ||
199 | +#define D_CAN_CTL_EIE BIT(3) /* Error interrupt enable */ | ||
200 | +#define D_CAN_CTL_SIE BIT(2) /* Status change int enable */ | ||
201 | +#define D_CAN_CTL_IE0 BIT(1) /* Interrupt line 0 enable */ | ||
202 | +#define D_CAN_CTL_INIT BIT(0) /* D_CAN initialization mode */ | ||
203 | + | ||
204 | +/* D_CAN Error and Status and Parity Error EOI reg bit fields */ | ||
205 | +#define D_CAN_ES_PDA BIT(10) /* Local power-down ACK */ | ||
206 | +#define D_CAN_ES_WUP BIT(9) /* Wkae up pending */ | ||
207 | +#define D_CAN_ES_PER BIT(8) /* Parity error detected */ | ||
208 | +#define D_CAN_ES_BOFF BIT(7) /* Bus off state */ | ||
209 | +#define D_CAN_ES_EWARN BIT(6) /* Warning state */ | ||
210 | +#define D_CAN_ES_EPASS BIT(5) /* Error passive state */ | ||
211 | +#define D_CAN_ES_RXOK BIT(4) /* Received a msg successfully */ | ||
212 | +#define D_CAN_ES_TXOK BIT(3) /* Transmitted a msg successfully */ | ||
213 | +#define D_CAN_ES_LEC_MASK 0x7 /* Last error code */ | ||
214 | + | ||
215 | +/* Parity error reg bit fields */ | ||
216 | +#define D_CAN_PEEOI BIT(8) /* EOI indication for parity error */ | ||
217 | + | ||
218 | +/* Error counter reg bit fields */ | ||
219 | +#define D_CAN_ERRC_RP_SHIFT 15 | ||
220 | +#define D_CAN_ERRC_RP_MASK BIT(15) /* Receive error passive */ | ||
221 | +#define D_CAN_ERRC_REC_SHIFT 8 | ||
222 | +#define D_CAN_ERRC_REC_MASK (0x7F << 8) /* Receive err counter */ | ||
223 | +#define D_CAN_ERRC_TEC_SHIFT 0 | ||
224 | +#define D_CAN_ERRC_TEC_MASK (0xFF << 0) /* Transmit err counter */ | ||
225 | + | ||
226 | +/* Bit timing reg bit fields */ | ||
227 | +#define D_CAN_BTR_BRPE_SHIFT 16 | ||
228 | +#define D_CAN_BTR_BRPE_MASK (0xF << 16) /* Baud rate prescaler ext */ | ||
229 | +#define D_CAN_BTR_TSEG2_SHIFT 12 | ||
230 | +#define D_CAN_BTR_TSEG2_MASK (0x7 << 12) /* Time seg after smpl point */ | ||
231 | +#define D_CAN_BTR_TSEG1_SHIFT 8 | ||
232 | +#define D_CAN_BTR_TSEG1_MASK (0xF << 8) /* Time seg before smpl point */ | ||
233 | +#define D_CAN_BTR_SJW_SHIFT 6 | ||
234 | +#define D_CAN_BTR_SJW_MASK (0x3 << 6) /* Syncronization jump width */ | ||
235 | +#define D_CAN_BTR_BRP_SHIFT 0 | ||
236 | +#define D_CAN_BTR_BRP_MASK (0x3F << 0) /* Baud rate prescaler */ | ||
237 | + | ||
238 | +/* D_CAN Test register bit fields */ | ||
239 | +#define D_CAN_TEST_RDA BIT(9) /* RAM direct access enable */ | ||
240 | +#define D_CAN_TEST_EXL BIT(8) /* External loopback mode */ | ||
241 | +#define D_CAN_TEST_RX BIT(7) /* Monitors the reveive pin */ | ||
242 | +#define D_CAN_TEST_TX (0x3 << 5) /* Control of CAN_TX pin */ | ||
243 | +#define D_CAN_TEST_LBACK BIT(4) /* Loopback mode */ | ||
244 | +#define D_CAN_TEST_SILENT BIT(3) /* Silent mdoe */ | ||
245 | + | ||
246 | +/* D_CAN Parity error reg bit fields */ | ||
247 | +#define D_CAN_PERR_WN_MASK (0x7 << 8) /* Parity error word nuber */ | ||
248 | +#define D_CAN_PERR_MN_MASK 0xFF /* Parity error msg object */ | ||
249 | + | ||
250 | +/* D_CAN X registers bit fields */ | ||
251 | +#define D_CAN_BIT_FIELD(n) (0x3 << (2 * n)) /* X reg's bit field 1 mask */ | ||
252 | + | ||
253 | +/* D_CAN IF command reg bit fields */ | ||
254 | +#define D_CAN_IF_CMD_WR BIT(23) /* Write/read */ | ||
255 | +#define D_CAN_IF_CMD_MASK BIT(22) /* Access mask bits */ | ||
256 | +#define D_CAN_IF_CMD_ARB BIT(21) /* Access arbitration bits */ | ||
257 | +#define D_CAN_IF_CMD_CONTROL BIT(20) /* Acess control bits */ | ||
258 | +#define D_CAN_IF_CMD_CIP BIT(19) /* Clear int pending */ | ||
259 | +#define D_CAN_IF_CMD_TXRQST BIT(18) /* Access transmission request */ | ||
260 | +#define D_CAN_IF_CMD_DATAA BIT(17) /* Access Data Bytes 0-3 */ | ||
261 | +#define D_CAN_IF_CMD_DATAB BIT(16) /* Access Data Bytes 4-7 */ | ||
262 | +#define D_CAN_IF_CMD_BUSY BIT(15) /* Busy flag */ | ||
263 | +#define D_CAN_IF_CMD_DAM BIT(14) /* Activation of DMA */ | ||
264 | +#define D_CAN_IF_CMD_MN_MASK 0xFF /* No. of msg's used for DMA T/F */ | ||
265 | +#define D_CAN_IF_CMD_ALL (D_CAN_IF_CMD_MASK | D_CAN_IF_CMD_ARB | \ | ||
266 | + D_CAN_IF_CMD_CONTROL | D_CAN_IF_CMD_TXRQST | \ | ||
267 | + D_CAN_IF_CMD_DATAA | D_CAN_IF_CMD_DATAB) | ||
268 | + | ||
269 | +/* D_CAN IF mask reg bit fields */ | ||
270 | +#define D_CAN_IF_MASK_MX BIT(31) /* Mask Extended Identifier */ | ||
271 | +#define D_CAN_IF_MASK_MD BIT(30) /* Mask Message direction */ | ||
272 | + | ||
273 | +/* D_CAN IF Arbitration */ | ||
274 | +#define D_CAN_IF_ARB_MSGVAL BIT(31) /* Message Vaild */ | ||
275 | +#define D_CAN_IF_ARB_MSGXTD BIT(30) /* Extended Identifier 0-11 1-29 */ | ||
276 | +#define D_CAN_IF_ARB_DIR_XMIT BIT(29) /* Message direction 0-R 1-T */ | ||
277 | + | ||
278 | +/* D_CAN IF Message control */ | ||
279 | +#define D_CAN_IF_MCTL_NEWDAT BIT(15) /* New data available */ | ||
280 | +#define D_CAN_IF_MCTL_MSGLST BIT(14) /* Message lost, only for receive */ | ||
281 | +#define D_CAN_IF_MCTL_CLR_MSGLST (0 << 14) | ||
282 | +#define D_CAN_IF_MCTL_INTPND BIT(13) /* Interrupt pending */ | ||
283 | +#define D_CAN_IF_MCTL_UMASK BIT(12) /* Use acceptance mask */ | ||
284 | +#define D_CAN_IF_MCTL_TXIE BIT(11) /* Transmit int enable */ | ||
285 | +#define D_CAN_IF_MCTL_RXIE BIT(10) /* Receive int enable */ | ||
286 | +#define D_CAN_IF_MCTL_RMTEN BIT(9) /* Remote enable */ | ||
287 | +#define D_CAN_IF_MCTL_TXRQST BIT(8) /* Transmit request */ | ||
288 | +#define D_CAN_IF_MCTL_EOB BIT(7) /* Data frames */ | ||
289 | +#define D_CAN_IF_MCTL_DLC_MASK 0xF /* Data length code */ | ||
290 | + | ||
291 | +/* D_CAN IF3 Observation reg bit fields */ | ||
292 | +#define D_CAN_IF3OBS_UP BIT(15) /* Update data status */ | ||
293 | +#define D_CAN_IF3OBS_SDB BIT(12) /* DataB read out status */ | ||
294 | +#define D_CAN_IF3OBS_SDA BIT(11) /* DataA read out status */ | ||
295 | +#define D_CAN_IF3OBS_SC BIT(10) /* Contol bits read out status */ | ||
296 | +#define D_CAN_IF3OBS_SA BIT(9) /* Arbitration read out status */ | ||
297 | +#define D_CAN_IF3OBS_SM BIT(8) /* Mask bits read out status */ | ||
298 | +#define D_CAN_IF3OBS_DB BIT(4) /* Data B read observation */ | ||
299 | +#define D_CAN_IF3OBS_DA BIT(3) /* Data A read observation */ | ||
300 | +#define D_CAN_IF3OBS_CTL BIT(2) /* Control read observation */ | ||
301 | +#define D_CAN_IF3OBS_ARB BIT(1) /* Arbitration data read observation */ | ||
302 | +#define D_CAN_IF3OBS_MASK BIT(0) /* Mask data read observation */ | ||
303 | + | ||
304 | +/* D_CAN TX I/O reg bit fields */ | ||
305 | +#define D_CAN_TIOC_PU BIT(18) /* CAN_TX pull up/down select */ | ||
306 | +#define D_CAN_TIOC_PD BIT(17) /* CAN_TX pull disable */ | ||
307 | +#define D_CAN_TIOC_OD BIT(16) /* CAN_TX open drain enable */ | ||
308 | +#define D_CAN_TIOC_FUNC BIT(3) /* CAN_TX function */ | ||
309 | +#define D_CAN_TIOC_DIR BIT(2) /* CAN_TX data direction */ | ||
310 | +#define D_CAN_TIOC_OUT BIT(1) /* CAN_TX data out write */ | ||
311 | +#define D_CAN_TIOC_IN BIT(0) /* CAN_TX data in */ | ||
312 | + | ||
313 | +/* D_CAN RX I/O reg bit fields */ | ||
314 | +#define D_CAN_RIOC_PU BIT(18) /* CAN_RX pull up/down select */ | ||
315 | +#define D_CAN_RIOC_PD BIT(17) /* CAN_RX pull disable */ | ||
316 | +#define D_CAN_RIOC_OD BIT(16) /* CAN_RX open drain enable */ | ||
317 | +#define D_CAN_RIOC_FUNC BIT(3) /* CAN_RX function */ | ||
318 | +#define D_CAN_RIOC_DIR BIT(2) /* CAN_RX data direction */ | ||
319 | +#define D_CAN_RIOC_OUT BIT(1) /* CAN_RX data out write */ | ||
320 | +#define D_CAN_RTIOC_IN BIT(0) /* CAN_RX data in */ | ||
321 | + | ||
322 | +#define D_CAN_SET_REG 0xFFFFFFFF | ||
323 | + | ||
324 | +#define D_CAN_CANMID_IDE BIT(31) /* Extended frame format */ | ||
325 | +#define D_CAN_CANMID_AME BIT(30) /* Acceptance mask enable */ | ||
326 | +#define D_CAN_CANMID_AAM BIT(29) /* Auto answer mode */ | ||
327 | + | ||
328 | +/* | ||
329 | + * IF register masks: | ||
330 | + */ | ||
331 | +#define IFX_WRITE_IDR(x) ((x) & 0x1FFFFFFF) | ||
332 | + | ||
333 | +#define IFX_CMD_BITS(x) ((x) & 0xFFFFFF00) | ||
334 | +#define IFX_CMD_MSG_NUMBER(x) ((x) & 0xFF) | ||
335 | + | ||
336 | +/* message object split */ | ||
337 | +#define D_CAN_NUM_OF_OBJECTS 64 | ||
338 | +#define D_CAN_MSG_OBJ_RX_NUM 32 | ||
339 | +#define D_CAN_MSG_OBJ_TX_NUM 32 | ||
340 | + | ||
341 | +#define D_CAN_MSG_OBJ_RX_FIRST 1 | ||
342 | +#define D_CAN_MSG_OBJ_RX_LAST (D_CAN_MSG_OBJ_RX_FIRST + \ | ||
343 | + D_CAN_MSG_OBJ_RX_NUM - 1) | ||
344 | + | ||
345 | +#define D_CAN_MSG_OBJ_TX_FIRST (D_CAN_MSG_OBJ_RX_LAST + 1) | ||
346 | +#define D_CAN_MSG_OBJ_TX_LAST (D_CAN_MSG_OBJ_TX_FIRST + \ | ||
347 | + D_CAN_MSG_OBJ_TX_NUM - 1) | ||
348 | + | ||
349 | +#define D_CAN_MSG_OBJ_RX_SPLIT 17 | ||
350 | +#define D_CAN_MSG_OBJ_RX_LOW_LAST (D_CAN_MSG_OBJ_RX_SPLIT - 1) | ||
351 | + | ||
352 | +#define D_CAN_NEXT_MSG_OBJ_MASK (D_CAN_MSG_OBJ_TX_NUM - 1) | ||
353 | + | ||
354 | +/* status interrupt */ | ||
355 | +#define STATUS_INTERRUPT 0x8000 | ||
356 | + | ||
357 | +/* global interrupt masks */ | ||
358 | +#define ENABLE_ALL_INTERRUPTS 1 | ||
359 | +#define DISABLE_ALL_INTERRUPTS 0 | ||
360 | + | ||
361 | +/* minimum timeout for checking BUSY status */ | ||
362 | +#define MIN_TIMEOUT_VALUE 6 | ||
363 | + | ||
364 | +/* Wait for ~1 sec for INIT bit */ | ||
365 | +#define D_CAN_WAIT_COUNT 100 | ||
366 | + | ||
367 | +#define D_CAN_IF_RX_NUM 0 | ||
368 | +#define D_CAN_IF_TX_NUM 1 | ||
369 | + | ||
370 | +#define D_CAN_GET_XREG_NUM(priv, reg) (__ffs(d_can_read(priv, reg))/4) | ||
371 | + | ||
372 | +/* CAN Bittiming constants as per D_CAN specs */ | ||
373 | +static struct can_bittiming_const d_can_bittiming_const = { | ||
374 | + .name = D_CAN_DRV_NAME, | ||
375 | + .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ | ||
376 | + .tseg1_max = 16, | ||
377 | + .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ | ||
378 | + .tseg2_max = 8, | ||
379 | + .sjw_max = 4, | ||
380 | + .brp_min = 1, | ||
381 | + .brp_max = 1024, /* 6-bit BRP field + 4-bit BRPE field*/ | ||
382 | + .brp_inc = 1, | ||
383 | +}; | ||
384 | + | ||
385 | +/* d_can lec values */ | ||
386 | +enum d_can_lec_type { | ||
387 | + LEC_NO_ERROR = 0, | ||
388 | + LEC_STUFF_ERROR, | ||
389 | + LEC_FORM_ERROR, | ||
390 | + LEC_ACK_ERROR, | ||
391 | + LEC_BIT1_ERROR, | ||
392 | + LEC_BIT0_ERROR, | ||
393 | + LEC_CRC_ERROR, | ||
394 | + LEC_UNUSED, | ||
395 | +}; | ||
396 | + | ||
397 | +/* | ||
398 | + * d_can error types: | ||
399 | + * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported | ||
400 | + */ | ||
401 | +enum d_can_bus_error_types { | ||
402 | + D_CAN_NO_ERROR = 0, | ||
403 | + D_CAN_BUS_OFF, | ||
404 | + D_CAN_ERROR_WARNING, | ||
405 | + D_CAN_ERROR_PASSIVE, | ||
406 | +}; | ||
407 | + | ||
408 | +static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val) | ||
409 | +{ | ||
410 | + __raw_writel(val, priv->base + reg); | ||
411 | +} | ||
412 | + | ||
413 | +static inline u32 d_can_read(struct d_can_priv *priv, int reg) | ||
414 | +{ | ||
415 | + return __raw_readl(priv->base + reg); | ||
416 | +} | ||
417 | + | ||
418 | +static inline void d_can_set_bit(struct d_can_priv *priv, int reg, | ||
419 | + u32 bit_mask) | ||
420 | +{ | ||
421 | + d_can_write(priv, reg, d_can_read(priv, reg) | bit_mask); | ||
422 | +} | ||
423 | + | ||
424 | +static inline u32 d_can_get_bit(struct d_can_priv *priv, int reg, | ||
425 | + u32 bit_mask) | ||
426 | +{ | ||
427 | + return (d_can_read(priv, reg) & bit_mask) ? 1 : 0; | ||
428 | +} | ||
429 | + | ||
430 | +static inline void d_can_clear_bit(struct d_can_priv *priv, int reg, | ||
431 | + u32 bit_mask) | ||
432 | +{ | ||
433 | + d_can_write(priv, reg, d_can_read(priv, reg) & ~bit_mask); | ||
434 | +} | ||
435 | + | ||
436 | +static inline int get_tx_next_msg_obj(const struct d_can_priv *priv) | ||
437 | +{ | ||
438 | + return (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) + | ||
439 | + D_CAN_MSG_OBJ_TX_FIRST; | ||
440 | +} | ||
441 | + | ||
442 | +static inline int get_tx_echo_msg_obj(const struct d_can_priv *priv) | ||
443 | +{ | ||
444 | + return (priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) + | ||
445 | + D_CAN_MSG_OBJ_TX_FIRST; | ||
446 | +} | ||
447 | + | ||
448 | +static void d_can_interrupts(struct d_can_priv *priv, int enable) | ||
449 | +{ | ||
450 | + unsigned int cntrl_save = d_can_read(priv, D_CAN_CTL); | ||
451 | + | ||
452 | + if (enable) | ||
453 | + cntrl_save |= (D_CAN_CTL_IE1 | D_CAN_CTL_EIE | | ||
454 | + D_CAN_CTL_IE0); | ||
455 | + else | ||
456 | + cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_SIE | | ||
457 | + D_CAN_CTL_EIE | D_CAN_CTL_IE0); | ||
458 | + | ||
459 | + d_can_write(priv, D_CAN_CTL, cntrl_save); | ||
460 | +} | ||
461 | + | ||
462 | +static inline int d_can_msg_obj_is_busy(struct d_can_priv *priv, int iface) | ||
463 | +{ | ||
464 | + int count = MIN_TIMEOUT_VALUE; | ||
465 | + | ||
466 | + while (count && d_can_read(priv, D_CAN_IFCMD(iface)) & | ||
467 | + D_CAN_IF_CMD_BUSY) { | ||
468 | + count--; | ||
469 | + udelay(1); | ||
470 | + } | ||
471 | + | ||
472 | + if (!count) | ||
473 | + return 1; | ||
474 | + | ||
475 | + return 0; | ||
476 | +} | ||
477 | + | ||
478 | +static inline void d_can_object_get(struct net_device *dev, | ||
479 | + int iface, int objno, int mask) | ||
480 | +{ | ||
481 | + struct d_can_priv *priv = netdev_priv(dev); | ||
482 | + | ||
483 | + /* | ||
484 | + * As per specs, after writting the message object number in the | ||
485 | + * IF command register the transfer b/w interface register and | ||
486 | + * message RAM must be complete in 12 CAN-CLK period. | ||
487 | + */ | ||
488 | + d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) | | ||
489 | + IFX_CMD_MSG_NUMBER(objno)); | ||
490 | + | ||
491 | + if (d_can_msg_obj_is_busy(priv, iface)) | ||
492 | + netdev_err(dev, "timed out in object get\n"); | ||
493 | +} | ||
494 | + | ||
495 | +static inline void d_can_object_put(struct net_device *dev, | ||
496 | + int iface, int objno, int mask) | ||
497 | +{ | ||
498 | + struct d_can_priv *priv = netdev_priv(dev); | ||
499 | + | ||
500 | + /* | ||
501 | + * As per specs, after writting the message object number in the | ||
502 | + * IF command request register the transfer b/w interface | ||
503 | + * register and message RAM must be complete in 12 CAN-CLK | ||
504 | + * period. | ||
505 | + */ | ||
506 | + d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR | | ||
507 | + IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno)); | ||
508 | + | ||
509 | + if (d_can_msg_obj_is_busy(priv, iface)) | ||
510 | + netdev_err(dev, "timed out in object put\n"); | ||
511 | +} | ||
512 | + | ||
513 | +static void d_can_write_msg_object(struct net_device *dev, | ||
514 | + int iface, struct can_frame *frame, int objno) | ||
515 | +{ | ||
516 | + int i; | ||
517 | + u32 flags = 0; | ||
518 | + unsigned int id; | ||
519 | + u32 dataA = 0; | ||
520 | + u32 dataB = 0; | ||
521 | + struct d_can_priv *priv = netdev_priv(dev); | ||
522 | + | ||
523 | + if (!(frame->can_id & CAN_RTR_FLAG)) | ||
524 | + flags |= D_CAN_IF_ARB_DIR_XMIT; | ||
525 | + | ||
526 | + if (frame->can_id & CAN_EFF_FLAG) { | ||
527 | + id = frame->can_id & CAN_EFF_MASK; | ||
528 | + flags |= D_CAN_IF_ARB_MSGXTD; | ||
529 | + } else | ||
530 | + id = ((frame->can_id & CAN_SFF_MASK) << 18); | ||
531 | + | ||
532 | + flags |= D_CAN_IF_ARB_MSGVAL; | ||
533 | + d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags); | ||
534 | + | ||
535 | + for (i = 0; i < frame->can_dlc; i++) { | ||
536 | + if (i < 4) | ||
537 | + dataA |= (frame->data[i] << (8 * i)); | ||
538 | + else | ||
539 | + dataB |= (frame->data[i] << (8 * (i - 4))); | ||
540 | + } | ||
541 | + | ||
542 | + /* DATA write to Message object registers DATAA and DATAB */ | ||
543 | + if (frame->can_dlc < 4) | ||
544 | + d_can_write(priv, D_CAN_IFDATA(iface), dataA); | ||
545 | + else { | ||
546 | + d_can_write(priv, D_CAN_IFDATB(iface), dataB); | ||
547 | + d_can_write(priv, D_CAN_IFDATA(iface), dataA); | ||
548 | + } | ||
549 | + | ||
550 | + /* enable interrupt for this message object */ | ||
551 | + d_can_write(priv, D_CAN_IFMCTL(iface), | ||
552 | + D_CAN_IF_MCTL_TXIE | D_CAN_IF_MCTL_EOB | | ||
553 | + D_CAN_IF_MCTL_TXRQST | D_CAN_IF_MCTL_NEWDAT | | ||
554 | + frame->can_dlc); | ||
555 | + | ||
556 | + /* Put message data into message RAM */ | ||
557 | + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL); | ||
558 | +} | ||
559 | + | ||
560 | +static inline void d_can_mark_rx_msg_obj(struct net_device *dev, | ||
561 | + int iface, int ctrl_mask, | ||
562 | + int obj) | ||
563 | +{ | ||
564 | + struct d_can_priv *priv = netdev_priv(dev); | ||
565 | + | ||
566 | + d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask | ||
567 | + & ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND)); | ||
568 | + | ||
569 | + d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL); | ||
570 | +} | ||
571 | + | ||
572 | +static inline void d_can_activate_all_lower_rx_msg_obj(struct net_device *dev, | ||
573 | + int iface, | ||
574 | + int ctrl_mask) | ||
575 | +{ | ||
576 | + int i; | ||
577 | + struct d_can_priv *priv = netdev_priv(dev); | ||
578 | + | ||
579 | + for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_MSG_OBJ_RX_LOW_LAST; i++) { | ||
580 | + d_can_write(priv, D_CAN_IFMCTL(iface), | ||
581 | + ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST | | ||
582 | + D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT)); | ||
583 | + d_can_object_put(dev, iface, i, D_CAN_IF_CMD_CONTROL); | ||
584 | + } | ||
585 | +} | ||
586 | + | ||
587 | +static inline void d_can_activate_rx_msg_obj(struct net_device *dev, | ||
588 | + int iface, int ctrl_mask, | ||
589 | + int obj) | ||
590 | +{ | ||
591 | + struct d_can_priv *priv = netdev_priv(dev); | ||
592 | + | ||
593 | + d_can_write(priv, D_CAN_IFMCTL(iface), | ||
594 | + ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST | | ||
595 | + D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT)); | ||
596 | + d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL); | ||
597 | +} | ||
598 | + | ||
599 | +static void d_can_handle_lost_msg_obj(struct net_device *dev, | ||
600 | + int iface, int objno) | ||
601 | +{ | ||
602 | + struct d_can_priv *priv = netdev_priv(dev); | ||
603 | + struct net_device_stats *stats = &dev->stats; | ||
604 | + struct sk_buff *skb; | ||
605 | + struct can_frame *frame; | ||
606 | + | ||
607 | + netdev_err(dev, "msg lost in buffer %d\n", objno); | ||
608 | + | ||
609 | + d_can_object_get(dev, iface, objno, D_CAN_IF_CMD_ALL & | ||
610 | + ~D_CAN_IF_CMD_TXRQST); | ||
611 | + | ||
612 | + d_can_write(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_CLR_MSGLST); | ||
613 | + | ||
614 | + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL); | ||
615 | + | ||
616 | + /* create an error msg */ | ||
617 | + skb = alloc_can_err_skb(dev, &frame); | ||
618 | + if (unlikely(!skb)) | ||
619 | + return; | ||
620 | + | ||
621 | + frame->can_id |= CAN_ERR_CRTL; | ||
622 | + frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | ||
623 | + stats->rx_errors++; | ||
624 | + stats->rx_over_errors++; | ||
625 | + | ||
626 | + netif_receive_skb(skb); | ||
627 | +} | ||
628 | + | ||
629 | +static int d_can_read_msg_object(struct net_device *dev, int iface, int ctrl) | ||
630 | +{ | ||
631 | + int i; | ||
632 | + u32 dataA = 0; | ||
633 | + u32 dataB = 0; | ||
634 | + unsigned int arb_val; | ||
635 | + unsigned int mctl_val; | ||
636 | + struct d_can_priv *priv = netdev_priv(dev); | ||
637 | + struct net_device_stats *stats = &dev->stats; | ||
638 | + struct sk_buff *skb; | ||
639 | + struct can_frame *frame; | ||
640 | + | ||
641 | + skb = alloc_can_skb(dev, &frame); | ||
642 | + if (!skb) { | ||
643 | + stats->rx_dropped++; | ||
644 | + return -ENOMEM; | ||
645 | + } | ||
646 | + | ||
647 | + frame->can_dlc = get_can_dlc(ctrl & 0x0F); | ||
648 | + | ||
649 | + arb_val = d_can_read(priv, D_CAN_IFARB(iface)); | ||
650 | + mctl_val = d_can_read(priv, D_CAN_IFMCTL(iface)); | ||
651 | + | ||
652 | + if (arb_val & D_CAN_IF_ARB_MSGXTD) | ||
653 | + frame->can_id = (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG; | ||
654 | + else | ||
655 | + frame->can_id = (arb_val >> 18) & CAN_SFF_MASK; | ||
656 | + | ||
657 | + if (mctl_val & D_CAN_IF_MCTL_RMTEN) | ||
658 | + frame->can_id |= CAN_RTR_FLAG; | ||
659 | + else { | ||
660 | + dataA = d_can_read(priv, D_CAN_IFDATA(iface)); | ||
661 | + dataB = d_can_read(priv, D_CAN_IFDATB(iface)); | ||
662 | + for (i = 0; i < frame->can_dlc; i++) { | ||
663 | + /* Writing MO higher 4 data bytes to skb */ | ||
664 | + if (i <= 3) | ||
665 | + frame->data[i] = dataA >> (8 * i); /* Lower */ | ||
666 | + if (i > 3) | ||
667 | + frame->data[i] = dataB >> (8 * (i-4)); | ||
668 | + } | ||
669 | + } | ||
670 | + | ||
671 | + netif_receive_skb(skb); | ||
672 | + | ||
673 | + stats->rx_packets++; | ||
674 | + stats->rx_bytes += frame->can_dlc; | ||
675 | + | ||
676 | + return 0; | ||
677 | +} | ||
678 | + | ||
679 | +static void d_can_setup_receive_object(struct net_device *dev, int iface, | ||
680 | + int objno, unsigned int mask, | ||
681 | + unsigned int id, unsigned int mcont) | ||
682 | +{ | ||
683 | + struct d_can_priv *priv = netdev_priv(dev); | ||
684 | + | ||
685 | + d_can_write(priv, D_CAN_IFMSK(iface), IFX_WRITE_IDR(mask)); | ||
686 | + d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | | ||
687 | + D_CAN_IF_ARB_MSGVAL); | ||
688 | + d_can_write(priv, D_CAN_IFMCTL(iface), mcont); | ||
689 | + | ||
690 | + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL & | ||
691 | + ~D_CAN_IF_CMD_TXRQST); | ||
692 | + | ||
693 | + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv, | ||
694 | + D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X)))); | ||
695 | +} | ||
696 | + | ||
697 | +static void d_can_inval_msg_object(struct net_device *dev, int iface, int objno) | ||
698 | +{ | ||
699 | + struct d_can_priv *priv = netdev_priv(dev); | ||
700 | + | ||
701 | + d_can_write(priv, D_CAN_IFARB(iface), 0); | ||
702 | + d_can_write(priv, D_CAN_IFMCTL(iface), 0); | ||
703 | + | ||
704 | + d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ARB | | ||
705 | + D_CAN_IF_CMD_CONTROL); | ||
706 | + | ||
707 | + netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv, | ||
708 | + D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X)))); | ||
709 | +} | ||
710 | + | ||
711 | +static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, int objno) | ||
712 | +{ | ||
713 | + u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X); | ||
714 | + | ||
715 | + /* | ||
716 | + * as transmission request register's bit n-1 corresponds to | ||
717 | + * message object n, we need to handle the same properly. | ||
718 | + */ | ||
719 | + if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) & | ||
720 | + (1 << (objno - 1))) | ||
721 | + return 1; | ||
722 | + | ||
723 | + return 0; | ||
724 | +} | ||
725 | + | ||
726 | +static netdev_tx_t d_can_start_xmit(struct sk_buff *skb, | ||
727 | + struct net_device *dev) | ||
728 | +{ | ||
729 | + u32 msg_obj_no; | ||
730 | + struct d_can_priv *priv = netdev_priv(dev); | ||
731 | + struct can_frame *frame = (struct can_frame *)skb->data; | ||
732 | + | ||
733 | + if (can_dropped_invalid_skb(dev, skb)) | ||
734 | + return NETDEV_TX_OK; | ||
735 | + | ||
736 | + msg_obj_no = get_tx_next_msg_obj(priv); | ||
737 | + | ||
738 | + /* prepare message object for transmission */ | ||
739 | + d_can_write_msg_object(dev, D_CAN_IF_TX_NUM, frame, msg_obj_no); | ||
740 | + can_put_echo_skb(skb, dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST); | ||
741 | + | ||
742 | + /* | ||
743 | + * we have to stop the queue in case of a wrap around or | ||
744 | + * if the next TX message object is still in use | ||
745 | + */ | ||
746 | + priv->tx_next++; | ||
747 | + if (d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) || | ||
748 | + (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) | ||
749 | + == 0) | ||
750 | + netif_stop_queue(dev); | ||
751 | + | ||
752 | + return NETDEV_TX_OK; | ||
753 | +} | ||
754 | + | ||
755 | +static int d_can_set_bittiming(struct net_device *dev) | ||
756 | +{ | ||
757 | + struct d_can_priv *priv = netdev_priv(dev); | ||
758 | + const struct can_bittiming *bt = &priv->can.bittiming; | ||
759 | + u32 can_btc; | ||
760 | + | ||
761 | + can_btc = ((bt->phase_seg2 - 1) & 0x7) << D_CAN_BTR_TSEG2_SHIFT; | ||
762 | + can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1) | ||
763 | + & 0xF) << D_CAN_BTR_TSEG1_SHIFT; | ||
764 | + | ||
765 | + can_btc |= ((bt->sjw - 1) & 0x3) << D_CAN_BTR_SJW_SHIFT; | ||
766 | + | ||
767 | + /* Ten bits contains the BRP, 6 bits for BRP and upper 4 bits for brpe*/ | ||
768 | + can_btc |= ((bt->brp - 1) & 0x3F) << D_CAN_BTR_BRP_SHIFT; | ||
769 | + can_btc |= ((((bt->brp - 1) >> 6) & 0xF) << D_CAN_BTR_BRPE_SHIFT); | ||
770 | + | ||
771 | + d_can_write(priv, D_CAN_BTR, can_btc); | ||
772 | + | ||
773 | + netdev_info(dev, "setting CAN BT = %#x\n", can_btc); | ||
774 | + | ||
775 | + return 0; | ||
776 | +} | ||
777 | + | ||
778 | +/* | ||
779 | + * Configure D_CAN message objects for Tx and Rx purposes: | ||
780 | + * D_CAN provides a total of 64 message objects that can be configured | ||
781 | + * either for Tx or Rx purposes. In this driver first 32 message objects | ||
782 | + * are used as a reception FIFO and the reception FIFO is signified by the | ||
783 | + * EoB bit being SET. The remaining 32 message objects are kept aside for | ||
784 | + * Tx purposes. See user guide document for further details on configuring | ||
785 | + * message objects. | ||
786 | + */ | ||
787 | +static void d_can_configure_msg_objects(struct net_device *dev) | ||
788 | +{ | ||
789 | + unsigned int i; | ||
790 | + | ||
791 | + /* first invalidate all message objects */ | ||
792 | + for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_NUM_OF_OBJECTS; i++) | ||
793 | + d_can_inval_msg_object(dev, D_CAN_IF_RX_NUM, i); | ||
794 | + | ||
795 | + /* setup receive message objects */ | ||
796 | + for (i = D_CAN_MSG_OBJ_RX_FIRST; i < D_CAN_MSG_OBJ_RX_LAST; i++) | ||
797 | + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, i, 0, 0, | ||
798 | + (D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK) & | ||
799 | + ~D_CAN_IF_MCTL_EOB); | ||
800 | + | ||
801 | + /* Last object EoB bit should be 1 for terminate */ | ||
802 | + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, D_CAN_MSG_OBJ_RX_LAST, | ||
803 | + 0, 0, D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK | | ||
804 | + D_CAN_IF_MCTL_EOB); | ||
805 | +} | ||
806 | + | ||
807 | +static void d_can_test_mode(struct net_device *dev) | ||
808 | +{ | ||
809 | + struct d_can_priv *priv = netdev_priv(dev); | ||
810 | + | ||
811 | + /* Test mode is enabled in this step & the specific TEST bits | ||
812 | + * are enabled accordingly */ | ||
813 | + d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | | ||
814 | + D_CAN_CTL_IE1 | D_CAN_CTL_IE0 | D_CAN_CTL_TEST); | ||
815 | + | ||
816 | + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { | ||
817 | + /* silent mode : bus-monitoring mode */ | ||
818 | + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_SILENT); | ||
819 | + } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { | ||
820 | + /* loopback mode : useful for self-test function */ | ||
821 | + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK); | ||
822 | + } else { | ||
823 | + /* loopback + silent mode : useful for hot self-test */ | ||
824 | + d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK | | ||
825 | + D_CAN_TEST_SILENT); | ||
826 | + } | ||
827 | +} | ||
828 | + | ||
829 | +/* | ||
830 | + * Configure D_CAN chip: | ||
831 | + * - enable/disable auto-retransmission | ||
832 | + * - set operating mode | ||
833 | + * - configure message objects | ||
834 | + */ | ||
835 | +static void d_can_init(struct net_device *dev) | ||
836 | +{ | ||
837 | + struct d_can_priv *priv = netdev_priv(dev); | ||
838 | + u32 cnt; | ||
839 | + | ||
840 | + netdev_dbg(dev, "resetting d_can ...\n"); | ||
841 | + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_SWR); | ||
842 | + | ||
843 | + /* Enter initialization mode by setting the Init bit */ | ||
844 | + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT); | ||
845 | + | ||
846 | + /* enable automatic retransmission */ | ||
847 | + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_ENABLE_AR); | ||
848 | + | ||
849 | + /* Set the Configure Change Enable ( CCE) bit */ | ||
850 | + d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_CCE); | ||
851 | + | ||
852 | + /* Wait for the Init bit to get set */ | ||
853 | + cnt = D_CAN_WAIT_COUNT; | ||
854 | + while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) { | ||
855 | + --cnt; | ||
856 | + udelay(10); | ||
857 | + } | ||
858 | + | ||
859 | + /* set bittiming params */ | ||
860 | + d_can_set_bittiming(dev); | ||
861 | + | ||
862 | + d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT | D_CAN_CTL_CCE); | ||
863 | + | ||
864 | + /* Wait for the Init bit to get clear */ | ||
865 | + cnt = D_CAN_WAIT_COUNT; | ||
866 | + while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) { | ||
867 | + --cnt; | ||
868 | + udelay(10); | ||
869 | + } | ||
870 | + | ||
871 | + if (!priv->test_mode) { | ||
872 | + /* normal mode*/ | ||
873 | + d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 | | ||
874 | + D_CAN_CTL_IE0); | ||
875 | + } else | ||
876 | + d_can_test_mode(dev); | ||
877 | + | ||
878 | + /* Enable TX and RX I/O Control pins */ | ||
879 | + d_can_write(priv, D_CAN_TIOC, D_CAN_TIOC_FUNC); | ||
880 | + d_can_write(priv, D_CAN_RIOC, D_CAN_RIOC_FUNC); | ||
881 | + | ||
882 | + /* configure message objects */ | ||
883 | + d_can_configure_msg_objects(dev); | ||
884 | + | ||
885 | + /* set a `lec` value so that we can check for updates later */ | ||
886 | + d_can_write(priv, D_CAN_ES, LEC_UNUSED); | ||
887 | +} | ||
888 | + | ||
889 | +static void d_can_start(struct net_device *dev) | ||
890 | +{ | ||
891 | + struct d_can_priv *priv = netdev_priv(dev); | ||
892 | + | ||
893 | + /* basic d_can initialization */ | ||
894 | + d_can_init(dev); | ||
895 | + | ||
896 | + priv->can.state = CAN_STATE_ERROR_ACTIVE; | ||
897 | + | ||
898 | + /* reset tx helper pointers */ | ||
899 | + priv->tx_next = priv->tx_echo = 0; | ||
900 | + | ||
901 | + /* enable status change, error and module interrupts */ | ||
902 | + d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS); | ||
903 | +} | ||
904 | + | ||
905 | +static void d_can_stop(struct net_device *dev) | ||
906 | +{ | ||
907 | + struct d_can_priv *priv = netdev_priv(dev); | ||
908 | + | ||
909 | + /* disable all interrupts */ | ||
910 | + d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS); | ||
911 | + | ||
912 | + /* set the state as STOPPED */ | ||
913 | + priv->can.state = CAN_STATE_STOPPED; | ||
914 | +} | ||
915 | + | ||
916 | +static int d_can_set_mode(struct net_device *dev, enum can_mode mode) | ||
917 | +{ | ||
918 | + switch (mode) { | ||
919 | + case CAN_MODE_START: | ||
920 | + d_can_start(dev); | ||
921 | + netif_wake_queue(dev); | ||
922 | + break; | ||
923 | + default: | ||
924 | + return -EOPNOTSUPP; | ||
925 | + } | ||
926 | + | ||
927 | + return 0; | ||
928 | +} | ||
929 | + | ||
930 | +static int d_can_get_berr_counter(const struct net_device *dev, | ||
931 | + struct can_berr_counter *bec) | ||
932 | +{ | ||
933 | + unsigned int reg_err_counter; | ||
934 | + struct d_can_priv *priv = netdev_priv(dev); | ||
935 | + | ||
936 | + reg_err_counter = d_can_read(priv, D_CAN_ERRC); | ||
937 | + bec->rxerr = (reg_err_counter & D_CAN_ERRC_REC_MASK) >> | ||
938 | + D_CAN_ERRC_REC_SHIFT; | ||
939 | + bec->txerr = reg_err_counter & D_CAN_ERRC_TEC_MASK; | ||
940 | + | ||
941 | + return 0; | ||
942 | +} | ||
943 | + | ||
944 | +/* | ||
945 | + * theory of operation: | ||
946 | + * | ||
947 | + * priv->tx_echo holds the number of the oldest can_frame put for | ||
948 | + * transmission into the hardware, but not yet ACKed by the CAN tx | ||
949 | + * complete IRQ. | ||
950 | + * | ||
951 | + * We iterate from priv->tx_echo to priv->tx_next and check if the | ||
952 | + * packet has been transmitted, echo it back to the CAN framework. | ||
953 | + * If we discover a not yet transmitted package, stop looking for more. | ||
954 | + */ | ||
955 | +static void d_can_do_tx(struct net_device *dev) | ||
956 | +{ | ||
957 | + u32 msg_obj_no; | ||
958 | + struct d_can_priv *priv = netdev_priv(dev); | ||
959 | + struct net_device_stats *stats = &dev->stats; | ||
960 | + u32 txrq_x_reg_val; | ||
961 | + u32 txrq_reg_val; | ||
962 | + | ||
963 | + for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { | ||
964 | + msg_obj_no = get_tx_echo_msg_obj(priv); | ||
965 | + txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X); | ||
966 | + txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)); | ||
967 | + if (!(txrq_reg_val & (1 << (msg_obj_no - 1)))) { | ||
968 | + can_get_echo_skb(dev, | ||
969 | + msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST); | ||
970 | + stats->tx_bytes += d_can_read(priv, | ||
971 | + D_CAN_IFMCTL(D_CAN_IF_TX_NUM)) | ||
972 | + & D_CAN_IF_MCTL_DLC_MASK; | ||
973 | + stats->tx_packets++; | ||
974 | + d_can_inval_msg_object(dev, D_CAN_IF_TX_NUM, | ||
975 | + msg_obj_no); | ||
976 | + } else | ||
977 | + break; | ||
978 | + } | ||
979 | + | ||
980 | + /* restart queue if wrap-up or if queue stalled on last pkt */ | ||
981 | + if (((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) != 0) | ||
982 | + || ((priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) | ||
983 | + == 0)) | ||
984 | + netif_wake_queue(dev); | ||
985 | +} | ||
986 | + | ||
987 | +/* | ||
988 | + * theory of operation: | ||
989 | + * | ||
990 | + * d_can core saves a received CAN message into the first free message | ||
991 | + * object it finds free (starting with the lowest). Bits NEWDAT and | ||
992 | + * INTPND are set for this message object indicating that a new message | ||
993 | + * has arrived. To work-around this issue, we keep two groups of message | ||
994 | + * objects whose partitioning is defined by D_CAN_MSG_OBJ_RX_SPLIT. | ||
995 | + * | ||
996 | + * To ensure in-order frame reception we use the following | ||
997 | + * approach while re-activating a message object to receive further | ||
998 | + * frames: | ||
999 | + * - if the current message object number is lower than | ||
1000 | + * D_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing | ||
1001 | + * the INTPND bit. | ||
1002 | + * - if the current message object number is equal to | ||
1003 | + * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower | ||
1004 | + * receive message objects. | ||
1005 | + * - if the current message object number is greater than | ||
1006 | + * D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of | ||
1007 | + * only this message object. | ||
1008 | + */ | ||
1009 | +static int d_can_do_rx_poll(struct net_device *dev, int quota) | ||
1010 | +{ | ||
1011 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1012 | + unsigned int msg_obj, mctrl_reg_val; | ||
1013 | + u32 num_rx_pkts = 0; | ||
1014 | + u32 intpnd_x_reg_val; | ||
1015 | + u32 intpnd_reg_val; | ||
1016 | + | ||
1017 | + for (msg_obj = D_CAN_MSG_OBJ_RX_FIRST; msg_obj <= D_CAN_MSG_OBJ_RX_LAST | ||
1018 | + && quota > 0; msg_obj++) { | ||
1019 | + | ||
1020 | + intpnd_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X); | ||
1021 | + intpnd_reg_val = d_can_read(priv, | ||
1022 | + D_CAN_INTPND(intpnd_x_reg_val)); | ||
1023 | + | ||
1024 | + /* | ||
1025 | + * as interrupt pending register's bit n-1 corresponds to | ||
1026 | + * message object n, we need to handle the same properly. | ||
1027 | + */ | ||
1028 | + if (intpnd_reg_val & (1 << (msg_obj - 1))) { | ||
1029 | + | ||
1030 | + d_can_object_get(dev, D_CAN_IF_RX_NUM, msg_obj, | ||
1031 | + D_CAN_IF_CMD_ALL & | ||
1032 | + ~D_CAN_IF_CMD_TXRQST); | ||
1033 | + | ||
1034 | + mctrl_reg_val = d_can_read(priv, | ||
1035 | + D_CAN_IFMCTL(D_CAN_IF_RX_NUM)); | ||
1036 | + | ||
1037 | + if (!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT)) | ||
1038 | + continue; | ||
1039 | + | ||
1040 | + /* read the data from the message object */ | ||
1041 | + d_can_read_msg_object(dev, D_CAN_IF_RX_NUM, | ||
1042 | + mctrl_reg_val); | ||
1043 | + | ||
1044 | + if (mctrl_reg_val & D_CAN_IF_MCTL_EOB) | ||
1045 | + d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, | ||
1046 | + D_CAN_MSG_OBJ_RX_LAST, 0, 0, | ||
1047 | + D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK | ||
1048 | + | D_CAN_IF_MCTL_EOB); | ||
1049 | + | ||
1050 | + if (mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) { | ||
1051 | + d_can_handle_lost_msg_obj(dev, D_CAN_IF_RX_NUM, | ||
1052 | + msg_obj); | ||
1053 | + num_rx_pkts++; | ||
1054 | + quota--; | ||
1055 | + continue; | ||
1056 | + } | ||
1057 | + | ||
1058 | + if (msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST) | ||
1059 | + d_can_mark_rx_msg_obj(dev, D_CAN_IF_RX_NUM, | ||
1060 | + mctrl_reg_val, msg_obj); | ||
1061 | + else if (msg_obj > D_CAN_MSG_OBJ_RX_LOW_LAST) | ||
1062 | + /* activate this msg obj */ | ||
1063 | + d_can_activate_rx_msg_obj(dev, D_CAN_IF_RX_NUM, | ||
1064 | + mctrl_reg_val, msg_obj); | ||
1065 | + else if (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST) | ||
1066 | + /* activate all lower message objects */ | ||
1067 | + d_can_activate_all_lower_rx_msg_obj(dev, | ||
1068 | + D_CAN_IF_RX_NUM, mctrl_reg_val); | ||
1069 | + | ||
1070 | + num_rx_pkts++; | ||
1071 | + quota--; | ||
1072 | + } | ||
1073 | + } | ||
1074 | + | ||
1075 | + return num_rx_pkts; | ||
1076 | +} | ||
1077 | + | ||
1078 | +static inline int d_can_has_and_handle_berr(struct d_can_priv *priv) | ||
1079 | +{ | ||
1080 | + return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && | ||
1081 | + (priv->current_status & LEC_UNUSED); | ||
1082 | +} | ||
1083 | + | ||
1084 | +static int d_can_handle_state_change(struct net_device *dev, | ||
1085 | + enum d_can_bus_error_types error_type) | ||
1086 | +{ | ||
1087 | + unsigned int reg_err_counter; | ||
1088 | + unsigned int rx_err_passive; | ||
1089 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1090 | + struct net_device_stats *stats = &dev->stats; | ||
1091 | + struct can_frame *cf; | ||
1092 | + struct sk_buff *skb; | ||
1093 | + struct can_berr_counter bec; | ||
1094 | + | ||
1095 | + /* propagate the error condition to the CAN stack */ | ||
1096 | + skb = alloc_can_err_skb(dev, &cf); | ||
1097 | + if (unlikely(!skb)) | ||
1098 | + return 0; | ||
1099 | + | ||
1100 | + d_can_get_berr_counter(dev, &bec); | ||
1101 | + reg_err_counter = d_can_read(priv, D_CAN_ERRC); | ||
1102 | + rx_err_passive = (reg_err_counter & D_CAN_ERRC_RP_MASK) >> | ||
1103 | + D_CAN_ERRC_RP_SHIFT; | ||
1104 | + | ||
1105 | + switch (error_type) { | ||
1106 | + case D_CAN_ERROR_WARNING: | ||
1107 | + /* error warning state */ | ||
1108 | + priv->can.can_stats.error_warning++; | ||
1109 | + priv->can.state = CAN_STATE_ERROR_WARNING; | ||
1110 | + cf->can_id |= CAN_ERR_CRTL; | ||
1111 | + cf->data[1] = (bec.txerr > bec.rxerr) ? | ||
1112 | + CAN_ERR_CRTL_TX_WARNING : | ||
1113 | + CAN_ERR_CRTL_RX_WARNING; | ||
1114 | + cf->data[6] = bec.txerr; | ||
1115 | + cf->data[7] = bec.rxerr; | ||
1116 | + | ||
1117 | + break; | ||
1118 | + case D_CAN_ERROR_PASSIVE: | ||
1119 | + /* error passive state */ | ||
1120 | + priv->can.can_stats.error_passive++; | ||
1121 | + priv->can.state = CAN_STATE_ERROR_PASSIVE; | ||
1122 | + cf->can_id |= CAN_ERR_CRTL; | ||
1123 | + if (rx_err_passive) | ||
1124 | + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; | ||
1125 | + if (bec.txerr > 127) | ||
1126 | + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; | ||
1127 | + | ||
1128 | + cf->data[6] = bec.txerr; | ||
1129 | + cf->data[7] = bec.rxerr; | ||
1130 | + break; | ||
1131 | + case D_CAN_BUS_OFF: | ||
1132 | + /* bus-off state */ | ||
1133 | + priv->can.state = CAN_STATE_BUS_OFF; | ||
1134 | + cf->can_id |= CAN_ERR_BUSOFF; | ||
1135 | + /* | ||
1136 | + * disable all interrupts in bus-off mode to ensure that | ||
1137 | + * the CPU is not hogged down | ||
1138 | + */ | ||
1139 | + d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS); | ||
1140 | + can_bus_off(dev); | ||
1141 | + break; | ||
1142 | + default: | ||
1143 | + break; | ||
1144 | + } | ||
1145 | + | ||
1146 | + netif_receive_skb(skb); | ||
1147 | + stats->rx_packets++; | ||
1148 | + stats->rx_bytes += cf->can_dlc; | ||
1149 | + | ||
1150 | + return 1; | ||
1151 | +} | ||
1152 | + | ||
1153 | +static int d_can_handle_bus_err(struct net_device *dev, | ||
1154 | + enum d_can_lec_type lec_type) | ||
1155 | +{ | ||
1156 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1157 | + struct net_device_stats *stats = &dev->stats; | ||
1158 | + struct can_frame *cf; | ||
1159 | + struct sk_buff *skb; | ||
1160 | + | ||
1161 | + /* | ||
1162 | + * early exit if no lec update or no error. | ||
1163 | + * no lec update means that no CAN bus event has been detected | ||
1164 | + * since CPU wrote 0x7 value to status reg. | ||
1165 | + */ | ||
1166 | + if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR) | ||
1167 | + return 0; | ||
1168 | + | ||
1169 | + /* propagate the error condition to the CAN stack */ | ||
1170 | + skb = alloc_can_err_skb(dev, &cf); | ||
1171 | + if (unlikely(!skb)) | ||
1172 | + return 0; | ||
1173 | + | ||
1174 | + /* | ||
1175 | + * check for 'last error code' which tells us the | ||
1176 | + * type of the last error to occur on the CAN bus | ||
1177 | + */ | ||
1178 | + | ||
1179 | + /* common for all type of bus errors */ | ||
1180 | + priv->can.can_stats.bus_error++; | ||
1181 | + stats->rx_errors++; | ||
1182 | + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; | ||
1183 | + cf->data[2] |= CAN_ERR_PROT_UNSPEC; | ||
1184 | + | ||
1185 | + switch (lec_type) { | ||
1186 | + case LEC_STUFF_ERROR: | ||
1187 | + netdev_dbg(dev, "stuff error\n"); | ||
1188 | + cf->data[2] |= CAN_ERR_PROT_STUFF; | ||
1189 | + break; | ||
1190 | + case LEC_FORM_ERROR: | ||
1191 | + netdev_dbg(dev, "form error\n"); | ||
1192 | + cf->data[2] |= CAN_ERR_PROT_FORM; | ||
1193 | + break; | ||
1194 | + case LEC_ACK_ERROR: | ||
1195 | + netdev_dbg(dev, "ack error\n"); | ||
1196 | + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK | | ||
1197 | + CAN_ERR_PROT_LOC_ACK_DEL); | ||
1198 | + break; | ||
1199 | + case LEC_BIT1_ERROR: | ||
1200 | + netdev_dbg(dev, "bit1 error\n"); | ||
1201 | + cf->data[2] |= CAN_ERR_PROT_BIT1; | ||
1202 | + break; | ||
1203 | + case LEC_BIT0_ERROR: | ||
1204 | + netdev_dbg(dev, "bit0 error\n"); | ||
1205 | + cf->data[2] |= CAN_ERR_PROT_BIT0; | ||
1206 | + break; | ||
1207 | + case LEC_CRC_ERROR: | ||
1208 | + netdev_dbg(dev, "CRC error\n"); | ||
1209 | + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ | | ||
1210 | + CAN_ERR_PROT_LOC_CRC_DEL); | ||
1211 | + break; | ||
1212 | + default: | ||
1213 | + break; | ||
1214 | + } | ||
1215 | + | ||
1216 | + /* set a `lec` value so that we can check for updates later */ | ||
1217 | + d_can_write(priv, D_CAN_ES, LEC_UNUSED); | ||
1218 | + | ||
1219 | + netif_receive_skb(skb); | ||
1220 | + stats->rx_packets++; | ||
1221 | + stats->rx_bytes += cf->can_dlc; | ||
1222 | + | ||
1223 | + return 1; | ||
1224 | +} | ||
1225 | + | ||
1226 | +static int d_can_poll(struct napi_struct *napi, int quota) | ||
1227 | +{ | ||
1228 | + int lec_type = 0; | ||
1229 | + int work_done = 0; | ||
1230 | + struct net_device *dev = napi->dev; | ||
1231 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1232 | + | ||
1233 | + priv->irqstatus = d_can_read(priv, D_CAN_INT); | ||
1234 | + if (!priv->irqstatus) | ||
1235 | + goto end; | ||
1236 | + | ||
1237 | + /* status events have the highest priority */ | ||
1238 | + if (priv->irqstatus == STATUS_INTERRUPT) { | ||
1239 | + priv->current_status = d_can_read(priv, D_CAN_ES); | ||
1240 | + | ||
1241 | + /* handle Tx/Rx events */ | ||
1242 | + if (priv->current_status & D_CAN_ES_TXOK) | ||
1243 | + d_can_write(priv, D_CAN_ES, | ||
1244 | + priv->current_status & ~D_CAN_ES_TXOK); | ||
1245 | + | ||
1246 | + if (priv->current_status & D_CAN_ES_RXOK) | ||
1247 | + d_can_write(priv, D_CAN_ES, | ||
1248 | + priv->current_status & ~D_CAN_ES_RXOK); | ||
1249 | + | ||
1250 | + /* handle state changes */ | ||
1251 | + if ((priv->current_status & D_CAN_ES_EWARN) && | ||
1252 | + (!(priv->last_status & D_CAN_ES_EWARN))) { | ||
1253 | + netdev_dbg(dev, "entered error warning state\n"); | ||
1254 | + work_done += d_can_handle_state_change(dev, | ||
1255 | + D_CAN_ERROR_WARNING); | ||
1256 | + } | ||
1257 | + if ((priv->current_status & D_CAN_ES_EPASS) && | ||
1258 | + (!(priv->last_status & D_CAN_ES_EPASS))) { | ||
1259 | + netdev_dbg(dev, "entered error passive state\n"); | ||
1260 | + work_done += d_can_handle_state_change(dev, | ||
1261 | + D_CAN_ERROR_PASSIVE); | ||
1262 | + } | ||
1263 | + if ((priv->current_status & D_CAN_ES_BOFF) && | ||
1264 | + (!(priv->last_status & D_CAN_ES_BOFF))) { | ||
1265 | + netdev_dbg(dev, "entered bus off state\n"); | ||
1266 | + work_done += d_can_handle_state_change(dev, | ||
1267 | + D_CAN_BUS_OFF); | ||
1268 | + } | ||
1269 | + | ||
1270 | + /* handle bus recovery events */ | ||
1271 | + if ((!(priv->current_status & D_CAN_ES_BOFF)) && | ||
1272 | + (priv->last_status & D_CAN_ES_BOFF)) { | ||
1273 | + netdev_dbg(dev, "left bus off state\n"); | ||
1274 | + priv->can.state = CAN_STATE_ERROR_ACTIVE; | ||
1275 | + } | ||
1276 | + if ((!(priv->current_status & D_CAN_ES_EPASS)) && | ||
1277 | + (priv->last_status & D_CAN_ES_EPASS)) { | ||
1278 | + netdev_dbg(dev, "left error passive state\n"); | ||
1279 | + priv->can.state = CAN_STATE_ERROR_ACTIVE; | ||
1280 | + } | ||
1281 | + | ||
1282 | + priv->last_status = priv->current_status; | ||
1283 | + | ||
1284 | + /* handle lec errors on the bus */ | ||
1285 | + lec_type = d_can_has_and_handle_berr(priv); | ||
1286 | + if (lec_type) | ||
1287 | + work_done += d_can_handle_bus_err(dev, lec_type); | ||
1288 | + } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) && | ||
1289 | + (priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) { | ||
1290 | + /* handle events corresponding to receive message objects */ | ||
1291 | + work_done += d_can_do_rx_poll(dev, (quota - work_done)); | ||
1292 | + } else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) && | ||
1293 | + (priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) { | ||
1294 | + /* handle events corresponding to transmit message objects */ | ||
1295 | + d_can_do_tx(dev); | ||
1296 | + } | ||
1297 | + | ||
1298 | +end: | ||
1299 | + if (work_done < quota) { | ||
1300 | + napi_complete(napi); | ||
1301 | + /* enable all IRQs */ | ||
1302 | + d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS); | ||
1303 | + } | ||
1304 | + | ||
1305 | + return work_done; | ||
1306 | +} | ||
1307 | + | ||
1308 | +static irqreturn_t d_can_isr(int irq, void *dev_id) | ||
1309 | +{ | ||
1310 | + struct net_device *dev = (struct net_device *)dev_id; | ||
1311 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1312 | + | ||
1313 | + priv->irqstatus = d_can_read(priv, D_CAN_INT); | ||
1314 | + if (!priv->irqstatus) | ||
1315 | + return IRQ_NONE; | ||
1316 | + | ||
1317 | + /* disable all interrupts and schedule the NAPI */ | ||
1318 | + d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS); | ||
1319 | + napi_schedule(&priv->napi); | ||
1320 | + | ||
1321 | + return IRQ_HANDLED; | ||
1322 | +} | ||
1323 | + | ||
1324 | +static int d_can_open(struct net_device *ndev) | ||
1325 | +{ | ||
1326 | + int err; | ||
1327 | + struct d_can_priv *priv = netdev_priv(ndev); | ||
1328 | + | ||
1329 | + /* Open common can device */ | ||
1330 | + err = open_candev(ndev); | ||
1331 | + if (err) { | ||
1332 | + netdev_err(ndev, "open_candev() failed %d\n", err); | ||
1333 | + return err; | ||
1334 | + } | ||
1335 | + | ||
1336 | + /* register interrupt handler for Message Object (MO) | ||
1337 | + * and Error + status change (ES) */ | ||
1338 | + err = request_irq(ndev->irq, &d_can_isr, IRQF_SHARED, ndev->name, | ||
1339 | + ndev); | ||
1340 | + if (err) { | ||
1341 | + netdev_err(ndev, "failed to request MO_ES interrupt\n"); | ||
1342 | + goto exit_close_candev; | ||
1343 | + } | ||
1344 | + | ||
1345 | + /* register interrupt handler for only Message Object */ | ||
1346 | + err = request_irq(priv->irq_obj, &d_can_isr, IRQF_SHARED, ndev->name, | ||
1347 | + ndev); | ||
1348 | + if (err) { | ||
1349 | + netdev_err(ndev, "failed to request MO interrupt\n"); | ||
1350 | + goto exit_free_irq; | ||
1351 | + } | ||
1352 | + | ||
1353 | + /* start the d_can controller */ | ||
1354 | + d_can_start(ndev); | ||
1355 | + | ||
1356 | + napi_enable(&priv->napi); | ||
1357 | + netif_start_queue(ndev); | ||
1358 | + | ||
1359 | + return 0; | ||
1360 | +exit_free_irq: | ||
1361 | + free_irq(ndev->irq, ndev); | ||
1362 | +exit_close_candev: | ||
1363 | + close_candev(ndev); | ||
1364 | + return err; | ||
1365 | +} | ||
1366 | + | ||
1367 | +static int d_can_close(struct net_device *ndev) | ||
1368 | +{ | ||
1369 | + struct d_can_priv *priv = netdev_priv(ndev); | ||
1370 | + | ||
1371 | + netif_stop_queue(ndev); | ||
1372 | + napi_disable(&priv->napi); | ||
1373 | + d_can_stop(ndev); | ||
1374 | + free_irq(ndev->irq, ndev); | ||
1375 | + free_irq(priv->irq_obj, ndev); | ||
1376 | + close_candev(ndev); | ||
1377 | + | ||
1378 | + return 0; | ||
1379 | +} | ||
1380 | + | ||
1381 | +struct net_device *alloc_d_can_dev(int num_objs) | ||
1382 | +{ | ||
1383 | + struct net_device *dev; | ||
1384 | + struct d_can_priv *priv; | ||
1385 | + | ||
1386 | + dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2); | ||
1387 | + if (!dev) | ||
1388 | + return NULL; | ||
1389 | + | ||
1390 | + priv = netdev_priv(dev); | ||
1391 | + netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2); | ||
1392 | + | ||
1393 | + priv->dev = dev; | ||
1394 | + priv->can.bittiming_const = &d_can_bittiming_const; | ||
1395 | + priv->can.do_set_mode = d_can_set_mode; | ||
1396 | + priv->can.do_get_berr_counter = d_can_get_berr_counter; | ||
1397 | + priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK | | ||
1398 | + CAN_CTRLMODE_LISTENONLY | | ||
1399 | + CAN_CTRLMODE_BERR_REPORTING | | ||
1400 | + CAN_CTRLMODE_3_SAMPLES); | ||
1401 | + | ||
1402 | + return dev; | ||
1403 | +} | ||
1404 | +EXPORT_SYMBOL_GPL(alloc_d_can_dev); | ||
1405 | + | ||
1406 | +void free_d_can_dev(struct net_device *dev) | ||
1407 | +{ | ||
1408 | + free_candev(dev); | ||
1409 | +} | ||
1410 | +EXPORT_SYMBOL_GPL(free_d_can_dev); | ||
1411 | + | ||
1412 | +static const struct net_device_ops d_can_netdev_ops = { | ||
1413 | + .ndo_open = d_can_open, | ||
1414 | + .ndo_stop = d_can_close, | ||
1415 | + .ndo_start_xmit = d_can_start_xmit, | ||
1416 | +}; | ||
1417 | + | ||
1418 | +int register_d_can_dev(struct net_device *dev) | ||
1419 | +{ | ||
1420 | + /* we support local echo */ | ||
1421 | + dev->flags |= IFF_ECHO; | ||
1422 | + dev->netdev_ops = &d_can_netdev_ops; | ||
1423 | + | ||
1424 | + return register_candev(dev); | ||
1425 | +} | ||
1426 | +EXPORT_SYMBOL_GPL(register_d_can_dev); | ||
1427 | + | ||
1428 | +void unregister_d_can_dev(struct net_device *dev) | ||
1429 | +{ | ||
1430 | + struct d_can_priv *priv = netdev_priv(dev); | ||
1431 | + | ||
1432 | + /* disable all interrupts */ | ||
1433 | + d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS); | ||
1434 | + | ||
1435 | + unregister_candev(dev); | ||
1436 | +} | ||
1437 | +EXPORT_SYMBOL_GPL(unregister_d_can_dev); | ||
1438 | + | ||
1439 | +MODULE_AUTHOR("Anil Kumar Ch <anilkumar@ti.com>"); | ||
1440 | +MODULE_LICENSE("GPL v2"); | ||
1441 | +MODULE_VERSION(D_CAN_VERSION); | ||
1442 | +MODULE_DESCRIPTION(D_CAN_DRV_DESC); | ||
1443 | diff --git a/drivers/net/can/d_can/d_can.h b/drivers/net/can/d_can/d_can.h | ||
1444 | new file mode 100644 | ||
1445 | index 0000000..f096944 | ||
1446 | --- /dev/null | ||
1447 | +++ b/drivers/net/can/d_can/d_can.h | ||
1448 | @@ -0,0 +1,67 @@ | ||
1449 | +/* | ||
1450 | + * CAN bus driver for Bosch D_CAN controller | ||
1451 | + * | ||
1452 | + * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/ | ||
1453 | + * Anil Kumar Ch <anilkumar@ti.com> | ||
1454 | + * | ||
1455 | + * Base taken from C_CAN driver | ||
1456 | + * Copyright (C) 2010 ST Microelectronics | ||
1457 | + * - Bhupesh Sharma <bhupesh.sharma@st.com> | ||
1458 | + * | ||
1459 | + * Borrowed heavily from the C_CAN driver originally written by: | ||
1460 | + * Copyright (C) 2007 | ||
1461 | + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> | ||
1462 | + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> | ||
1463 | + * | ||
1464 | + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B. | ||
1465 | + * Bosch D_CAN user manual can be obtained from: | ||
1466 | + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/ | ||
1467 | + * d_can_users_manual_111.pdf | ||
1468 | + * | ||
1469 | + * This program is free software; you can redistribute it and/or | ||
1470 | + * modify it under the terms of the GNU General Public License as | ||
1471 | + * published by the Free Software Foundation version 2. | ||
1472 | + * | ||
1473 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
1474 | + * kind, whether express or implied; without even the implied warranty | ||
1475 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1476 | + * GNU General Public License for more details. | ||
1477 | + */ | ||
1478 | + | ||
1479 | +#ifndef D_CAN_H | ||
1480 | +#define D_CAN_H | ||
1481 | + | ||
1482 | +#define D_CAN_DRV_NAME "d_can" | ||
1483 | +#define D_CAN_VERSION "1.0" | ||
1484 | +#define D_CAN_DRV_DESC "CAN bus driver for Bosch D_CAN controller " \ | ||
1485 | + D_CAN_VERSION | ||
1486 | + | ||
1487 | +/* d_can private data structure */ | ||
1488 | +struct d_can_priv { | ||
1489 | + struct can_priv can; /* must be the first member */ | ||
1490 | + struct napi_struct napi; | ||
1491 | + struct net_device *dev; | ||
1492 | + int current_status; | ||
1493 | + int last_status; | ||
1494 | + unsigned int irqstatus; | ||
1495 | + void __iomem *base; | ||
1496 | + u32 napi_weight; | ||
1497 | + struct clk *fck; | ||
1498 | + struct clk *ick; | ||
1499 | + bool test_mode; | ||
1500 | + unsigned int irq; /* device IRQ number, for all MO and ES */ | ||
1501 | + unsigned int irq_obj; /* device IRQ number for only Msg Object */ | ||
1502 | + unsigned int irq_parity; /* device IRQ number for parity error */ | ||
1503 | + unsigned long irq_flags; /* for request_irq() */ | ||
1504 | + unsigned int tx_next; | ||
1505 | + unsigned int tx_echo; | ||
1506 | + unsigned int rx_next; | ||
1507 | + void *priv; /* for board-specific data */ | ||
1508 | +}; | ||
1509 | + | ||
1510 | +struct net_device *alloc_d_can_dev(int); | ||
1511 | +void free_d_can_dev(struct net_device *dev); | ||
1512 | +int register_d_can_dev(struct net_device *dev); | ||
1513 | +void unregister_d_can_dev(struct net_device *dev); | ||
1514 | + | ||
1515 | +#endif /* D_CAN_H */ | ||
1516 | diff --git a/drivers/net/can/d_can/d_can_platform.c b/drivers/net/can/d_can/d_can_platform.c | ||
1517 | new file mode 100644 | ||
1518 | index 0000000..b430a18 | ||
1519 | --- /dev/null | ||
1520 | +++ b/drivers/net/can/d_can/d_can_platform.c | ||
1521 | @@ -0,0 +1,256 @@ | ||
1522 | +/* | ||
1523 | + * Platform CAN bus driver for Bosch D_CAN controller | ||
1524 | + * | ||
1525 | + * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/ | ||
1526 | + * Anil Kumar Ch <anilkumar@ti.com> | ||
1527 | + * | ||
1528 | + * Base taken from C_CAN driver | ||
1529 | + * Copyright (C) 2010 ST Microelectronics | ||
1530 | + * - Bhupesh Sharma <bhupesh.sharma@st.com> | ||
1531 | + * | ||
1532 | + * Borrowed heavily from the C_CAN driver originally written by: | ||
1533 | + * Copyright (C) 2007 | ||
1534 | + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de> | ||
1535 | + * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch> | ||
1536 | + * | ||
1537 | + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B. | ||
1538 | + * Bosch D_CAN user manual can be obtained from: | ||
1539 | + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/ | ||
1540 | + * d_can_users_manual_111.pdf | ||
1541 | + * | ||
1542 | + * This program is free software; you can redistribute it and/or | ||
1543 | + * modify it under the terms of the GNU General Public License as | ||
1544 | + * published by the Free Software Foundation version 2. | ||
1545 | + * | ||
1546 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
1547 | + * kind, whether express or implied; without even the implied warranty | ||
1548 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1549 | + * GNU General Public License for more details. | ||
1550 | + */ | ||
1551 | + | ||
1552 | +/* | ||
1553 | + * Your platform definitions should specify module ram offsets and interrupt | ||
1554 | + * number to use as follows: | ||
1555 | + * | ||
1556 | + * static struct d_can_platform_data am33xx_evm_d_can_pdata = { | ||
1557 | + * .d_can_offset = 0, | ||
1558 | + * .d_can_ram_offset = 0x1000, | ||
1559 | + * .num_of_msg_objs = 64, | ||
1560 | + * .dma_support = true, | ||
1561 | + * .test_mode_enable = false, | ||
1562 | + * .parity_check = false, | ||
1563 | + * .version = 0x1, | ||
1564 | + * .hw_raminit = d_can_hw_raminit, | ||
1565 | + * }; | ||
1566 | + * | ||
1567 | + * Please see include/linux/can/platform/d_can.h for description of | ||
1568 | + * above fields. | ||
1569 | + * | ||
1570 | + */ | ||
1571 | + | ||
1572 | +#include <linux/kernel.h> | ||
1573 | +#include <linux/module.h> | ||
1574 | +#include <linux/interrupt.h> | ||
1575 | +#include <linux/delay.h> | ||
1576 | +#include <linux/netdevice.h> | ||
1577 | +#include <linux/if_arp.h> | ||
1578 | +#include <linux/if_ether.h> | ||
1579 | +#include <linux/list.h> | ||
1580 | +#include <linux/io.h> | ||
1581 | +#include <linux/platform_device.h> | ||
1582 | +#include <linux/can/platform/d_can.h> | ||
1583 | +#include <linux/clk.h> | ||
1584 | +#include <linux/slab.h> | ||
1585 | +#include <linux/can/dev.h> | ||
1586 | + | ||
1587 | +#include "d_can.h" | ||
1588 | + | ||
1589 | +#define D_CAN_CLK_NAME_LEN 40 | ||
1590 | + | ||
1591 | +static int __devinit d_can_plat_probe(struct platform_device *pdev) | ||
1592 | +{ | ||
1593 | + int ret = 0; | ||
1594 | + void __iomem *addr; | ||
1595 | + struct net_device *ndev; | ||
1596 | + struct d_can_priv *priv; | ||
1597 | + struct resource *mem; | ||
1598 | + struct d_can_platform_data *pdata; | ||
1599 | + char *clk_name; | ||
1600 | + | ||
1601 | + pdata = pdev->dev.platform_data; | ||
1602 | + if (!pdata) { | ||
1603 | + dev_err(&pdev->dev, "No platform data\n"); | ||
1604 | + goto exit; | ||
1605 | + } | ||
1606 | + | ||
1607 | + /* allocate the d_can device */ | ||
1608 | + ndev = alloc_d_can_dev(pdata->num_of_msg_objs); | ||
1609 | + if (!ndev) { | ||
1610 | + ret = -ENOMEM; | ||
1611 | + dev_err(&pdev->dev, "alloc_d_can_dev failed\n"); | ||
1612 | + goto exit; | ||
1613 | + } | ||
1614 | + | ||
1615 | + clk_name = kzalloc(D_CAN_CLK_NAME_LEN + 1, GFP_KERNEL); | ||
1616 | + if (!clk_name) | ||
1617 | + goto exit; | ||
1618 | + | ||
1619 | + priv = netdev_priv(ndev); | ||
1620 | + clk_name = "dcan"; | ||
1621 | + if (pdev->id == 0) | ||
1622 | + strcat(clk_name, "0_fck"); | ||
1623 | + else | ||
1624 | + strcat(clk_name, "1_fck"); | ||
1625 | + /* get the appropriate clk */ | ||
1626 | + priv->fck = clk_get(&pdev->dev, clk_name); | ||
1627 | + if (IS_ERR(priv->fck)) { | ||
1628 | + dev_err(&pdev->dev, "%s is not found\n", clk_name); | ||
1629 | + ret = -ENODEV; | ||
1630 | + goto exit_free_ndev; | ||
1631 | + } | ||
1632 | + clk_enable(priv->fck); | ||
1633 | + | ||
1634 | + /* clk_name = D_CAN_DRV_NAME; */ | ||
1635 | + clk_name = "dcan"; | ||
1636 | + if (pdev->id == 0) | ||
1637 | + strcat(clk_name, "0_ick"); | ||
1638 | + else | ||
1639 | + strcat(clk_name, "1_ick"); | ||
1640 | + priv->ick = clk_get(&pdev->dev, clk_name); | ||
1641 | + if (IS_ERR(priv->ick)) { | ||
1642 | + dev_err(&pdev->dev, "%s is not found\n", clk_name); | ||
1643 | + ret = -ENODEV; | ||
1644 | + goto exit_free_fck; | ||
1645 | + } | ||
1646 | + clk_enable(priv->ick); | ||
1647 | + | ||
1648 | + /* get the platform data */ | ||
1649 | + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1650 | + if (!mem) { | ||
1651 | + ret = -ENODEV; | ||
1652 | + dev_err(&pdev->dev, "No mem resource\n"); | ||
1653 | + goto exit_free_clks; | ||
1654 | + } | ||
1655 | + | ||
1656 | + if (!request_mem_region(mem->start, resource_size(mem), | ||
1657 | + D_CAN_DRV_NAME)) { | ||
1658 | + dev_err(&pdev->dev, "resource unavailable\n"); | ||
1659 | + ret = -EBUSY; | ||
1660 | + goto exit_free_clks; | ||
1661 | + } | ||
1662 | + | ||
1663 | + addr = ioremap(mem->start, resource_size(mem)); | ||
1664 | + if (!addr) { | ||
1665 | + dev_err(&pdev->dev, "ioremap failed\n"); | ||
1666 | + ret = -ENOMEM; | ||
1667 | + goto exit_release_mem; | ||
1668 | + } | ||
1669 | + | ||
1670 | + /* IRQ specific to Error and status & can be used for Message Object */ | ||
1671 | + ndev->irq = platform_get_irq_byname(pdev, "d_can_int0"); | ||
1672 | + if (!ndev->irq) { | ||
1673 | + dev_err(&pdev->dev, "No irq0 resource\n"); | ||
1674 | + goto exit_iounmap; | ||
1675 | + } | ||
1676 | + | ||
1677 | + /* IRQ specific for Message Object */ | ||
1678 | + priv->irq_obj = platform_get_irq_byname(pdev, "d_can_int1"); | ||
1679 | + if (!priv->irq_obj) { | ||
1680 | + dev_err(&pdev->dev, "No irq1 resource\n"); | ||
1681 | + goto exit_iounmap; | ||
1682 | + } | ||
1683 | + | ||
1684 | + priv->base = addr; | ||
1685 | + priv->can.clock.freq = clk_get_rate(priv->fck); | ||
1686 | + | ||
1687 | + /* RAM init */ | ||
1688 | + pdata->hw_raminit(pdev->id); | ||
1689 | + | ||
1690 | + priv->test_mode = pdata->test_mode_enable; | ||
1691 | + | ||
1692 | + platform_set_drvdata(pdev, ndev); | ||
1693 | + SET_NETDEV_DEV(ndev, &pdev->dev); | ||
1694 | + | ||
1695 | + ret = register_d_can_dev(ndev); | ||
1696 | + if (ret) { | ||
1697 | + dev_err(&pdev->dev, "registering %s failed (err=%d)\n", | ||
1698 | + D_CAN_DRV_NAME, ret); | ||
1699 | + goto exit_free_device; | ||
1700 | + } | ||
1701 | + | ||
1702 | + dev_info(&pdev->dev, "%s device registered (irq=%d, irq_obj=%d)\n", | ||
1703 | + D_CAN_DRV_NAME, ndev->irq, priv->irq_obj); | ||
1704 | + | ||
1705 | + return 0; | ||
1706 | + | ||
1707 | +exit_free_device: | ||
1708 | + platform_set_drvdata(pdev, NULL); | ||
1709 | +exit_iounmap: | ||
1710 | + iounmap(addr); | ||
1711 | +exit_release_mem: | ||
1712 | + release_mem_region(mem->start, resource_size(mem)); | ||
1713 | +exit_free_clks: | ||
1714 | +#ifdef CONFIG_HAVE_CLK | ||
1715 | + clk_disable(priv->ick); | ||
1716 | + clk_put(priv->ick); | ||
1717 | +exit_free_fck: | ||
1718 | + clk_disable(priv->fck); | ||
1719 | + clk_put(priv->fck); | ||
1720 | +exit_free_ndev: | ||
1721 | + free_d_can_dev(ndev); | ||
1722 | +exit: | ||
1723 | +#endif | ||
1724 | + dev_err(&pdev->dev, "probe failed\n"); | ||
1725 | + | ||
1726 | + return ret; | ||
1727 | +} | ||
1728 | + | ||
1729 | +static int __devexit d_can_plat_remove(struct platform_device *pdev) | ||
1730 | +{ | ||
1731 | + struct net_device *ndev = platform_get_drvdata(pdev); | ||
1732 | + struct d_can_priv *priv = netdev_priv(ndev); | ||
1733 | + struct resource *mem; | ||
1734 | + | ||
1735 | + free_d_can_dev(ndev); | ||
1736 | + iounmap(priv->base); | ||
1737 | + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1738 | + release_mem_region(mem->start, resource_size(mem)); | ||
1739 | +#ifdef CONFIG_HAVE_CLK | ||
1740 | + clk_disable(priv->ick); | ||
1741 | + clk_disable(priv->fck); | ||
1742 | + clk_put(priv->ick); | ||
1743 | + clk_put(priv->fck); | ||
1744 | +#endif | ||
1745 | + unregister_d_can_dev(ndev); | ||
1746 | + platform_set_drvdata(pdev, NULL); | ||
1747 | + | ||
1748 | + return 0; | ||
1749 | +} | ||
1750 | + | ||
1751 | +static struct platform_driver d_can_plat_driver = { | ||
1752 | + .driver = { | ||
1753 | + .name = D_CAN_DRV_NAME, | ||
1754 | + .owner = THIS_MODULE, | ||
1755 | + }, | ||
1756 | + .probe = d_can_plat_probe, | ||
1757 | + .remove = __devexit_p(d_can_plat_remove), | ||
1758 | +}; | ||
1759 | + | ||
1760 | +static int __init d_can_plat_init(void) | ||
1761 | +{ | ||
1762 | + printk(KERN_INFO D_CAN_DRV_DESC "\n"); | ||
1763 | + return platform_driver_register(&d_can_plat_driver); | ||
1764 | +} | ||
1765 | +module_init(d_can_plat_init); | ||
1766 | + | ||
1767 | +static void __exit d_can_plat_exit(void) | ||
1768 | +{ | ||
1769 | + printk(KERN_INFO D_CAN_DRV_DESC " unloaded\n"); | ||
1770 | + platform_driver_unregister(&d_can_plat_driver); | ||
1771 | +} | ||
1772 | +module_exit(d_can_plat_exit); | ||
1773 | + | ||
1774 | +MODULE_AUTHOR("Anil Kumar Ch <anilkumar@ti.com>"); | ||
1775 | +MODULE_LICENSE("GPL v2"); | ||
1776 | +MODULE_VERSION(D_CAN_VERSION); | ||
1777 | +MODULE_DESCRIPTION(D_CAN_DRV_DESC); | ||
1778 | diff --git a/include/linux/can/platform/d_can.h b/include/linux/can/platform/d_can.h | ||
1779 | new file mode 100644 | ||
1780 | index 0000000..b139e05 | ||
1781 | --- /dev/null | ||
1782 | +++ b/include/linux/can/platform/d_can.h | ||
1783 | @@ -0,0 +1,53 @@ | ||
1784 | +#ifndef __CAN_PLATFORM_TI_D_CAN_H__ | ||
1785 | +#define __CAN_PLATFORM_TI_D_CAN_H__ | ||
1786 | + | ||
1787 | +/* | ||
1788 | + * D_CAN controller driver platform header | ||
1789 | + * | ||
1790 | + * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/ | ||
1791 | + * Anil Kumar Ch <anilkumar@ti.com> | ||
1792 | + * | ||
1793 | + * Bosch D_CAN controller is compliant to CAN protocol version 2.0 part A and B. | ||
1794 | + * Bosch D_CAN user manual can be obtained from: | ||
1795 | + * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/can/ | ||
1796 | + * d_can_users_manual_111.pdf | ||
1797 | + * | ||
1798 | + * This program is free software; you can redistribute it and/or | ||
1799 | + * modify it under the terms of the GNU General Public License as | ||
1800 | + * published by the Free Software Foundation version 2. | ||
1801 | + * | ||
1802 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
1803 | + * kind, whether express or implied; without even the implied warranty | ||
1804 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1805 | + * GNU General Public License for more details. | ||
1806 | + */ | ||
1807 | + | ||
1808 | +/** | ||
1809 | + * struct d_can_platform_data - DCAN Platform Data | ||
1810 | + * | ||
1811 | + * @d_can_offset: mostly 0 - should really never change | ||
1812 | + * @d_can_ram_offset: d_can RAM offset | ||
1813 | + * @msg_obj_offset: Mailbox RAM offset | ||
1814 | + * @num_of_msg_objs: Number of message objects | ||
1815 | + * @dma_support: DMA support is required/not | ||
1816 | + * test_mode_enable: Test mode enable bit | ||
1817 | + * @parity_check: Parity error checking is needed/not | ||
1818 | + * @version: version for future use | ||
1819 | + * @hw_raminit: platform specific callback fn for h/w ram init | ||
1820 | + * | ||
1821 | + * Platform data structure to get all platform specific settings. | ||
1822 | + * this structure also accounts the fact that the IP may have different | ||
1823 | + * RAM and mailbox offsets for different SOC's | ||
1824 | + */ | ||
1825 | +struct d_can_platform_data { | ||
1826 | + u32 d_can_offset; | ||
1827 | + u32 d_can_ram_offset; | ||
1828 | + u32 msg_obj_offset; | ||
1829 | + u32 num_of_msg_objs; | ||
1830 | + bool dma_support; | ||
1831 | + bool test_mode_enable; | ||
1832 | + bool parity_check; | ||
1833 | + u32 version; | ||
1834 | + void (*hw_raminit) (unsigned int); | ||
1835 | +}; | ||
1836 | +#endif | ||
1837 | -- | ||
1838 | 1.7.2.5 | ||
1839 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch new file mode 100644 index 00000000..c3fd4cda --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch | |||
@@ -0,0 +1,260 @@ | |||
1 | From f2da2b163827a075c98f1897801c90bf736784a3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Sun, 6 Nov 2011 02:46:12 +0530 | ||
4 | Subject: [PATCH 2/7] can: d_can: Added platform data for am33xx device | ||
5 | |||
6 | This patch adds the platform data needed by the driver. Added the | ||
7 | resources to the difference d_can instances. | ||
8 | |||
9 | Initialization of message ram is necessary to read/write the message object | ||
10 | from/into the message RAM | ||
11 | |||
12 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
13 | --- | ||
14 | arch/arm/mach-omap2/board-am335xevm.c | 131 ++++++++++++++++++++++++++++++ | ||
15 | arch/arm/mach-omap2/clock33xx_data.c | 18 ++++ | ||
16 | arch/arm/mach-omap2/mux33xx.c | 8 +- | ||
17 | arch/arm/plat-omap/include/plat/am33xx.h | 3 + | ||
18 | 4 files changed, 156 insertions(+), 4 deletions(-) | ||
19 | |||
20 | diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c | ||
21 | index c84857e..6773f3b 100644 | ||
22 | --- a/arch/arm/mach-omap2/board-am335xevm.c | ||
23 | +++ b/arch/arm/mach-omap2/board-am335xevm.c | ||
24 | @@ -24,6 +24,7 @@ | ||
25 | #include <linux/mtd/nand.h> | ||
26 | #include <linux/mtd/partitions.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | +#include <linux/can/platform/d_can.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/err.h> | ||
31 | #include <linux/wl12xx.h> | ||
32 | @@ -50,6 +51,7 @@ | ||
33 | /* LCD controller is similar to DA850 */ | ||
34 | #include <video/da8xx-fb.h> | ||
35 | |||
36 | +#include "control.h" | ||
37 | #include "board-flash.h" | ||
38 | #include "mux.h" | ||
39 | #include "devices.h" | ||
40 | @@ -991,6 +993,133 @@ static void mmc2_wl12xx_init(int evm_id, int profile) | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | +#define AM33XX_D_CAN_RAM_BASE 0x1000 | ||
45 | +#define AM33XX_D_CAN_NUM_MSG_OBJS 64 | ||
46 | +#define AM33XX_D_CAN_VERSION 0x1 | ||
47 | +#define AM33XX_CTL_DCAN_RAMINIT_OFFSET 0x644 | ||
48 | +#define AM33XX_D_CAN_RAMINIT_START(n) (0x1 << n) | ||
49 | + | ||
50 | +static void d_can_hw_raminit(unsigned int instance) | ||
51 | +{ | ||
52 | + u32 raminit_reg_val; | ||
53 | + | ||
54 | + /* Read the value */ | ||
55 | + raminit_reg_val = __raw_readl(AM33XX_CTRL_REGADDR( | ||
56 | + AM33XX_CTL_DCAN_RAMINIT_OFFSET)); | ||
57 | + | ||
58 | + /* Modify by setting "0" */ | ||
59 | + raminit_reg_val &= ~AM33XX_D_CAN_RAMINIT_START(instance); | ||
60 | + __raw_writel(raminit_reg_val, AM33XX_CTRL_REGADDR( | ||
61 | + AM33XX_CTL_DCAN_RAMINIT_OFFSET)); | ||
62 | + | ||
63 | + /* Reset to one */ | ||
64 | + raminit_reg_val |= AM33XX_D_CAN_RAMINIT_START(instance); | ||
65 | + __raw_writel(raminit_reg_val, AM33XX_CTRL_REGADDR( | ||
66 | + AM33XX_CTL_DCAN_RAMINIT_OFFSET)); | ||
67 | + udelay(10); | ||
68 | +} | ||
69 | + | ||
70 | +static struct d_can_platform_data am33xx_evm_d_can_pdata = { | ||
71 | + .d_can_offset = 0, | ||
72 | + .d_can_ram_offset = AM33XX_D_CAN_RAM_BASE, | ||
73 | + .num_of_msg_objs = AM33XX_D_CAN_NUM_MSG_OBJS, | ||
74 | + .dma_support = false, | ||
75 | + .test_mode_enable = false, | ||
76 | + .parity_check = false, | ||
77 | + .version = AM33XX_D_CAN_VERSION, | ||
78 | + .hw_raminit = d_can_hw_raminit, | ||
79 | +}; | ||
80 | + | ||
81 | +static struct resource am33xx_d_can0_resources[] = { | ||
82 | + { | ||
83 | + .start = AM33XX_D_CAN0_BASE, | ||
84 | + .end = AM33XX_D_CAN0_BASE + 0x3FFF, | ||
85 | + .flags = IORESOURCE_MEM, | ||
86 | + }, | ||
87 | + { | ||
88 | + .name = "d_can_int0", | ||
89 | + .start = AM33XX_IRQ_DCAN0_0, | ||
90 | + .end = AM33XX_IRQ_DCAN0_0, | ||
91 | + .flags = IORESOURCE_IRQ, | ||
92 | + }, | ||
93 | + { | ||
94 | + .name = "d_can_int1", | ||
95 | + .start = AM33XX_IRQ_DCAN0_1, | ||
96 | + .end = AM33XX_IRQ_DCAN0_1, | ||
97 | + .flags = IORESOURCE_IRQ, | ||
98 | + }, | ||
99 | +}; | ||
100 | + | ||
101 | +static struct platform_device am33xx_d_can0_device = { | ||
102 | + .dev = { | ||
103 | + .platform_data = &am33xx_evm_d_can_pdata, | ||
104 | + }, | ||
105 | + .name = "d_can", | ||
106 | + .id = 0, | ||
107 | + .num_resources = ARRAY_SIZE(am33xx_d_can0_resources), | ||
108 | + .resource = am33xx_d_can0_resources, | ||
109 | +}; | ||
110 | + | ||
111 | +static struct pinmux_config d_can0_pin_mux[] = { | ||
112 | + {"uart1_ctsn.d_can0_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL}, | ||
113 | + {"uart1_rtsn.d_can0_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP}, | ||
114 | + {NULL, 0}, | ||
115 | +}; | ||
116 | + | ||
117 | +static void d_can0_init(int evm_id, int profile) | ||
118 | +{ | ||
119 | + /* For instance 0 */ | ||
120 | + if (profile == PROFILE_1) { | ||
121 | + setup_pin_mux(d_can0_pin_mux); | ||
122 | + platform_device_register(&am33xx_d_can0_device); | ||
123 | + } | ||
124 | +} | ||
125 | + | ||
126 | +/* DCAN instnace 1 specific resources */ | ||
127 | +static struct resource am33xx_d_can1_resources[] = { | ||
128 | + { | ||
129 | + .start = AM33XX_D_CAN1_BASE, | ||
130 | + .end = AM33XX_D_CAN1_BASE + 0x3FFF, | ||
131 | + .flags = IORESOURCE_MEM, | ||
132 | + }, | ||
133 | + { | ||
134 | + .name = "d_can_int0", | ||
135 | + .start = AM33XX_IRQ_DCAN1_0, | ||
136 | + .end = AM33XX_IRQ_DCAN1_0, | ||
137 | + .flags = IORESOURCE_IRQ, | ||
138 | + }, | ||
139 | + { | ||
140 | + .name = "d_can_int1", | ||
141 | + .start = AM33XX_IRQ_DCAN1_1, | ||
142 | + .end = AM33XX_IRQ_DCAN1_1, | ||
143 | + .flags = IORESOURCE_IRQ, | ||
144 | + }, | ||
145 | +}; | ||
146 | + | ||
147 | +static struct platform_device am33xx_d_can1_device = { | ||
148 | + .dev = { | ||
149 | + .platform_data = &am33xx_evm_d_can_pdata, | ||
150 | + }, | ||
151 | + .name = "d_can", | ||
152 | + .id = 1, | ||
153 | + .num_resources = ARRAY_SIZE(am33xx_d_can1_resources), | ||
154 | + .resource = am33xx_d_can1_resources, | ||
155 | +}; | ||
156 | + | ||
157 | +static struct pinmux_config d_can1_pin_mux[] = { | ||
158 | + {"uart1_rxd.d_can1_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL}, | ||
159 | + {"uart1_txd.d_can1_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP}, | ||
160 | + {NULL, 0}, | ||
161 | +}; | ||
162 | + | ||
163 | +static void d_can1_init(int evm_id, int profile) | ||
164 | +{ | ||
165 | + /* For instance 1 */ | ||
166 | + if (profile == PROFILE_4) { | ||
167 | + setup_pin_mux(d_can1_pin_mux); | ||
168 | + platform_device_register(&am33xx_d_can1_device); | ||
169 | + } | ||
170 | +} | ||
171 | static void uart1_wl12xx_init(int evm_id, int profile) | ||
172 | { | ||
173 | setup_pin_mux(uart1_wl12xx_pin_mux); | ||
174 | @@ -1194,6 +1323,8 @@ static struct evm_dev_cfg gen_purp_evm_dev_cfg[] = { | ||
175 | {uart1_wl12xx_init, DEV_ON_BASEBOARD, (PROFILE_0 | PROFILE_3 | | ||
176 | PROFILE_5)}, | ||
177 | {wl12xx_init, DEV_ON_BASEBOARD, (PROFILE_0 | PROFILE_3 | PROFILE_5)}, | ||
178 | + {d_can0_init, DEV_ON_BASEBOARD, PROFILE_1}, | ||
179 | + {d_can1_init, DEV_ON_BASEBOARD, PROFILE_4}, | ||
180 | {NULL, 0, 0}, | ||
181 | }; | ||
182 | |||
183 | diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c | ||
184 | index 6763c59..d8670f2 100644 | ||
185 | --- a/arch/arm/mach-omap2/clock33xx_data.c | ||
186 | +++ b/arch/arm/mach-omap2/clock33xx_data.c | ||
187 | @@ -421,6 +421,22 @@ static struct clk dcan1_fck = { | ||
188 | .recalc = &followparent_recalc, | ||
189 | }; | ||
190 | |||
191 | +static struct clk dcan0_ick = { | ||
192 | + .name = "dcan0_ick", | ||
193 | + .parent = &dpll_per_m2_ck , | ||
194 | + .ops = &clkops_null, | ||
195 | + .clkdm_name = "l4ls_clkdm", | ||
196 | + .recalc = &followparent_recalc, | ||
197 | +}; | ||
198 | + | ||
199 | +static struct clk dcan1_ick = { | ||
200 | + .name = "dcan1_ick", | ||
201 | + .parent = &dpll_per_m2_ck , | ||
202 | + .ops = &clkops_null, | ||
203 | + .clkdm_name = "l4ls_clkdm", | ||
204 | + .recalc = &followparent_recalc, | ||
205 | +}; | ||
206 | + | ||
207 | static struct clk debugss_fck = { | ||
208 | .name = "debugss_fck", | ||
209 | .ops = &clkops_omap2_dflt, | ||
210 | @@ -1771,6 +1787,8 @@ static struct omap_clk am33xx_clks[] = { | ||
211 | CLK("cpsw.0", NULL, &cpgmac0_fck, CK_AM33XX), | ||
212 | CLK(NULL, "dcan0_fck", &dcan0_fck, CK_AM33XX), | ||
213 | CLK(NULL, "dcan1_fck", &dcan1_fck, CK_AM33XX), | ||
214 | + CLK(NULL, "dcan0_ick", &dcan0_ick, CK_AM33XX), | ||
215 | + CLK(NULL, "dcan1_ick", &dcan1_ick, CK_AM33XX), | ||
216 | CLK(NULL, "debugss_fck", &debugss_fck, CK_AM33XX), | ||
217 | CLK(NULL, "elm_fck", &elm_fck, CK_AM33XX), | ||
218 | CLK(NULL, "emif_fck", &emif_fck, CK_AM33XX), | ||
219 | diff --git a/arch/arm/mach-omap2/mux33xx.c b/arch/arm/mach-omap2/mux33xx.c | ||
220 | index 0286c4f..8232b46 100644 | ||
221 | --- a/arch/arm/mach-omap2/mux33xx.c | ||
222 | +++ b/arch/arm/mach-omap2/mux33xx.c | ||
223 | @@ -315,16 +315,16 @@ static struct omap_mux __initdata am33xx_muxmodes[] = { | ||
224 | "uart0_txd", "spi1_cs1", NULL, NULL, | ||
225 | NULL, NULL, NULL, NULL), | ||
226 | _AM33XX_MUXENTRY(UART1_CTSN, 0, | ||
227 | - "uart1_ctsn", NULL, NULL, NULL, | ||
228 | + "uart1_ctsn", NULL, "d_can0_tx", NULL, | ||
229 | "spi1_cs0", NULL, NULL, NULL), | ||
230 | _AM33XX_MUXENTRY(UART1_RTSN, 0, | ||
231 | - "uart1_rtsn", NULL, NULL, NULL, | ||
232 | + "uart1_rtsn", NULL, "d_can0_rx", NULL, | ||
233 | "spi1_cs1", NULL, NULL, NULL), | ||
234 | _AM33XX_MUXENTRY(UART1_RXD, 0, | ||
235 | - "uart1_rxd", "mmc1_sdwp", NULL, NULL, | ||
236 | + "uart1_rxd", "mmc1_sdwp", "d_can1_tx", NULL, | ||
237 | NULL, NULL, NULL, NULL), | ||
238 | _AM33XX_MUXENTRY(UART1_TXD, 0, | ||
239 | - "uart1_txd", "mmc2_sdwp", NULL, NULL, | ||
240 | + "uart1_txd", "mmc2_sdwp", "d_can1_rx", NULL, | ||
241 | NULL, NULL, NULL, NULL), | ||
242 | _AM33XX_MUXENTRY(I2C0_SDA, 0, | ||
243 | "i2c0_sda", NULL, NULL, NULL, | ||
244 | diff --git a/arch/arm/plat-omap/include/plat/am33xx.h b/arch/arm/plat-omap/include/plat/am33xx.h | ||
245 | index a77c38e..cfd1883 100644 | ||
246 | --- a/arch/arm/plat-omap/include/plat/am33xx.h | ||
247 | +++ b/arch/arm/plat-omap/include/plat/am33xx.h | ||
248 | @@ -30,6 +30,9 @@ | ||
249 | #define AM33XX_TSC_BASE 0x44E0D000 | ||
250 | #define AM33XX_RTC_BASE 0x44E3E000 | ||
251 | |||
252 | +#define AM33XX_D_CAN0_BASE 0x481CC000 | ||
253 | +#define AM33XX_D_CAN1_BASE 0x481D0000 | ||
254 | + | ||
255 | #define AM33XX_ASP0_BASE 0x48038000 | ||
256 | #define AM33XX_ASP1_BASE 0x4803C000 | ||
257 | |||
258 | -- | ||
259 | 1.7.2.5 | ||
260 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch new file mode 100644 index 00000000..57285194 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch | |||
@@ -0,0 +1,57 @@ | |||
1 | From 68a9166b306c9b7a542a8ddcf31cc5fa738f52b3 Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Sun, 6 Nov 2011 10:44:26 +0530 | ||
4 | Subject: [PATCH 3/7] can: d_can: DCAN config added to am335x_evm_defconfig | ||
5 | |||
6 | This patch adds the DCAN and dependent modules configurations | ||
7 | to am335x_evm_defconfig | ||
8 | |||
9 | Dependent modules are: | ||
10 | CONFIG_CAN_RAW | ||
11 | CONFIG_CAN_BCM | ||
12 | |||
13 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
14 | --- | ||
15 | arch/arm/configs/am335x_evm_defconfig | 26 +++++++++++++++++++++++++- | ||
16 | 1 files changed, 25 insertions(+), 1 deletions(-) | ||
17 | |||
18 | diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig | ||
19 | index 02ee0c3..a90dffd 100644 | ||
20 | --- a/arch/arm/configs/am335x_evm_defconfig | ||
21 | +++ b/arch/arm/configs/am335x_evm_defconfig | ||
22 | @@ -658,7 +658,31 @@ CONFIG_DNS_RESOLVER=y | ||
23 | # | ||
24 | # CONFIG_NET_PKTGEN is not set | ||
25 | # CONFIG_HAMRADIO is not set | ||
26 | -# CONFIG_CAN is not set | ||
27 | +CONFIG_CAN=y | ||
28 | +CONFIG_CAN_RAW=y | ||
29 | +CONFIG_CAN_BCM=y | ||
30 | + | ||
31 | +# | ||
32 | +# CAN Device Drivers | ||
33 | +# | ||
34 | +# CONFIG_CAN_VCAN is not set | ||
35 | +# CONFIG_CAN_SLCAN is not set | ||
36 | +CONFIG_CAN_DEV=y | ||
37 | +CONFIG_CAN_CALC_BITTIMING=y | ||
38 | +# CONFIG_CAN_TI_HECC is not set | ||
39 | +# CONFIG_CAN_MCP251X is not set | ||
40 | +# CONFIG_CAN_SJA1000 is not set | ||
41 | +# CONFIG_CAN_C_CAN is not set | ||
42 | +CONFIG_CAN_D_CAN=y | ||
43 | +CONFIG_CAN_D_CAN_PLATFORM=y | ||
44 | + | ||
45 | +# | ||
46 | +# CAN USB interfaces | ||
47 | +# | ||
48 | +# CONFIG_CAN_EMS_USB is not set | ||
49 | +# CONFIG_CAN_ESD_USB2 is not set | ||
50 | +# CONFIG_CAN_SOFTING is not set | ||
51 | +# CONFIG_CAN_DEBUG_DEVICES is not set | ||
52 | # CONFIG_IRDA is not set | ||
53 | CONFIG_BT=y | ||
54 | CONFIG_BT_L2CAP=y | ||
55 | -- | ||
56 | 1.7.2.5 | ||
57 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch new file mode 100644 index 00000000..7d7b397a --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch | |||
@@ -0,0 +1,49 @@ | |||
1 | From 3788f8da920468db766e5e8ec03785d2fc2c8f12 Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Thu, 10 Nov 2011 12:36:12 +0530 | ||
4 | Subject: [PATCH 4/7] can: d_can: fix for cansend loop issue | ||
5 | |||
6 | The specified number of packets are not transmitting with the | ||
7 | help of cansend --loop=10. This pacth fixes the issue and able | ||
8 | to transmit upto 32 packets. This limitation is because of no. | ||
9 | of objects availability on AM335X | ||
10 | |||
11 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
12 | --- | ||
13 | drivers/net/can/d_can/d_can.c | 6 +++--- | ||
14 | 1 files changed, 3 insertions(+), 3 deletions(-) | ||
15 | |||
16 | diff --git a/drivers/net/can/d_can/d_can.c b/drivers/net/can/d_can/d_can.c | ||
17 | index e001db0..d31b019 100644 | ||
18 | --- a/drivers/net/can/d_can/d_can.c | ||
19 | +++ b/drivers/net/can/d_can/d_can.c | ||
20 | @@ -611,7 +611,7 @@ static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, int objno) | ||
21 | * message object n, we need to handle the same properly. | ||
22 | */ | ||
23 | if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) & | ||
24 | - (1 << (objno - 1))) | ||
25 | + (1 << (objno - D_CAN_MSG_OBJ_TX_FIRST))) | ||
26 | return 1; | ||
27 | |||
28 | return 0; | ||
29 | @@ -858,7 +858,8 @@ static void d_can_do_tx(struct net_device *dev) | ||
30 | msg_obj_no = get_tx_echo_msg_obj(priv); | ||
31 | txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X); | ||
32 | txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)); | ||
33 | - if (!(txrq_reg_val & (1 << (msg_obj_no - 1)))) { | ||
34 | + if (!(txrq_reg_val & (1 << (msg_obj_no - | ||
35 | + D_CAN_MSG_OBJ_TX_FIRST)))) { | ||
36 | can_get_echo_skb(dev, | ||
37 | msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST); | ||
38 | stats->tx_bytes += d_can_read(priv, | ||
39 | @@ -1124,7 +1125,6 @@ static int d_can_poll(struct napi_struct *napi, int quota) | ||
40 | struct net_device *dev = napi->dev; | ||
41 | struct d_can_priv *priv = netdev_priv(dev); | ||
42 | |||
43 | - priv->irqstatus = d_can_read(priv, D_CAN_INT); | ||
44 | if (!priv->irqstatus) | ||
45 | goto end; | ||
46 | |||
47 | -- | ||
48 | 1.7.2.5 | ||
49 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch new file mode 100644 index 00000000..5c8b0633 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch | |||
@@ -0,0 +1,60 @@ | |||
1 | From 332ec54d00463875532584604f364fc4347d918b Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Thu, 10 Nov 2011 17:59:16 +0530 | ||
4 | Subject: [PATCH 5/7] can: d_can: fixes the rmmod crash | ||
5 | |||
6 | This patch fixes the rmmod crash while unloading the | ||
7 | DCAN driver from the kernel. | ||
8 | |||
9 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
10 | --- | ||
11 | drivers/net/can/d_can/d_can_platform.c | 11 +++++------ | ||
12 | 1 files changed, 5 insertions(+), 6 deletions(-) | ||
13 | |||
14 | diff --git a/drivers/net/can/d_can/d_can_platform.c b/drivers/net/can/d_can/d_can_platform.c | ||
15 | index b430a18..859756b 100644 | ||
16 | --- a/drivers/net/can/d_can/d_can_platform.c | ||
17 | +++ b/drivers/net/can/d_can/d_can_platform.c | ||
18 | @@ -190,7 +190,6 @@ exit_iounmap: | ||
19 | exit_release_mem: | ||
20 | release_mem_region(mem->start, resource_size(mem)); | ||
21 | exit_free_clks: | ||
22 | -#ifdef CONFIG_HAVE_CLK | ||
23 | clk_disable(priv->ick); | ||
24 | clk_put(priv->ick); | ||
25 | exit_free_fck: | ||
26 | @@ -199,7 +198,6 @@ exit_free_fck: | ||
27 | exit_free_ndev: | ||
28 | free_d_can_dev(ndev); | ||
29 | exit: | ||
30 | -#endif | ||
31 | dev_err(&pdev->dev, "probe failed\n"); | ||
32 | |||
33 | return ret; | ||
34 | @@ -211,18 +209,19 @@ static int __devexit d_can_plat_remove(struct platform_device *pdev) | ||
35 | struct d_can_priv *priv = netdev_priv(ndev); | ||
36 | struct resource *mem; | ||
37 | |||
38 | + unregister_d_can_dev(ndev); | ||
39 | + platform_set_drvdata(pdev, NULL); | ||
40 | + | ||
41 | free_d_can_dev(ndev); | ||
42 | iounmap(priv->base); | ||
43 | + | ||
44 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
45 | release_mem_region(mem->start, resource_size(mem)); | ||
46 | -#ifdef CONFIG_HAVE_CLK | ||
47 | + | ||
48 | clk_disable(priv->ick); | ||
49 | clk_disable(priv->fck); | ||
50 | clk_put(priv->ick); | ||
51 | clk_put(priv->fck); | ||
52 | -#endif | ||
53 | - unregister_d_can_dev(ndev); | ||
54 | - platform_set_drvdata(pdev, NULL); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | -- | ||
59 | 1.7.2.5 | ||
60 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch new file mode 100644 index 00000000..123266f2 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch | |||
@@ -0,0 +1,47 @@ | |||
1 | From 0aea3e2629cd1681d8d8e6e0a4409959b31ea4e9 Mon Sep 17 00:00:00 2001 | ||
2 | From: Anil Kumar Ch <anilkumar@ti.com> | ||
3 | Date: Thu, 10 Nov 2011 15:21:47 +0100 | ||
4 | Subject: [PATCH 7/7] can: d_can: am335x profile modification for dcan0 | ||
5 | |||
6 | This patch modifies the profile information of am335x device. | ||
7 | |||
8 | Profile reads of cpld_client from smbus gives an error leads to put | ||
9 | the device into default profile 0. So by default the board configured | ||
10 | to beaglebone even if we set the sw8 switch on daughter card to other | ||
11 | profiles. | ||
12 | |||
13 | This patch makes all the IO connecters are configured in profile 1. | ||
14 | |||
15 | Signed-off-by: Anil Kumar Ch <anilkumar@ti.com> | ||
16 | --- | ||
17 | arch/arm/mach-omap2/board-am335xevm.c | 7 +++++-- | ||
18 | 1 files changed, 5 insertions(+), 2 deletions(-) | ||
19 | |||
20 | diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c | ||
21 | index 590c4ca..ac64fc7 100644 | ||
22 | --- a/arch/arm/mach-omap2/board-am335xevm.c | ||
23 | +++ b/arch/arm/mach-omap2/board-am335xevm.c | ||
24 | @@ -340,6 +340,9 @@ static u32 am335x_get_profile_selection(void) | ||
25 | { | ||
26 | int val = 0; | ||
27 | |||
28 | + /* FIXME: temporary fix */ | ||
29 | + return 1; | ||
30 | + | ||
31 | if (!cpld_client) | ||
32 | /* error checking is not done in func's calling this routine. | ||
33 | so return profile 0 on error */ | ||
34 | @@ -1721,8 +1724,8 @@ out: | ||
35 | */ | ||
36 | pr_err("Could not detect any board, falling back to: " | ||
37 | "Beaglebone (< Rev A3) with no daughter card connected\n"); | ||
38 | - daughter_brd_detected = false; | ||
39 | - setup_beaglebone_old(); | ||
40 | + daughter_brd_detected = true; | ||
41 | + setup_general_purpose_evm(); | ||
42 | |||
43 | /* Initialize cpsw after board detection is completed as board | ||
44 | * information is required for configuring phy address and hence | ||
45 | -- | ||
46 | 1.7.2.5 | ||
47 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp_3.1.bb b/recipes-kernel/linux/linux-ti33x-psp_3.1.bb index 836c5f82..c4cdfea9 100644 --- a/recipes-kernel/linux/linux-ti33x-psp_3.1.bb +++ b/recipes-kernel/linux/linux-ti33x-psp_3.1.bb | |||
@@ -35,6 +35,12 @@ PATCHES_OVER_PSP = " \ | |||
35 | file://0003-arm-omap-mcspi-correct-memory-range-when-requesting-.patch \ | 35 | file://0003-arm-omap-mcspi-correct-memory-range-when-requesting-.patch \ |
36 | file://0004-arm-omap-mcspi-follow-proper-pm_runtime-enable-disab.patch \ | 36 | file://0004-arm-omap-mcspi-follow-proper-pm_runtime-enable-disab.patch \ |
37 | file://0005-arm-omap-mcspi-follow-proper-probe-remove-steps.patch \ | 37 | file://0005-arm-omap-mcspi-follow-proper-probe-remove-steps.patch \ |
38 | file://can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch \ | ||
39 | file://can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch \ | ||
40 | file://can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch \ | ||
41 | file://can/0004-can-d_can-fix-for-cansend-loop-issue.patch \ | ||
42 | file://can/0005-can-d_can-fixes-the-rmmod-crash.patch \ | ||
43 | file://can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch \ | ||
38 | " | 44 | " |
39 | 45 | ||
40 | SRC_URI += "${@base_contains('DISTRO_FEATURES', 'tipspkernel', "", "${PATCHES_OVER_PSP}", d)}" | 46 | SRC_URI += "${@base_contains('DISTRO_FEATURES', 'tipspkernel', "", "${PATCHES_OVER_PSP}", d)}" |