diff options
author | AnilKumar Ch <anilkumar@ti.com> | 2012-05-29 01:43:16 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2012-06-07 04:02:27 -0400 |
commit | 69927fccd96b15bd228bb82d356a7a2a0cfaeefb (patch) | |
tree | ef9487a9cab32ed0baa50749b4dbbe2232e0af99 /drivers/net/can | |
parent | 33f8100977693fa09c2a32b1ca6dbf4d6eabdd0c (diff) |
can: c_can: Add support for Bosch D_CAN controller
This patch adds the support for D_CAN controller driver to the existing
C_CAN driver.
Bosch D_CAN controller is a full-CAN implementation which is compliant
to CAN protocol version 2.0 part A and B. Bosch D_CAN user manual can be
obtained from: http://www.semiconductors.bosch.de/media/en/pdf/
ipmodules_1/can/d_can_users_manual_111.pdf
A new array is added for accessing the d_can registers, according to d_can
controller register space.
Current D_CAN implementation has following limitations, this is done
to avoid large changes to the C_CAN driver.
1. Message objects are limited to 32, 16 for RX and 16 for TX. C_CAN IP
supports upto 32 message objects but in case of D_CAN we can configure
upto 128 message objects.
2. Using two 16bit reads/writes for accessing the 32bit D_CAN registers.
3. These patches have been tested on little endian machine, there might
be some hidden endian-related issues due to the nature of the accesses
(32-bit registers accessed as 2 16-bit registers). However, I do not
have a big-endian D_CAN implementation to confirm.
Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r-- | drivers/net/can/c_can/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/can/c_can/c_can.h | 45 | ||||
-rw-r--r-- | drivers/net/can/c_can/c_can_platform.c | 55 |
3 files changed, 94 insertions, 19 deletions
diff --git a/drivers/net/can/c_can/Kconfig b/drivers/net/can/c_can/Kconfig index ffb9773d102d..25d371cf98dd 100644 --- a/drivers/net/can/c_can/Kconfig +++ b/drivers/net/can/c_can/Kconfig | |||
@@ -1,15 +1,16 @@ | |||
1 | menuconfig CAN_C_CAN | 1 | menuconfig CAN_C_CAN |
2 | tristate "Bosch C_CAN devices" | 2 | tristate "Bosch C_CAN/D_CAN devices" |
3 | depends on CAN_DEV && HAS_IOMEM | 3 | depends on CAN_DEV && HAS_IOMEM |
4 | 4 | ||
5 | if CAN_C_CAN | 5 | if CAN_C_CAN |
6 | 6 | ||
7 | config CAN_C_CAN_PLATFORM | 7 | config CAN_C_CAN_PLATFORM |
8 | tristate "Generic Platform Bus based C_CAN driver" | 8 | tristate "Generic Platform Bus based C_CAN/D_CAN driver" |
9 | ---help--- | 9 | ---help--- |
10 | This driver adds support for the C_CAN chips connected to | 10 | This driver adds support for the C_CAN/D_CAN chips connected |
11 | the "platform bus" (Linux abstraction for directly to the | 11 | to the "platform bus" (Linux abstraction for directly to the |
12 | processor attached devices) which can be found on various | 12 | processor attached devices) which can be found on various |
13 | boards from ST Microelectronics (http://www.st.com) | 13 | boards from ST Microelectronics (http://www.st.com) like the |
14 | like the SPEAr1310 and SPEAr320 evaluation boards. | 14 | SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com) |
15 | boards like am335x, dm814x, dm813x and dm811x. | ||
15 | endif | 16 | endif |
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index d1e141e3b99c..01a7049ab990 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h | |||
@@ -102,6 +102,51 @@ static const u16 reg_map_c_can[] = { | |||
102 | [C_CAN_MSGVAL2_REG] = 0xB2, | 102 | [C_CAN_MSGVAL2_REG] = 0xB2, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static const u16 reg_map_d_can[] = { | ||
106 | [C_CAN_CTRL_REG] = 0x00, | ||
107 | [C_CAN_STS_REG] = 0x04, | ||
108 | [C_CAN_ERR_CNT_REG] = 0x08, | ||
109 | [C_CAN_BTR_REG] = 0x0C, | ||
110 | [C_CAN_BRPEXT_REG] = 0x0E, | ||
111 | [C_CAN_INT_REG] = 0x10, | ||
112 | [C_CAN_TEST_REG] = 0x14, | ||
113 | [C_CAN_TXRQST1_REG] = 0x88, | ||
114 | [C_CAN_TXRQST2_REG] = 0x8A, | ||
115 | [C_CAN_NEWDAT1_REG] = 0x9C, | ||
116 | [C_CAN_NEWDAT2_REG] = 0x9E, | ||
117 | [C_CAN_INTPND1_REG] = 0xB0, | ||
118 | [C_CAN_INTPND2_REG] = 0xB2, | ||
119 | [C_CAN_MSGVAL1_REG] = 0xC4, | ||
120 | [C_CAN_MSGVAL2_REG] = 0xC6, | ||
121 | [C_CAN_IF1_COMREQ_REG] = 0x100, | ||
122 | [C_CAN_IF1_COMMSK_REG] = 0x102, | ||
123 | [C_CAN_IF1_MASK1_REG] = 0x104, | ||
124 | [C_CAN_IF1_MASK2_REG] = 0x106, | ||
125 | [C_CAN_IF1_ARB1_REG] = 0x108, | ||
126 | [C_CAN_IF1_ARB2_REG] = 0x10A, | ||
127 | [C_CAN_IF1_MSGCTRL_REG] = 0x10C, | ||
128 | [C_CAN_IF1_DATA1_REG] = 0x110, | ||
129 | [C_CAN_IF1_DATA2_REG] = 0x112, | ||
130 | [C_CAN_IF1_DATA3_REG] = 0x114, | ||
131 | [C_CAN_IF1_DATA4_REG] = 0x116, | ||
132 | [C_CAN_IF2_COMREQ_REG] = 0x120, | ||
133 | [C_CAN_IF2_COMMSK_REG] = 0x122, | ||
134 | [C_CAN_IF2_MASK1_REG] = 0x124, | ||
135 | [C_CAN_IF2_MASK2_REG] = 0x126, | ||
136 | [C_CAN_IF2_ARB1_REG] = 0x128, | ||
137 | [C_CAN_IF2_ARB2_REG] = 0x12A, | ||
138 | [C_CAN_IF2_MSGCTRL_REG] = 0x12C, | ||
139 | [C_CAN_IF2_DATA1_REG] = 0x130, | ||
140 | [C_CAN_IF2_DATA2_REG] = 0x132, | ||
141 | [C_CAN_IF2_DATA3_REG] = 0x134, | ||
142 | [C_CAN_IF2_DATA4_REG] = 0x136, | ||
143 | }; | ||
144 | |||
145 | enum c_can_dev_id { | ||
146 | C_CAN_DEVTYPE, | ||
147 | D_CAN_DEVTYPE, | ||
148 | }; | ||
149 | |||
105 | /* c_can private data structure */ | 150 | /* c_can private data structure */ |
106 | struct c_can_priv { | 151 | struct c_can_priv { |
107 | struct can_priv can; /* must be the first member */ | 152 | struct can_priv can; /* must be the first member */ |
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index a6e9b937683a..f0921d16f0a9 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c | |||
@@ -71,6 +71,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
71 | void __iomem *addr; | 71 | void __iomem *addr; |
72 | struct net_device *dev; | 72 | struct net_device *dev; |
73 | struct c_can_priv *priv; | 73 | struct c_can_priv *priv; |
74 | const struct platform_device_id *id; | ||
74 | struct resource *mem; | 75 | struct resource *mem; |
75 | int irq; | 76 | int irq; |
76 | #ifdef CONFIG_HAVE_CLK | 77 | #ifdef CONFIG_HAVE_CLK |
@@ -115,7 +116,32 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
115 | } | 116 | } |
116 | 117 | ||
117 | priv = netdev_priv(dev); | 118 | priv = netdev_priv(dev); |
118 | priv->regs = reg_map_c_can; | 119 | id = platform_get_device_id(pdev); |
120 | switch (id->driver_data) { | ||
121 | case C_CAN_DEVTYPE: | ||
122 | priv->regs = reg_map_c_can; | ||
123 | switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) { | ||
124 | case IORESOURCE_MEM_32BIT: | ||
125 | priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; | ||
126 | priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; | ||
127 | break; | ||
128 | case IORESOURCE_MEM_16BIT: | ||
129 | default: | ||
130 | priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; | ||
131 | priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; | ||
132 | break; | ||
133 | } | ||
134 | break; | ||
135 | case D_CAN_DEVTYPE: | ||
136 | priv->regs = reg_map_d_can; | ||
137 | priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; | ||
138 | priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; | ||
139 | priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; | ||
140 | break; | ||
141 | default: | ||
142 | ret = -EINVAL; | ||
143 | goto exit_free_device; | ||
144 | } | ||
119 | 145 | ||
120 | dev->irq = irq; | 146 | dev->irq = irq; |
121 | priv->base = addr; | 147 | priv->base = addr; |
@@ -124,18 +150,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) | |||
124 | priv->priv = clk; | 150 | priv->priv = clk; |
125 | #endif | 151 | #endif |
126 | 152 | ||
127 | switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) { | ||
128 | case IORESOURCE_MEM_32BIT: | ||
129 | priv->read_reg = c_can_plat_read_reg_aligned_to_32bit; | ||
130 | priv->write_reg = c_can_plat_write_reg_aligned_to_32bit; | ||
131 | break; | ||
132 | case IORESOURCE_MEM_16BIT: | ||
133 | default: | ||
134 | priv->read_reg = c_can_plat_read_reg_aligned_to_16bit; | ||
135 | priv->write_reg = c_can_plat_write_reg_aligned_to_16bit; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | platform_set_drvdata(pdev, dev); | 153 | platform_set_drvdata(pdev, dev); |
140 | SET_NETDEV_DEV(dev, &pdev->dev); | 154 | SET_NETDEV_DEV(dev, &pdev->dev); |
141 | 155 | ||
@@ -189,6 +203,20 @@ static int __devexit c_can_plat_remove(struct platform_device *pdev) | |||
189 | return 0; | 203 | return 0; |
190 | } | 204 | } |
191 | 205 | ||
206 | static const struct platform_device_id c_can_id_table[] = { | ||
207 | { | ||
208 | .name = KBUILD_MODNAME, | ||
209 | .driver_data = C_CAN_DEVTYPE, | ||
210 | }, { | ||
211 | .name = "c_can", | ||
212 | .driver_data = C_CAN_DEVTYPE, | ||
213 | }, { | ||
214 | .name = "d_can", | ||
215 | .driver_data = D_CAN_DEVTYPE, | ||
216 | }, { | ||
217 | } | ||
218 | }; | ||
219 | |||
192 | static struct platform_driver c_can_plat_driver = { | 220 | static struct platform_driver c_can_plat_driver = { |
193 | .driver = { | 221 | .driver = { |
194 | .name = KBUILD_MODNAME, | 222 | .name = KBUILD_MODNAME, |
@@ -196,6 +224,7 @@ static struct platform_driver c_can_plat_driver = { | |||
196 | }, | 224 | }, |
197 | .probe = c_can_plat_probe, | 225 | .probe = c_can_plat_probe, |
198 | .remove = __devexit_p(c_can_plat_remove), | 226 | .remove = __devexit_p(c_can_plat_remove), |
227 | .id_table = c_can_id_table, | ||
199 | }; | 228 | }; |
200 | 229 | ||
201 | module_platform_driver(c_can_plat_driver); | 230 | module_platform_driver(c_can_plat_driver); |