diff options
-rw-r--r-- | drivers/net/can/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/can/sja1000/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_platform.c | 164 | ||||
-rw-r--r-- | include/linux/can/platform/sja1000.h | 32 |
4 files changed, 207 insertions, 0 deletions
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index c7e5ce339ead..8fe79741d3ca 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig | |||
@@ -41,6 +41,16 @@ config CAN_SJA1000 | |||
41 | ---help--- | 41 | ---help--- |
42 | Driver for the SJA1000 CAN controllers from Philips or NXP | 42 | Driver for the SJA1000 CAN controllers from Philips or NXP |
43 | 43 | ||
44 | config CAN_SJA1000_PLATFORM | ||
45 | depends on CAN_SJA1000 | ||
46 | tristate "Generic Platform Bus based SJA1000 driver" | ||
47 | ---help--- | ||
48 | This driver adds support for the SJA1000 chips connected to | ||
49 | the "platform bus" (Linux abstraction for directly to the | ||
50 | processor attached devices). Which can be found on various | ||
51 | boards from Phytec (http://www.phytec.de) like the PCM027, | ||
52 | PCM038. | ||
53 | |||
44 | config CAN_DEBUG_DEVICES | 54 | config CAN_DEBUG_DEVICES |
45 | bool "CAN devices debugging messages" | 55 | bool "CAN devices debugging messages" |
46 | depends on CAN | 56 | depends on CAN |
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index 893ab2cfe244..5115cc90ab51 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile | |||
@@ -3,5 +3,6 @@ | |||
3 | # | 3 | # |
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 | 7 | ||
7 | ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG | 8 | ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG |
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c new file mode 100644 index 000000000000..8017229d6fd6 --- /dev/null +++ b/drivers/net/can/sja1000/sja1000_platform.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 Sascha Hauer, Pengutronix | ||
3 | * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the version 2 of the GNU General Public License | ||
7 | * as published by the Free Software Foundation | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/can.h> | ||
28 | #include <linux/can/dev.h> | ||
29 | #include <linux/can/platform/sja1000.h> | ||
30 | #include <linux/io.h> | ||
31 | |||
32 | #include "sja1000.h" | ||
33 | |||
34 | #define DRV_NAME "sja1000_platform" | ||
35 | |||
36 | MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); | ||
37 | MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); | ||
38 | MODULE_LICENSE("GPL v2"); | ||
39 | |||
40 | static u8 sp_read_reg(const struct net_device *dev, int reg) | ||
41 | { | ||
42 | return ioread8((void __iomem *)(dev->base_addr + reg)); | ||
43 | } | ||
44 | |||
45 | static void sp_write_reg(const struct net_device *dev, int reg, u8 val) | ||
46 | { | ||
47 | iowrite8(val, (void __iomem *)(dev->base_addr + reg)); | ||
48 | } | ||
49 | |||
50 | static int sp_probe(struct platform_device *pdev) | ||
51 | { | ||
52 | int err; | ||
53 | void __iomem *addr; | ||
54 | struct net_device *dev; | ||
55 | struct sja1000_priv *priv; | ||
56 | struct resource *res_mem, *res_irq; | ||
57 | struct sja1000_platform_data *pdata; | ||
58 | |||
59 | pdata = pdev->dev.platform_data; | ||
60 | if (!pdata) { | ||
61 | dev_err(&pdev->dev, "No platform data provided!\n"); | ||
62 | err = -ENODEV; | ||
63 | goto exit; | ||
64 | } | ||
65 | |||
66 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
67 | res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
68 | if (!res_mem || !res_irq) { | ||
69 | err = -ENODEV; | ||
70 | goto exit; | ||
71 | } | ||
72 | |||
73 | if (!request_mem_region(res_mem->start, resource_size(res_mem), | ||
74 | DRV_NAME)) { | ||
75 | err = -EBUSY; | ||
76 | goto exit; | ||
77 | } | ||
78 | |||
79 | addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); | ||
80 | if (!addr) { | ||
81 | err = -ENOMEM; | ||
82 | goto exit_release; | ||
83 | } | ||
84 | |||
85 | dev = alloc_sja1000dev(0); | ||
86 | if (!dev) { | ||
87 | err = -ENOMEM; | ||
88 | goto exit_iounmap; | ||
89 | } | ||
90 | priv = netdev_priv(dev); | ||
91 | |||
92 | dev->base_addr = (unsigned long)addr; | ||
93 | dev->irq = res_irq->start; | ||
94 | priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; | ||
95 | priv->read_reg = sp_read_reg; | ||
96 | priv->write_reg = sp_write_reg; | ||
97 | priv->can.clock.freq = pdata->clock; | ||
98 | priv->ocr = pdata->ocr; | ||
99 | priv->cdr = pdata->cdr; | ||
100 | |||
101 | dev_set_drvdata(&pdev->dev, dev); | ||
102 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
103 | |||
104 | err = register_sja1000dev(dev); | ||
105 | if (err) { | ||
106 | dev_err(&pdev->dev, "registering %s failed (err=%d)\n", | ||
107 | DRV_NAME, err); | ||
108 | goto exit_free; | ||
109 | } | ||
110 | |||
111 | dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n", | ||
112 | DRV_NAME, dev->base_addr, dev->irq); | ||
113 | return 0; | ||
114 | |||
115 | exit_free: | ||
116 | free_sja1000dev(dev); | ||
117 | exit_iounmap: | ||
118 | iounmap(addr); | ||
119 | exit_release: | ||
120 | release_mem_region(res_mem->start, resource_size(res_mem)); | ||
121 | exit: | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | static int sp_remove(struct platform_device *pdev) | ||
126 | { | ||
127 | struct net_device *dev = dev_get_drvdata(&pdev->dev); | ||
128 | struct resource *res; | ||
129 | |||
130 | unregister_sja1000dev(dev); | ||
131 | dev_set_drvdata(&pdev->dev, NULL); | ||
132 | |||
133 | if (dev->base_addr) | ||
134 | iounmap((void __iomem *)dev->base_addr); | ||
135 | |||
136 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
137 | release_mem_region(res->start, resource_size(res)); | ||
138 | |||
139 | free_sja1000dev(dev); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static struct platform_driver sp_driver = { | ||
145 | .probe = sp_probe, | ||
146 | .remove = sp_remove, | ||
147 | .driver = { | ||
148 | .name = DRV_NAME, | ||
149 | .owner = THIS_MODULE, | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static int __init sp_init(void) | ||
154 | { | ||
155 | return platform_driver_register(&sp_driver); | ||
156 | } | ||
157 | |||
158 | static void __exit sp_exit(void) | ||
159 | { | ||
160 | platform_driver_unregister(&sp_driver); | ||
161 | } | ||
162 | |||
163 | module_init(sp_init); | ||
164 | module_exit(sp_exit); | ||
diff --git a/include/linux/can/platform/sja1000.h b/include/linux/can/platform/sja1000.h new file mode 100644 index 000000000000..37966e630ff5 --- /dev/null +++ b/include/linux/can/platform/sja1000.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef _CAN_PLATFORM_SJA1000_H_ | ||
2 | #define _CAN_PLATFORM_SJA1000_H_ | ||
3 | |||
4 | /* clock divider register */ | ||
5 | #define CDR_CLKOUT_MASK 0x07 | ||
6 | #define CDR_CLK_OFF 0x08 /* Clock off (CLKOUT pin) */ | ||
7 | #define CDR_RXINPEN 0x20 /* TX1 output is RX irq output */ | ||
8 | #define CDR_CBP 0x40 /* CAN input comparator bypass */ | ||
9 | #define CDR_PELICAN 0x80 /* PeliCAN mode */ | ||
10 | |||
11 | /* output control register */ | ||
12 | #define OCR_MODE_BIPHASE 0x00 | ||
13 | #define OCR_MODE_TEST 0x01 | ||
14 | #define OCR_MODE_NORMAL 0x02 | ||
15 | #define OCR_MODE_CLOCK 0x03 | ||
16 | #define OCR_TX0_INVERT 0x04 | ||
17 | #define OCR_TX0_PULLDOWN 0x08 | ||
18 | #define OCR_TX0_PULLUP 0x10 | ||
19 | #define OCR_TX0_PUSHPULL 0x18 | ||
20 | #define OCR_TX1_INVERT 0x20 | ||
21 | #define OCR_TX1_PULLDOWN 0x40 | ||
22 | #define OCR_TX1_PULLUP 0x80 | ||
23 | #define OCR_TX1_PUSHPULL 0xc0 | ||
24 | |||
25 | struct sja1000_platform_data { | ||
26 | u32 clock; /* CAN bus oscillator frequency in Hz */ | ||
27 | |||
28 | u8 ocr; /* output control register */ | ||
29 | u8 cdr; /* clock divider register */ | ||
30 | }; | ||
31 | |||
32 | #endif /* !_CAN_PLATFORM_SJA1000_H_ */ | ||