summaryrefslogtreecommitdiff
path: root/drivers/net/can/flexcan/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can/flexcan/dev.c')
-rw-r--r--drivers/net/can/flexcan/dev.c112
1 files changed, 110 insertions, 2 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);