diff options
author | Wolfgang Grandegger <wg@grandegger.com> | 2009-05-30 03:55:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-01 05:53:35 -0400 |
commit | d1a277c584d0862dbf51991baea947ea5f2ce6bf (patch) | |
tree | 368832ff703abde6c813eaaba42a48ae451fc1f1 | |
parent | 255a9154319d3cf475d527458037758935f6445b (diff) |
can: sja1000: generic OF platform bus driver
This patch adds a generic driver for SJA1000 chips on the OpenFirmware
platform bus found on embedded PowerPC systems. You need a SJA1000 node
definition in your flattened device tree source (DTS) file similar to:
can@3,100 {
compatible = "nxp,sja1000";
reg = <3 0x100 0x80>;
interrupts = <2 0>;
interrupt-parent = <&mpic>;
nxp,external-clock-frequency = <16000000>;
};
See also Documentation/powerpc/dts-bindings/can/sja1000.txt.
CC: devicetree-discuss@ozlabs.org
Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/powerpc/dts-bindings/can/sja1000.txt | 53 | ||||
-rw-r--r-- | drivers/net/can/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/can/sja1000/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_of_platform.c | 233 | ||||
-rw-r--r-- | include/linux/can/platform/sja1000.h | 3 |
5 files changed, 299 insertions, 0 deletions
diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt new file mode 100644 index 000000000000..d6d209ded937 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/can/sja1000.txt | |||
@@ -0,0 +1,53 @@ | |||
1 | Memory mapped SJA1000 CAN controller from NXP (formerly Philips) | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible : should be "nxp,sja1000". | ||
6 | |||
7 | - reg : should specify the chip select, address offset and size required | ||
8 | to map the registers of the SJA1000. The size is usually 0x80. | ||
9 | |||
10 | - interrupts: property with a value describing the interrupt source | ||
11 | (number and sensitivity) required for the SJA1000. | ||
12 | |||
13 | Optional properties: | ||
14 | |||
15 | - nxp,external-clock-frequency : Frequency of the external oscillator | ||
16 | clock in Hz. Note that the internal clock frequency used by the | ||
17 | SJA1000 is half of that value. If not specified, a default value | ||
18 | of 16000000 (16 MHz) is used. | ||
19 | |||
20 | - nxp,tx-output-mode : operation mode of the TX output control logic: | ||
21 | <0x0> : bi-phase output mode | ||
22 | <0x1> : normal output mode (default) | ||
23 | <0x2> : test output mode | ||
24 | <0x3> : clock output mode | ||
25 | |||
26 | - nxp,tx-output-config : TX output pin configuration: | ||
27 | <0x01> : TX0 invert | ||
28 | <0x02> : TX0 pull-down (default) | ||
29 | <0x04> : TX0 pull-up | ||
30 | <0x06> : TX0 push-pull | ||
31 | <0x08> : TX1 invert | ||
32 | <0x10> : TX1 pull-down | ||
33 | <0x20> : TX1 pull-up | ||
34 | <0x30> : TX1 push-pull | ||
35 | |||
36 | - nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin. | ||
37 | If not specified or if the specified value is 0, the CLKOUT pin | ||
38 | will be disabled. | ||
39 | |||
40 | - nxp,no-comparator-bypass : Allows to disable the CAN input comperator. | ||
41 | |||
42 | For futher information, please have a look to the SJA1000 data sheet. | ||
43 | |||
44 | Examples: | ||
45 | |||
46 | can@3,100 { | ||
47 | compatible = "nxp,sja1000"; | ||
48 | reg = <3 0x100 0x80>; | ||
49 | interrupts = <2 0>; | ||
50 | interrupt-parent = <&mpic>; | ||
51 | nxp,external-clock-frequency = <16000000>; | ||
52 | }; | ||
53 | |||
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index cfd6c5a285fa..d5e18812bf49 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig | |||
@@ -51,6 +51,15 @@ config CAN_SJA1000_PLATFORM | |||
51 | boards from Phytec (http://www.phytec.de) like the PCM027, | 51 | boards from Phytec (http://www.phytec.de) like the PCM027, |
52 | PCM038. | 52 | PCM038. |
53 | 53 | ||
54 | config CAN_SJA1000_OF_PLATFORM | ||
55 | depends on CAN_SJA1000 && PPC_OF | ||
56 | tristate "Generic OF Platform Bus based SJA1000 driver" | ||
57 | ---help--- | ||
58 | This driver adds support for the SJA1000 chips connected to | ||
59 | the OpenFirmware "platform bus" found on embedded systems with | ||
60 | OpenFirmware bindings, e.g. if you have a PowerPC based system | ||
61 | you may want to enable this option. | ||
62 | |||
54 | config CAN_EMS_PCI | 63 | config CAN_EMS_PCI |
55 | tristate "EMS CPC-PCI and CPC-PCIe Card" | 64 | tristate "EMS CPC-PCI and CPC-PCIe Card" |
56 | depends on PCI && CAN_SJA1000 | 65 | depends on PCI && CAN_SJA1000 |
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index d6c631f9e665..9d0c08da273c 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_CAN_SJA1000) += sja1000.o | 5 | obj-$(CONFIG_CAN_SJA1000) += sja1000.o |
6 | obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o | 6 | obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o |
7 | obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o | ||
7 | obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o | 8 | obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o |
8 | obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o | 9 | obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o |
9 | 10 | ||
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c new file mode 100644 index 000000000000..aa953fb4b8d0 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_of_platform.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the version 2 of the GNU General Public License | ||
8 | * as published by the Free Software Foundation | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software Foundation, | ||
17 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* This is a generic driver for SJA1000 chips on the OpenFirmware platform | ||
21 | * bus found on embedded PowerPC systems. You need a SJA1000 CAN node | ||
22 | * definition in your flattened device tree source (DTS) file similar to: | ||
23 | * | ||
24 | * can@3,100 { | ||
25 | * compatible = "nxp,sja1000"; | ||
26 | * reg = <3 0x100 0x80>; | ||
27 | * interrupts = <2 0>; | ||
28 | * interrupt-parent = <&mpic>; | ||
29 | * nxp,external-clock-frequency = <16000000>; | ||
30 | * }; | ||
31 | * | ||
32 | * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further | ||
33 | * information. | ||
34 | */ | ||
35 | |||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/interrupt.h> | ||
39 | #include <linux/netdevice.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/can.h> | ||
42 | #include <linux/can/dev.h> | ||
43 | |||
44 | #include <linux/of_platform.h> | ||
45 | #include <asm/prom.h> | ||
46 | |||
47 | #include "sja1000.h" | ||
48 | |||
49 | #define DRV_NAME "sja1000_of_platform" | ||
50 | |||
51 | MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); | ||
52 | MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); | ||
53 | MODULE_LICENSE("GPL v2"); | ||
54 | |||
55 | #define SJA1000_OFP_CAN_CLOCK (16000000 / 2) | ||
56 | |||
57 | #define SJA1000_OFP_OCR OCR_TX0_PULLDOWN | ||
58 | #define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) | ||
59 | |||
60 | static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) | ||
61 | { | ||
62 | return in_8(priv->reg_base + reg); | ||
63 | } | ||
64 | |||
65 | static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, | ||
66 | int reg, u8 val) | ||
67 | { | ||
68 | out_8(priv->reg_base + reg, val); | ||
69 | } | ||
70 | |||
71 | static int __devexit sja1000_ofp_remove(struct of_device *ofdev) | ||
72 | { | ||
73 | struct net_device *dev = dev_get_drvdata(&ofdev->dev); | ||
74 | struct sja1000_priv *priv = netdev_priv(dev); | ||
75 | struct device_node *np = ofdev->node; | ||
76 | struct resource res; | ||
77 | |||
78 | dev_set_drvdata(&ofdev->dev, NULL); | ||
79 | |||
80 | unregister_sja1000dev(dev); | ||
81 | free_sja1000dev(dev); | ||
82 | iounmap(priv->reg_base); | ||
83 | irq_dispose_mapping(dev->irq); | ||
84 | |||
85 | of_address_to_resource(np, 0, &res); | ||
86 | release_mem_region(res.start, resource_size(&res)); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int __devinit sja1000_ofp_probe(struct of_device *ofdev, | ||
92 | const struct of_device_id *id) | ||
93 | { | ||
94 | struct device_node *np = ofdev->node; | ||
95 | struct net_device *dev; | ||
96 | struct sja1000_priv *priv; | ||
97 | struct resource res; | ||
98 | const u32 *prop; | ||
99 | int err, irq, res_size, prop_size; | ||
100 | void __iomem *base; | ||
101 | |||
102 | err = of_address_to_resource(np, 0, &res); | ||
103 | if (err) { | ||
104 | dev_err(&ofdev->dev, "invalid address\n"); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | res_size = resource_size(&res); | ||
109 | |||
110 | if (!request_mem_region(res.start, res_size, DRV_NAME)) { | ||
111 | dev_err(&ofdev->dev, "couldn't request %#x..%#x\n", | ||
112 | res.start, res.end); | ||
113 | return -EBUSY; | ||
114 | } | ||
115 | |||
116 | base = ioremap_nocache(res.start, res_size); | ||
117 | if (!base) { | ||
118 | dev_err(&ofdev->dev, "couldn't ioremap %#x..%#x\n", | ||
119 | res.start, res.end); | ||
120 | err = -ENOMEM; | ||
121 | goto exit_release_mem; | ||
122 | } | ||
123 | |||
124 | irq = irq_of_parse_and_map(np, 0); | ||
125 | if (irq == NO_IRQ) { | ||
126 | dev_err(&ofdev->dev, "no irq found\n"); | ||
127 | err = -ENODEV; | ||
128 | goto exit_unmap_mem; | ||
129 | } | ||
130 | |||
131 | dev = alloc_sja1000dev(0); | ||
132 | if (!dev) { | ||
133 | err = -ENOMEM; | ||
134 | goto exit_dispose_irq; | ||
135 | } | ||
136 | |||
137 | priv = netdev_priv(dev); | ||
138 | |||
139 | priv->read_reg = sja1000_ofp_read_reg; | ||
140 | priv->write_reg = sja1000_ofp_write_reg; | ||
141 | |||
142 | prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); | ||
143 | if (prop && (prop_size == sizeof(u32))) | ||
144 | priv->can.clock.freq = *prop / 2; | ||
145 | else | ||
146 | priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ | ||
147 | |||
148 | prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); | ||
149 | if (prop && (prop_size == sizeof(u32))) | ||
150 | priv->ocr |= *prop & OCR_MODE_MASK; | ||
151 | else | ||
152 | priv->ocr |= OCR_MODE_NORMAL; /* default */ | ||
153 | |||
154 | prop = of_get_property(np, "nxp,tx-output-config", &prop_size); | ||
155 | if (prop && (prop_size == sizeof(u32))) | ||
156 | priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; | ||
157 | else | ||
158 | priv->ocr |= OCR_TX0_PULLDOWN; /* default */ | ||
159 | |||
160 | prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); | ||
161 | if (prop && (prop_size == sizeof(u32)) && *prop) { | ||
162 | u32 divider = priv->can.clock.freq * 2 / *prop; | ||
163 | |||
164 | if (divider > 1) | ||
165 | priv->cdr |= divider / 2 - 1; | ||
166 | else | ||
167 | priv->cdr |= CDR_CLKOUT_MASK; | ||
168 | } else { | ||
169 | priv->cdr |= CDR_CLK_OFF; /* default */ | ||
170 | } | ||
171 | |||
172 | prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); | ||
173 | if (!prop) | ||
174 | priv->cdr |= CDR_CBP; /* default */ | ||
175 | |||
176 | priv->irq_flags = IRQF_SHARED; | ||
177 | priv->reg_base = base; | ||
178 | |||
179 | dev->irq = irq; | ||
180 | |||
181 | dev_info(&ofdev->dev, | ||
182 | "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", | ||
183 | priv->reg_base, dev->irq, priv->can.clock.freq, | ||
184 | priv->ocr, priv->cdr); | ||
185 | |||
186 | dev_set_drvdata(&ofdev->dev, dev); | ||
187 | SET_NETDEV_DEV(dev, &ofdev->dev); | ||
188 | |||
189 | err = register_sja1000dev(dev); | ||
190 | if (err) { | ||
191 | dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", | ||
192 | DRV_NAME, err); | ||
193 | goto exit_free_sja1000; | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | |||
198 | exit_free_sja1000: | ||
199 | free_sja1000dev(dev); | ||
200 | exit_dispose_irq: | ||
201 | irq_dispose_mapping(irq); | ||
202 | exit_unmap_mem: | ||
203 | iounmap(base); | ||
204 | exit_release_mem: | ||
205 | release_mem_region(res.start, res_size); | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | static struct of_device_id __devinitdata sja1000_ofp_table[] = { | ||
211 | {.compatible = "nxp,sja1000"}, | ||
212 | {}, | ||
213 | }; | ||
214 | |||
215 | static struct of_platform_driver sja1000_ofp_driver = { | ||
216 | .owner = THIS_MODULE, | ||
217 | .name = DRV_NAME, | ||
218 | .probe = sja1000_ofp_probe, | ||
219 | .remove = __devexit_p(sja1000_ofp_remove), | ||
220 | .match_table = sja1000_ofp_table, | ||
221 | }; | ||
222 | |||
223 | static int __init sja1000_ofp_init(void) | ||
224 | { | ||
225 | return of_register_platform_driver(&sja1000_ofp_driver); | ||
226 | } | ||
227 | module_init(sja1000_ofp_init); | ||
228 | |||
229 | static void __exit sja1000_ofp_exit(void) | ||
230 | { | ||
231 | return of_unregister_platform_driver(&sja1000_ofp_driver); | ||
232 | }; | ||
233 | module_exit(sja1000_ofp_exit); | ||
diff --git a/include/linux/can/platform/sja1000.h b/include/linux/can/platform/sja1000.h index 37966e630ff5..01ee2aeb048d 100644 --- a/include/linux/can/platform/sja1000.h +++ b/include/linux/can/platform/sja1000.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define OCR_MODE_TEST 0x01 | 13 | #define OCR_MODE_TEST 0x01 |
14 | #define OCR_MODE_NORMAL 0x02 | 14 | #define OCR_MODE_NORMAL 0x02 |
15 | #define OCR_MODE_CLOCK 0x03 | 15 | #define OCR_MODE_CLOCK 0x03 |
16 | #define OCR_MODE_MASK 0x07 | ||
16 | #define OCR_TX0_INVERT 0x04 | 17 | #define OCR_TX0_INVERT 0x04 |
17 | #define OCR_TX0_PULLDOWN 0x08 | 18 | #define OCR_TX0_PULLDOWN 0x08 |
18 | #define OCR_TX0_PULLUP 0x10 | 19 | #define OCR_TX0_PULLUP 0x10 |
@@ -21,6 +22,8 @@ | |||
21 | #define OCR_TX1_PULLDOWN 0x40 | 22 | #define OCR_TX1_PULLDOWN 0x40 |
22 | #define OCR_TX1_PULLUP 0x80 | 23 | #define OCR_TX1_PULLUP 0x80 |
23 | #define OCR_TX1_PUSHPULL 0xc0 | 24 | #define OCR_TX1_PUSHPULL 0xc0 |
25 | #define OCR_TX_MASK 0xfc | ||
26 | #define OCR_TX_SHIFT 2 | ||
24 | 27 | ||
25 | struct sja1000_platform_data { | 28 | struct sja1000_platform_data { |
26 | u32 clock; /* CAN bus oscillator frequency in Hz */ | 29 | u32 clock; /* CAN bus oscillator frequency in Hz */ |