diff options
author | Hui Wang <jason77.wang@gmail.com> | 2012-06-28 04:21:35 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2012-07-03 03:33:00 -0400 |
commit | 30c1e672044d98e5c4cff5fcbdb34b55a2df0c0f (patch) | |
tree | 6b12a4975cb050ecc7eda4273a26d58ee92cb5bd /drivers/net/can/flexcan.c | |
parent | afc016d8360ceb19a1f37bf6579d5850d47d582d (diff) |
can: flexcan: add hardware controller version support
At least in the i.MX series, the flexcan contrller divides into ver_3
and ver_10, current driver is for ver_3 controller.
i.MX6 has ver_10 controller, it has more reigsters than ver_3 has.
The rxfgmask (Rx FIFO Global Mask) register is one of the new added.
Its reset value is 0xffffffff, this means ID Filter Table must be
checked when receive a packet, but the driver is designed to accept
everything during the chip start, we need to clear this register to
follow this design.
Use the data entry of the struct of_device_id to point chip specific
info, we can set hardware version for each platform.
Cc: linux-can@vger.kernel.org
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Wolfgang Grandegger <wg@grandegger.com>
Cc: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Hui Wang <jason77.wang@gmail.com>
[mkl: add id_table support]
Tested-by: Hui Wang <jason77.wang@gmail.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can/flexcan.c')
-rw-r--r-- | drivers/net/can/flexcan.c | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index b429b3f3fa7f..81324a11a50f 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/of_device.h> | ||
37 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
38 | #include <linux/pinctrl/consumer.h> | 39 | #include <linux/pinctrl/consumer.h> |
39 | 40 | ||
@@ -165,10 +166,21 @@ struct flexcan_regs { | |||
165 | u32 imask1; /* 0x28 */ | 166 | u32 imask1; /* 0x28 */ |
166 | u32 iflag2; /* 0x2c */ | 167 | u32 iflag2; /* 0x2c */ |
167 | u32 iflag1; /* 0x30 */ | 168 | u32 iflag1; /* 0x30 */ |
168 | u32 _reserved2[19]; | 169 | u32 crl2; /* 0x34 */ |
170 | u32 esr2; /* 0x38 */ | ||
171 | u32 imeur; /* 0x3c */ | ||
172 | u32 lrfr; /* 0x40 */ | ||
173 | u32 crcr; /* 0x44 */ | ||
174 | u32 rxfgmask; /* 0x48 */ | ||
175 | u32 rxfir; /* 0x4c */ | ||
176 | u32 _reserved3[12]; | ||
169 | struct flexcan_mb cantxfg[64]; | 177 | struct flexcan_mb cantxfg[64]; |
170 | }; | 178 | }; |
171 | 179 | ||
180 | struct flexcan_devtype_data { | ||
181 | u32 hw_ver; /* hardware controller version */ | ||
182 | }; | ||
183 | |||
172 | struct flexcan_priv { | 184 | struct flexcan_priv { |
173 | struct can_priv can; | 185 | struct can_priv can; |
174 | struct net_device *dev; | 186 | struct net_device *dev; |
@@ -180,6 +192,15 @@ struct flexcan_priv { | |||
180 | 192 | ||
181 | struct clk *clk; | 193 | struct clk *clk; |
182 | struct flexcan_platform_data *pdata; | 194 | struct flexcan_platform_data *pdata; |
195 | struct flexcan_devtype_data *devtype_data; | ||
196 | }; | ||
197 | |||
198 | static struct flexcan_devtype_data fsl_p1010_devtype_data = { | ||
199 | .hw_ver = 3, | ||
200 | }; | ||
201 | |||
202 | static struct flexcan_devtype_data fsl_imx6q_devtype_data = { | ||
203 | .hw_ver = 10, | ||
183 | }; | 204 | }; |
184 | 205 | ||
185 | static struct can_bittiming_const flexcan_bittiming_const = { | 206 | static struct can_bittiming_const flexcan_bittiming_const = { |
@@ -750,6 +771,9 @@ static int flexcan_chip_start(struct net_device *dev) | |||
750 | flexcan_write(0x0, ®s->rx14mask); | 771 | flexcan_write(0x0, ®s->rx14mask); |
751 | flexcan_write(0x0, ®s->rx15mask); | 772 | flexcan_write(0x0, ®s->rx15mask); |
752 | 773 | ||
774 | if (priv->devtype_data->hw_ver >= 10) | ||
775 | flexcan_write(0x0, ®s->rxfgmask); | ||
776 | |||
753 | flexcan_transceiver_switch(priv, 1); | 777 | flexcan_transceiver_switch(priv, 1); |
754 | 778 | ||
755 | /* synchronize with the can bus */ | 779 | /* synchronize with the can bus */ |
@@ -922,8 +946,21 @@ static void __devexit unregister_flexcandev(struct net_device *dev) | |||
922 | unregister_candev(dev); | 946 | unregister_candev(dev); |
923 | } | 947 | } |
924 | 948 | ||
949 | static const struct of_device_id flexcan_of_match[] = { | ||
950 | { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, | ||
951 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, | ||
952 | { /* sentinel */ }, | ||
953 | }; | ||
954 | |||
955 | static const struct platform_device_id flexcan_id_table[] = { | ||
956 | { .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, | ||
957 | { /* sentinel */ }, | ||
958 | }; | ||
959 | |||
925 | static int __devinit flexcan_probe(struct platform_device *pdev) | 960 | static int __devinit flexcan_probe(struct platform_device *pdev) |
926 | { | 961 | { |
962 | const struct of_device_id *of_id; | ||
963 | struct flexcan_devtype_data *devtype_data; | ||
927 | struct net_device *dev; | 964 | struct net_device *dev; |
928 | struct flexcan_priv *priv; | 965 | struct flexcan_priv *priv; |
929 | struct resource *mem; | 966 | struct resource *mem; |
@@ -977,6 +1014,17 @@ static int __devinit flexcan_probe(struct platform_device *pdev) | |||
977 | goto failed_alloc; | 1014 | goto failed_alloc; |
978 | } | 1015 | } |
979 | 1016 | ||
1017 | of_id = of_match_device(flexcan_of_match, &pdev->dev); | ||
1018 | if (of_id) { | ||
1019 | devtype_data = of_id->data; | ||
1020 | } else if (pdev->id_entry->driver_data) { | ||
1021 | devtype_data = (struct flexcan_devtype_data *) | ||
1022 | pdev->id_entry->driver_data; | ||
1023 | } else { | ||
1024 | err = -ENODEV; | ||
1025 | goto failed_devtype; | ||
1026 | } | ||
1027 | |||
980 | dev->netdev_ops = &flexcan_netdev_ops; | 1028 | dev->netdev_ops = &flexcan_netdev_ops; |
981 | dev->irq = irq; | 1029 | dev->irq = irq; |
982 | dev->flags |= IFF_ECHO; | 1030 | dev->flags |= IFF_ECHO; |
@@ -993,6 +1041,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev) | |||
993 | priv->dev = dev; | 1041 | priv->dev = dev; |
994 | priv->clk = clk; | 1042 | priv->clk = clk; |
995 | priv->pdata = pdev->dev.platform_data; | 1043 | priv->pdata = pdev->dev.platform_data; |
1044 | priv->devtype_data = devtype_data; | ||
996 | 1045 | ||
997 | netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); | 1046 | netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); |
998 | 1047 | ||
@@ -1011,6 +1060,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev) | |||
1011 | return 0; | 1060 | return 0; |
1012 | 1061 | ||
1013 | failed_register: | 1062 | failed_register: |
1063 | failed_devtype: | ||
1014 | free_candev(dev); | 1064 | free_candev(dev); |
1015 | failed_alloc: | 1065 | failed_alloc: |
1016 | iounmap(base); | 1066 | iounmap(base); |
@@ -1044,13 +1094,6 @@ static int __devexit flexcan_remove(struct platform_device *pdev) | |||
1044 | return 0; | 1094 | return 0; |
1045 | } | 1095 | } |
1046 | 1096 | ||
1047 | static struct of_device_id flexcan_of_match[] = { | ||
1048 | { | ||
1049 | .compatible = "fsl,p1010-flexcan", | ||
1050 | }, | ||
1051 | {}, | ||
1052 | }; | ||
1053 | |||
1054 | #ifdef CONFIG_PM | 1097 | #ifdef CONFIG_PM |
1055 | static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) | 1098 | static int flexcan_suspend(struct platform_device *pdev, pm_message_t state) |
1056 | { | 1099 | { |
@@ -1097,6 +1140,7 @@ static struct platform_driver flexcan_driver = { | |||
1097 | .remove = __devexit_p(flexcan_remove), | 1140 | .remove = __devexit_p(flexcan_remove), |
1098 | .suspend = flexcan_suspend, | 1141 | .suspend = flexcan_suspend, |
1099 | .resume = flexcan_resume, | 1142 | .resume = flexcan_resume, |
1143 | .id_table = flexcan_id_table, | ||
1100 | }; | 1144 | }; |
1101 | 1145 | ||
1102 | module_platform_driver(flexcan_driver); | 1146 | module_platform_driver(flexcan_driver); |