summaryrefslogtreecommitdiff
path: root/drivers/net/can/flexcan
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can/flexcan')
-rw-r--r--drivers/net/can/flexcan/dev.c112
-rw-r--r--drivers/net/can/flexcan/flexcan.h31
-rw-r--r--drivers/net/can/flexcan/mbm.c74
3 files changed, 169 insertions, 48 deletions
diff --git a/drivers/net/can/flexcan/dev.c b/drivers/net/can/flexcan/dev.c
index 389f85d75709..404877c33eab 100644
--- a/drivers/net/can/flexcan/dev.c
+++ b/drivers/net/can/flexcan/dev.c
@@ -35,6 +35,74 @@
#endif
#include "flexcan.h"
+#define DEFAULT_BITRATE 500000
+#define TIME_SEGMENT_MIN 8
+#define TIME_SEGMENT_MAX 25
+#define TIME_SEGMENT_MID ((TIME_SEGMENT_MIN + TIME_SEGMENT_MAX)/2)
+
+struct time_segment {
+ char propseg;
+ char pseg1;
+ char pseg2;
+};
+
+struct time_segment time_segments[] = {
+ { /* total 8 timequanta */
+ 1, 2, 1
+ },
+ { /* total 9 timequanta */
+ 1, 2, 2
+ },
+ { /* total 10 timequanta */
+ 2, 2, 2
+ },
+ { /* total 11 timequanta */
+ 2, 2, 3
+ },
+ { /* total 12 timequanta */
+ 2, 3, 3
+ },
+ { /* total 13 timequanta */
+ 3, 3, 3
+ },
+ { /* total 14 timequanta */
+ 3, 3, 4
+ },
+ { /* total 15 timequanta */
+ 3, 4, 4
+ },
+ { /* total 16 timequanta */
+ 4, 4, 4
+ },
+ { /* total 17 timequanta */
+ 4, 4, 5
+ },
+ { /* total 18 timequanta */
+ 4, 5, 5
+ },
+ { /* total 19 timequanta */
+ 5, 5, 5
+ },
+ { /* total 20 timequanta */
+ 5, 5, 6
+ },
+ { /* total 21 timequanta */
+ 5, 6, 6
+ },
+ { /* total 22 timequanta */
+ 6, 6, 6
+ },
+ { /* total 23 timequanta */
+ 6, 6, 7
+ },
+ { /* total 24 timequanta */
+ 6, 7, 7
+ },
+ { /* total 25 timequanta */
+ 7, 7, 7
+ },
+};
+
enum {
FLEXCAN_ATTR_STATE = 0,
FLEXCAN_ATTR_BITRATE,
@@ -138,6 +206,45 @@ static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)
* based on the bitrate to get the timing of
* presdiv, pseg1, pseg2, propseg
*/
+ int i, rate, div;
+ bool found = false;
+ struct time_segment *segment;
+ rate = clk_get_rate(flexcan->clk);
+
+ if (!bitrate)
+ bitrate = DEFAULT_BITRATE;
+
+ if (rate % bitrate == 0) {
+ div = rate / bitrate;
+ for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (i = TIME_SEGMENT_MID - 1;
+ i >= TIME_SEGMENT_MIN; i--) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ }
+ }
+
+ if (found) {
+ segment = &time_segments[i - TIME_SEGMENT_MIN];
+ flexcan->br_presdiv = div/i - 1;
+ flexcan->br_propseg = segment->propseg;
+ flexcan->br_pseg1 = segment->pseg1;
+ flexcan->br_pseg2 = segment->pseg2;
+ flexcan->bitrate = bitrate;
+ } else {
+ pr_info("The bitrate %d can't supported with clock \
+ rate of %d \n", bitrate, rate);
+ }
}
static void flexcan_update_bitrate(struct flexcan_device *flexcan)
@@ -201,7 +308,7 @@ static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -214,7 +321,7 @@ static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -575,6 +682,7 @@ struct net_device *flexcan_device_alloc(struct platform_device *pdev,
return NULL;
}
flexcan_device_default(flexcan);
+ flexcan_set_bitrate(flexcan, flexcan->bitrate);
flexcan_update_bitrate(flexcan);
num = ARRAY_SIZE(flexcan_dev_attr);
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index d19cc1ee0620..51a800bd8e55 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,17 +32,6 @@
#define FLEXCAN_DEVICE_NAME "FlexCAN"
-struct can_mb_cs {
- unsigned int time_stamp:16;
- unsigned int length:4;
- unsigned int rtr:1;
- unsigned int ide:1;
- unsigned int srr:1;
- unsigned int nouse1:1;
- unsigned int code:4;
- unsigned int nouse2:4;
-};
-
#define CAN_MB_RX_INACTIVE 0x0
#define CAN_MB_RX_EMPTY 0x4
#define CAN_MB_RX_FULL 0x2
@@ -55,14 +44,24 @@ struct can_mb_cs {
#define CAN_MB_TX_REMOTE 0xA
struct can_hw_mb {
- union {
- struct can_mb_cs cs;
- unsigned int data;
- } mb_cs;
+ unsigned int mb_cs;
unsigned int mb_id;
unsigned char mb_data[8];
};
+#define MB_CS_CODE_OFFSET 24
+#define MB_CS_CODE_MASK (0xF << MB_CS_CODE_OFFSET)
+#define MB_CS_SRR_OFFSET 22
+#define MB_CS_SRR_MASK (0x1 << MB_CS_SRR_OFFSET)
+#define MB_CS_IDE_OFFSET 21
+#define MB_CS_IDE_MASK (0x1 << MB_CS_IDE_OFFSET)
+#define MB_CS_RTR_OFFSET 20
+#define MB_CS_RTR_MASK (0x1 << MB_CS_RTR_OFFSET)
+#define MB_CS_LENGTH_OFFSET 16
+#define MB_CS_LENGTH_MASK (0xF << MB_CS_LENGTH_OFFSET)
+#define MB_CS_TIMESTAMP_OFFSET 0
+#define MB_CS_TIMESTAMP_MASK (0xFF << MB_CS_TIMESTAMP_OFFSET)
+
#define CAN_HW_REG_MCR 0x00
#define CAN_HW_REG_CTRL 0x04
#define CAN_HW_REG_TIMER 0x08
diff --git a/drivers/net/can/flexcan/mbm.c b/drivers/net/can/flexcan/mbm.c
index b0341ba9128e..c846d97daadb 100644
--- a/drivers/net/can/flexcan/mbm.c
+++ b/drivers/net/can/flexcan/mbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -55,10 +55,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
hwmb = flexcan->hwmb + index;
if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT)
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ if ((hwmb->mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_ABORT) {
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
- if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) {
+ if (hwmb->mb_cs & (CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET)) {
if (netif_queue_stopped(dev))
netif_start_queue(dev);
return;
@@ -68,16 +71,17 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (skb) {
frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && frame->can_dlc)
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -85,7 +89,8 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -101,13 +106,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
-
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -131,17 +136,19 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
frame =
(struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id =
(hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >>
+ MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && (frame->can_dlc <= 8))
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -158,7 +165,7 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
@@ -252,7 +259,8 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
struct can_hw_mb *hwmb = flexcan->hwmb;
do {
- if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE)
+ if ((hwmb[i].mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_INACTIVE)
break;
if ((++i) > flexcan->maxmb) {
if (flexcan->fifo)
@@ -273,22 +281,24 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
}
if (frame->can_id & CAN_RTR_FLAG)
- hwmb[i].mb_cs.cs.rtr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_RTR_OFFSET;
else
- hwmb[i].mb_cs.cs.rtr = 0;
+ hwmb[i].mb_cs &= ~MB_CS_RTR_MASK;
if (frame->can_id & CAN_EFF_FLAG) {
- hwmb[i].mb_cs.cs.ide = 1;
- hwmb[i].mb_cs.cs.srr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
+ hwmb[i].mb_cs |= 1 << MB_CS_SRR_OFFSET;
hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK;
} else {
- hwmb[i].mb_cs.cs.ide = 0;
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18;
}
- hwmb[i].mb_cs.cs.length = frame->can_dlc;
+ hwmb[i].mb_cs &= ~MB_CS_LENGTH_MASK;
+ hwmb[i].mb_cs |= frame->can_dlc << MB_CS_LENGTH_OFFSET;
flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc);
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_ONCE << MB_CS_CODE_OFFSET;
return 0;
}
@@ -325,23 +335,27 @@ void flexcan_mbm_init(struct flexcan_device *flexcan)
id_table[i] = 0;
} else {
for (i = 0; i < rx_mb; i++) {
- hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_RX_EMPTY << MB_CS_CODE_OFFSET;
/*
* IDE bit can not control by mask registers
* So set message buffer to receive extend
* or standard message.
*/
- if (flexcan->ext_msg && flexcan->std_msg)
- hwmb[i].mb_cs.cs.ide = i & 1;
- else {
+ if (flexcan->ext_msg && flexcan->std_msg) {
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
+ hwmb[i].mb_cs |= (i & 1) << MB_CS_IDE_OFFSET;
+ } else {
if (flexcan->ext_msg)
- hwmb[i].mb_cs.cs.ide = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
}
}
}
- for (; i <= flexcan->maxmb; i++)
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ for (; i <= flexcan->maxmb; i++) {
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
flexcan->xmit_mb = rx_mb;
}