aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/can
diff options
context:
space:
mode:
authorFlorian Vaussard <florian.vaussard@epfl.ch>2014-01-31 08:34:35 -0500
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-02-04 04:10:51 -0500
commit02729c3d08c9334d03d61d365ff2408514a46c81 (patch)
treeed4ae93aff4bac0aa27c61eabb177f8dbe0f7da3 /drivers/net/can
parent342180f7dcfb00e4019a0cd0f0e9bfd0c186c710 (diff)
can: sja1000: fuse of_platform into platform
The OpenFirmware probe can be merged into the standard platform probe to leverage common code. Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch> Tested-by: Andreas Larsson <andreas@gaisler.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r--drivers/net/can/sja1000/Kconfig13
-rw-r--r--drivers/net/can/sja1000/Makefile1
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c220
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c134
4 files changed, 109 insertions, 259 deletions
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index ff2ba86cd4a4..4b18b8765523 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM
17 the "platform bus" (Linux abstraction for directly to the 17 the "platform bus" (Linux abstraction for directly to the
18 processor attached devices). Which can be found on various 18 processor attached devices). Which can be found on various
19 boards from Phytec (http://www.phytec.de) like the PCM027, 19 boards from Phytec (http://www.phytec.de) like the PCM027,
20 PCM038. 20 PCM038. It also provides the OpenFirmware "platform bus" found
21 21 on embedded systems with OpenFirmware bindings, e.g. if you
22config CAN_SJA1000_OF_PLATFORM 22 have a PowerPC based system you may want to enable this option.
23 tristate "Generic OF Platform Bus based SJA1000 driver"
24 depends on OF
25 ---help---
26 This driver adds support for the SJA1000 chips connected to
27 the OpenFirmware "platform bus" found on embedded systems with
28 OpenFirmware bindings, e.g. if you have a PowerPC based system
29 you may want to enable this option.
30 23
31config CAN_EMS_PCMCIA 24config CAN_EMS_PCMCIA
32 tristate "EMS CPC-CARD Card" 25 tristate "EMS CPC-CARD Card"
diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile
index b3d05cbfec36..531d5fcc97e5 100644
--- a/drivers/net/can/sja1000/Makefile
+++ b/drivers/net/can/sja1000/Makefile
@@ -5,7 +5,6 @@
5obj-$(CONFIG_CAN_SJA1000) += sja1000.o 5obj-$(CONFIG_CAN_SJA1000) += sja1000.o
6obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o 6obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
7obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o 7obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
8obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
9obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o 8obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
10obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o 9obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
11obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o 10obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
deleted file mode 100644
index 2f6e24534231..000000000000
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ /dev/null
@@ -1,220 +0,0 @@
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, see <http://www.gnu.org/licenses/>.
17 */
18
19/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
20 * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
21 * definition in your flattened device tree source (DTS) file similar to:
22 *
23 * can@3,100 {
24 * compatible = "nxp,sja1000";
25 * reg = <3 0x100 0x80>;
26 * interrupts = <2 0>;
27 * interrupt-parent = <&mpic>;
28 * nxp,external-clock-frequency = <16000000>;
29 * };
30 *
31 * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
32 * information.
33 */
34
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/interrupt.h>
38#include <linux/netdevice.h>
39#include <linux/delay.h>
40#include <linux/io.h>
41#include <linux/can/dev.h>
42
43#include <linux/of_platform.h>
44#include <linux/of_address.h>
45#include <linux/of_irq.h>
46
47#include "sja1000.h"
48
49#define DRV_NAME "sja1000_of_platform"
50
51MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
52MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
53MODULE_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
60static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
61{
62 return ioread8(priv->reg_base + reg);
63}
64
65static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
66 int reg, u8 val)
67{
68 iowrite8(val, priv->reg_base + reg);
69}
70
71static int sja1000_ofp_remove(struct platform_device *ofdev)
72{
73 struct net_device *dev = platform_get_drvdata(ofdev);
74 struct sja1000_priv *priv = netdev_priv(dev);
75 struct device_node *np = ofdev->dev.of_node;
76 struct resource res;
77
78 unregister_sja1000dev(dev);
79 free_sja1000dev(dev);
80 iounmap(priv->reg_base);
81 irq_dispose_mapping(dev->irq);
82
83 of_address_to_resource(np, 0, &res);
84 release_mem_region(res.start, resource_size(&res));
85
86 return 0;
87}
88
89static int sja1000_ofp_probe(struct platform_device *ofdev)
90{
91 struct device_node *np = ofdev->dev.of_node;
92 struct net_device *dev;
93 struct sja1000_priv *priv;
94 struct resource res;
95 u32 prop;
96 int err, irq, res_size;
97 void __iomem *base;
98
99 err = of_address_to_resource(np, 0, &res);
100 if (err) {
101 dev_err(&ofdev->dev, "invalid address\n");
102 return err;
103 }
104
105 res_size = resource_size(&res);
106
107 if (!request_mem_region(res.start, res_size, DRV_NAME)) {
108 dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
109 return -EBUSY;
110 }
111
112 base = ioremap_nocache(res.start, res_size);
113 if (!base) {
114 dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
115 err = -ENOMEM;
116 goto exit_release_mem;
117 }
118
119 irq = irq_of_parse_and_map(np, 0);
120 if (irq == 0) {
121 dev_err(&ofdev->dev, "no irq found\n");
122 err = -ENODEV;
123 goto exit_unmap_mem;
124 }
125
126 dev = alloc_sja1000dev(0);
127 if (!dev) {
128 err = -ENOMEM;
129 goto exit_dispose_irq;
130 }
131
132 priv = netdev_priv(dev);
133
134 priv->read_reg = sja1000_ofp_read_reg;
135 priv->write_reg = sja1000_ofp_write_reg;
136
137 err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
138 if (!err)
139 priv->can.clock.freq = prop / 2;
140 else
141 priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
142
143 err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
144 if (!err)
145 priv->ocr |= prop & OCR_MODE_MASK;
146 else
147 priv->ocr |= OCR_MODE_NORMAL; /* default */
148
149 err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
150 if (!err)
151 priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
152 else
153 priv->ocr |= OCR_TX0_PULLDOWN; /* default */
154
155 err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
156 if (!err && prop) {
157 u32 divider = priv->can.clock.freq * 2 / prop;
158
159 if (divider > 1)
160 priv->cdr |= divider / 2 - 1;
161 else
162 priv->cdr |= CDR_CLKOUT_MASK;
163 } else {
164 priv->cdr |= CDR_CLK_OFF; /* default */
165 }
166
167 if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
168 priv->cdr |= CDR_CBP; /* default */
169
170 priv->irq_flags = IRQF_SHARED;
171 priv->reg_base = base;
172
173 dev->irq = irq;
174
175 dev_info(&ofdev->dev,
176 "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
177 priv->reg_base, dev->irq, priv->can.clock.freq,
178 priv->ocr, priv->cdr);
179
180 platform_set_drvdata(ofdev, dev);
181 SET_NETDEV_DEV(dev, &ofdev->dev);
182
183 err = register_sja1000dev(dev);
184 if (err) {
185 dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
186 DRV_NAME, err);
187 goto exit_free_sja1000;
188 }
189
190 return 0;
191
192exit_free_sja1000:
193 free_sja1000dev(dev);
194exit_dispose_irq:
195 irq_dispose_mapping(irq);
196exit_unmap_mem:
197 iounmap(base);
198exit_release_mem:
199 release_mem_region(res.start, res_size);
200
201 return err;
202}
203
204static struct of_device_id sja1000_ofp_table[] = {
205 {.compatible = "nxp,sja1000"},
206 {},
207};
208MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
209
210static struct platform_driver sja1000_ofp_driver = {
211 .driver = {
212 .owner = THIS_MODULE,
213 .name = DRV_NAME,
214 .of_match_table = sja1000_ofp_table,
215 },
216 .probe = sja1000_ofp_probe,
217 .remove = sja1000_ofp_remove,
218};
219
220module_platform_driver(sja1000_ofp_driver);
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 50ca27387c4c..b7fbe4f57720 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -26,12 +26,16 @@
26#include <linux/can/dev.h> 26#include <linux/can/dev.h>
27#include <linux/can/platform/sja1000.h> 27#include <linux/can/platform/sja1000.h>
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/of.h>
30#include <linux/of_irq.h>
29 31
30#include "sja1000.h" 32#include "sja1000.h"
31 33
32#define DRV_NAME "sja1000_platform" 34#define DRV_NAME "sja1000_platform"
35#define SP_CAN_CLOCK (16000000 / 2)
33 36
34MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 37MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
38MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
35MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); 39MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
36MODULE_ALIAS("platform:" DRV_NAME); 40MODULE_ALIAS("platform:" DRV_NAME);
37MODULE_LICENSE("GPL v2"); 41MODULE_LICENSE("GPL v2");
@@ -66,24 +70,92 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
66 iowrite8(val, priv->reg_base + reg * 4); 70 iowrite8(val, priv->reg_base + reg * 4);
67} 71}
68 72
69static int sp_probe(struct platform_device *pdev) 73static void sp_populate(struct sja1000_priv *priv,
74 struct sja1000_platform_data *pdata,
75 unsigned long resource_mem_flags)
76{
77 /* The CAN clock frequency is half the oscillator clock frequency */
78 priv->can.clock.freq = pdata->osc_freq / 2;
79 priv->ocr = pdata->ocr;
80 priv->cdr = pdata->cdr;
81
82 switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
83 case IORESOURCE_MEM_32BIT:
84 priv->read_reg = sp_read_reg32;
85 priv->write_reg = sp_write_reg32;
86 break;
87 case IORESOURCE_MEM_16BIT:
88 priv->read_reg = sp_read_reg16;
89 priv->write_reg = sp_write_reg16;
90 break;
91 case IORESOURCE_MEM_8BIT:
92 default:
93 priv->read_reg = sp_read_reg8;
94 priv->write_reg = sp_write_reg8;
95 break;
96 }
97}
98
99static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
70{ 100{
71 int err; 101 int err;
102 u32 prop;
103
104 priv->read_reg = sp_read_reg8;
105 priv->write_reg = sp_write_reg8;
106
107 err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
108 if (!err)
109 priv->can.clock.freq = prop / 2;
110 else
111 priv->can.clock.freq = SP_CAN_CLOCK; /* default */
112
113 err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
114 if (!err)
115 priv->ocr |= prop & OCR_MODE_MASK;
116 else
117 priv->ocr |= OCR_MODE_NORMAL; /* default */
118
119 err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
120 if (!err)
121 priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
122 else
123 priv->ocr |= OCR_TX0_PULLDOWN; /* default */
124
125 err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
126 if (!err && prop) {
127 u32 divider = priv->can.clock.freq * 2 / prop;
128
129 if (divider > 1)
130 priv->cdr |= divider / 2 - 1;
131 else
132 priv->cdr |= CDR_CLKOUT_MASK;
133 } else {
134 priv->cdr |= CDR_CLK_OFF; /* default */
135 }
136
137 if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
138 priv->cdr |= CDR_CBP; /* default */
139}
140
141static int sp_probe(struct platform_device *pdev)
142{
143 int err, irq = 0;
72 void __iomem *addr; 144 void __iomem *addr;
73 struct net_device *dev; 145 struct net_device *dev;
74 struct sja1000_priv *priv; 146 struct sja1000_priv *priv;
75 struct resource *res_mem, *res_irq; 147 struct resource *res_mem, *res_irq = NULL;
76 struct sja1000_platform_data *pdata; 148 struct sja1000_platform_data *pdata;
149 struct device_node *of = pdev->dev.of_node;
77 150
78 pdata = dev_get_platdata(&pdev->dev); 151 pdata = dev_get_platdata(&pdev->dev);
79 if (!pdata) { 152 if (!pdata && !of) {
80 dev_err(&pdev->dev, "No platform data provided!\n"); 153 dev_err(&pdev->dev, "No platform data provided!\n");
81 return -ENODEV; 154 return -ENODEV;
82 } 155 }
83 156
84 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 157 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
85 res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 158 if (!res_mem)
86 if (!res_mem || !res_irq)
87 return -ENODEV; 159 return -ENODEV;
88 160
89 if (!devm_request_mem_region(&pdev->dev, res_mem->start, 161 if (!devm_request_mem_region(&pdev->dev, res_mem->start,
@@ -95,36 +167,35 @@ static int sp_probe(struct platform_device *pdev)
95 if (!addr) 167 if (!addr)
96 return -ENOMEM; 168 return -ENOMEM;
97 169
170 if (of)
171 irq = irq_of_parse_and_map(of, 0);
172 else
173 res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
174
175 if (!irq && !res_irq)
176 return -ENODEV;
177
98 dev = alloc_sja1000dev(0); 178 dev = alloc_sja1000dev(0);
99 if (!dev) 179 if (!dev)
100 return -ENOMEM; 180 return -ENOMEM;
101 priv = netdev_priv(dev); 181 priv = netdev_priv(dev);
102 182
103 dev->irq = res_irq->start; 183 if (res_irq) {
104 priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; 184 irq = res_irq->start;
105 if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) 185 priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
106 priv->irq_flags |= IRQF_SHARED; 186 if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
187 priv->irq_flags |= IRQF_SHARED;
188 } else {
189 priv->irq_flags = IRQF_SHARED;
190 }
191
192 dev->irq = irq;
107 priv->reg_base = addr; 193 priv->reg_base = addr;
108 /* The CAN clock frequency is half the oscillator clock frequency */
109 priv->can.clock.freq = pdata->osc_freq / 2;
110 priv->ocr = pdata->ocr;
111 priv->cdr = pdata->cdr;
112 194
113 switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { 195 if (of)
114 case IORESOURCE_MEM_32BIT: 196 sp_populate_of(priv, of);
115 priv->read_reg = sp_read_reg32; 197 else
116 priv->write_reg = sp_write_reg32; 198 sp_populate(priv, pdata, res_mem->flags);
117 break;
118 case IORESOURCE_MEM_16BIT:
119 priv->read_reg = sp_read_reg16;
120 priv->write_reg = sp_write_reg16;
121 break;
122 case IORESOURCE_MEM_8BIT:
123 default:
124 priv->read_reg = sp_read_reg8;
125 priv->write_reg = sp_write_reg8;
126 break;
127 }
128 199
129 platform_set_drvdata(pdev, dev); 200 platform_set_drvdata(pdev, dev);
130 SET_NETDEV_DEV(dev, &pdev->dev); 201 SET_NETDEV_DEV(dev, &pdev->dev);
@@ -155,12 +226,19 @@ static int sp_remove(struct platform_device *pdev)
155 return 0; 226 return 0;
156} 227}
157 228
229static struct of_device_id sp_of_table[] = {
230 {.compatible = "nxp,sja1000"},
231 {},
232};
233MODULE_DEVICE_TABLE(of, sp_of_table);
234
158static struct platform_driver sp_driver = { 235static struct platform_driver sp_driver = {
159 .probe = sp_probe, 236 .probe = sp_probe,
160 .remove = sp_remove, 237 .remove = sp_remove,
161 .driver = { 238 .driver = {
162 .name = DRV_NAME, 239 .name = DRV_NAME,
163 .owner = THIS_MODULE, 240 .owner = THIS_MODULE,
241 .of_match_table = sp_of_table,
164 }, 242 },
165}; 243};
166 244