diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-platform-at91 | 25 | ||||
| -rw-r--r-- | drivers/net/can/at91_can.c | 90 |
2 files changed, 108 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-at91 b/Documentation/ABI/testing/sysfs-platform-at91 new file mode 100644 index 000000000000..4cc6a865ae66 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-at91 | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | What: /sys/devices/platform/at91_can/net/<iface>/mb0_id | ||
| 2 | Date: January 2011 | ||
| 3 | KernelVersion: 2.6.38 | ||
| 4 | Contact: Marc Kleine-Budde <kernel@pengutronix.de> | ||
| 5 | Description: | ||
| 6 | Value representing the can_id of mailbox 0. | ||
| 7 | |||
| 8 | Default: 0x7ff (standard frame) | ||
| 9 | |||
| 10 | Due to a chip bug (errata 50.2.6.3 & 50.3.5.3 in | ||
| 11 | "AT91SAM9263 Preliminary 6249H-ATARM-27-Jul-09") the | ||
| 12 | contents of mailbox 0 may be send under certain | ||
| 13 | conditions (even if disabled or in rx mode). | ||
| 14 | |||
| 15 | The workaround in the errata suggests not to use the | ||
| 16 | mailbox and load it with an unused identifier. | ||
| 17 | |||
| 18 | In order to use an extended can_id add the | ||
| 19 | CAN_EFF_FLAG (0x80000000U) to the can_id. Example: | ||
| 20 | |||
| 21 | - standard id 0x7ff: | ||
| 22 | echo 0x7ff > /sys/class/net/can0/mb0_id | ||
| 23 | |||
| 24 | - extended id 0x1fffffff: | ||
| 25 | echo 0x9fffffff > /sys/class/net/can0/mb0_id | ||
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 16e45a51cbb3..2532b9631538 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
| 32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
| 33 | #include <linux/rtnetlink.h> | ||
| 33 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
| 34 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
| 35 | #include <linux/string.h> | 36 | #include <linux/string.h> |
| @@ -169,6 +170,8 @@ struct at91_priv { | |||
| 169 | 170 | ||
| 170 | struct clk *clk; | 171 | struct clk *clk; |
| 171 | struct at91_can_data *pdata; | 172 | struct at91_can_data *pdata; |
| 173 | |||
| 174 | canid_t mb0_id; | ||
| 172 | }; | 175 | }; |
| 173 | 176 | ||
| 174 | static struct can_bittiming_const at91_bittiming_const = { | 177 | static struct can_bittiming_const at91_bittiming_const = { |
| @@ -221,6 +224,18 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb, | |||
| 221 | set_mb_mode_prio(priv, mb, mode, 0); | 224 | set_mb_mode_prio(priv, mb, mode, 0); |
| 222 | } | 225 | } |
| 223 | 226 | ||
| 227 | static inline u32 at91_can_id_to_reg_mid(canid_t can_id) | ||
| 228 | { | ||
| 229 | u32 reg_mid; | ||
| 230 | |||
| 231 | if (can_id & CAN_EFF_FLAG) | ||
| 232 | reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE; | ||
| 233 | else | ||
| 234 | reg_mid = (can_id & CAN_SFF_MASK) << 18; | ||
| 235 | |||
| 236 | return reg_mid; | ||
| 237 | } | ||
| 238 | |||
| 224 | /* | 239 | /* |
| 225 | * Swtich transceiver on or off | 240 | * Swtich transceiver on or off |
| 226 | */ | 241 | */ |
| @@ -234,6 +249,7 @@ static void at91_setup_mailboxes(struct net_device *dev) | |||
| 234 | { | 249 | { |
| 235 | struct at91_priv *priv = netdev_priv(dev); | 250 | struct at91_priv *priv = netdev_priv(dev); |
| 236 | unsigned int i; | 251 | unsigned int i; |
| 252 | u32 reg_mid; | ||
| 237 | 253 | ||
| 238 | /* | 254 | /* |
| 239 | * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first | 255 | * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first |
| @@ -242,8 +258,13 @@ static void at91_setup_mailboxes(struct net_device *dev) | |||
| 242 | * overwrite option. The overwrite flag indicates a FIFO | 258 | * overwrite option. The overwrite flag indicates a FIFO |
| 243 | * overflow. | 259 | * overflow. |
| 244 | */ | 260 | */ |
| 245 | for (i = 0; i < AT91_MB_RX_FIRST; i++) | 261 | reg_mid = at91_can_id_to_reg_mid(priv->mb0_id); |
| 262 | for (i = 0; i < AT91_MB_RX_FIRST; i++) { | ||
| 246 | set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); | 263 | set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); |
| 264 | at91_write(priv, AT91_MID(i), reg_mid); | ||
| 265 | at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */ | ||
| 266 | } | ||
| 267 | |||
| 247 | for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) | 268 | for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) |
| 248 | set_mb_mode(priv, i, AT91_MB_MODE_RX); | 269 | set_mb_mode(priv, i, AT91_MB_MODE_RX); |
| 249 | set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); | 270 | set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); |
| @@ -378,12 +399,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 378 | netdev_err(dev, "BUG! TX buffer full when queue awake!\n"); | 399 | netdev_err(dev, "BUG! TX buffer full when queue awake!\n"); |
| 379 | return NETDEV_TX_BUSY; | 400 | return NETDEV_TX_BUSY; |
| 380 | } | 401 | } |
| 381 | 402 | reg_mid = at91_can_id_to_reg_mid(cf->can_id); | |
| 382 | if (cf->can_id & CAN_EFF_FLAG) | ||
| 383 | reg_mid = (cf->can_id & CAN_EFF_MASK) | AT91_MID_MIDE; | ||
| 384 | else | ||
| 385 | reg_mid = (cf->can_id & CAN_SFF_MASK) << 18; | ||
| 386 | |||
| 387 | reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) | | 403 | reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) | |
| 388 | (cf->can_dlc << 16) | AT91_MCR_MTCR; | 404 | (cf->can_dlc << 16) | AT91_MCR_MTCR; |
| 389 | 405 | ||
| @@ -1047,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = { | |||
| 1047 | .ndo_start_xmit = at91_start_xmit, | 1063 | .ndo_start_xmit = at91_start_xmit, |
| 1048 | }; | 1064 | }; |
| 1049 | 1065 | ||
| 1066 | static ssize_t at91_sysfs_show_mb0_id(struct device *dev, | ||
| 1067 | struct device_attribute *attr, char *buf) | ||
| 1068 | { | ||
| 1069 | struct at91_priv *priv = netdev_priv(to_net_dev(dev)); | ||
| 1070 | |||
| 1071 | if (priv->mb0_id & CAN_EFF_FLAG) | ||
| 1072 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id); | ||
| 1073 | else | ||
| 1074 | return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | static ssize_t at91_sysfs_set_mb0_id(struct device *dev, | ||
| 1078 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 1079 | { | ||
| 1080 | struct net_device *ndev = to_net_dev(dev); | ||
| 1081 | struct at91_priv *priv = netdev_priv(ndev); | ||
| 1082 | unsigned long can_id; | ||
| 1083 | ssize_t ret; | ||
| 1084 | int err; | ||
| 1085 | |||
| 1086 | rtnl_lock(); | ||
| 1087 | |||
| 1088 | if (ndev->flags & IFF_UP) { | ||
| 1089 | ret = -EBUSY; | ||
| 1090 | goto out; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | err = strict_strtoul(buf, 0, &can_id); | ||
| 1094 | if (err) { | ||
| 1095 | ret = err; | ||
| 1096 | goto out; | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | if (can_id & CAN_EFF_FLAG) | ||
| 1100 | can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; | ||
| 1101 | else | ||
| 1102 | can_id &= CAN_SFF_MASK; | ||
| 1103 | |||
| 1104 | priv->mb0_id = can_id; | ||
| 1105 | ret = count; | ||
| 1106 | |||
| 1107 | out: | ||
| 1108 | rtnl_unlock(); | ||
| 1109 | return ret; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | static DEVICE_ATTR(mb0_id, S_IWUGO | S_IRUGO, | ||
| 1113 | at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id); | ||
| 1114 | |||
| 1115 | static struct attribute *at91_sysfs_attrs[] = { | ||
| 1116 | &dev_attr_mb0_id.attr, | ||
| 1117 | NULL, | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | static struct attribute_group at91_sysfs_attr_group = { | ||
| 1121 | .attrs = at91_sysfs_attrs, | ||
| 1122 | }; | ||
| 1123 | |||
| 1050 | static int __devinit at91_can_probe(struct platform_device *pdev) | 1124 | static int __devinit at91_can_probe(struct platform_device *pdev) |
| 1051 | { | 1125 | { |
| 1052 | struct net_device *dev; | 1126 | struct net_device *dev; |
| @@ -1092,6 +1166,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) | |||
| 1092 | dev->netdev_ops = &at91_netdev_ops; | 1166 | dev->netdev_ops = &at91_netdev_ops; |
| 1093 | dev->irq = irq; | 1167 | dev->irq = irq; |
| 1094 | dev->flags |= IFF_ECHO; | 1168 | dev->flags |= IFF_ECHO; |
| 1169 | dev->sysfs_groups[0] = &at91_sysfs_attr_group; | ||
| 1095 | 1170 | ||
| 1096 | priv = netdev_priv(dev); | 1171 | priv = netdev_priv(dev); |
| 1097 | priv->can.clock.freq = clk_get_rate(clk); | 1172 | priv->can.clock.freq = clk_get_rate(clk); |
| @@ -1103,6 +1178,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev) | |||
| 1103 | priv->dev = dev; | 1178 | priv->dev = dev; |
| 1104 | priv->clk = clk; | 1179 | priv->clk = clk; |
| 1105 | priv->pdata = pdev->dev.platform_data; | 1180 | priv->pdata = pdev->dev.platform_data; |
| 1181 | priv->mb0_id = 0x7ff; | ||
| 1106 | 1182 | ||
| 1107 | netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); | 1183 | netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); |
| 1108 | 1184 | ||
