Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / net / can / softing / softing_cs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2008-2010
4  *
5  * - Kurt Van Dijck, EIA Electronics
6  */
7
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11
12 #include <pcmcia/cistpl.h>
13 #include <pcmcia/ds.h>
14
15 #include "softing_platform.h"
16
17 static int softingcs_index;
18 static DEFINE_SPINLOCK(softingcs_index_lock);
19
20 static int softingcs_reset(struct platform_device *pdev, int v);
21 static int softingcs_enable_irq(struct platform_device *pdev, int v);
22
23 /*
24  * platform_data descriptions
25  */
26 #define MHZ (1000*1000)
27 static const struct softing_platform_data softingcs_platform_data[] = {
28 {
29         .name = "CANcard",
30         .manf = 0x0168, .prod = 0x001,
31         .generation = 1,
32         .nbus = 2,
33         .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
34         .dpram_size = 0x0800,
35         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
36         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
37         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
38         .reset = softingcs_reset,
39         .enable_irq = softingcs_enable_irq,
40 }, {
41         .name = "CANcard-NEC",
42         .manf = 0x0168, .prod = 0x002,
43         .generation = 1,
44         .nbus = 2,
45         .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
46         .dpram_size = 0x0800,
47         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
48         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
49         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
50         .reset = softingcs_reset,
51         .enable_irq = softingcs_enable_irq,
52 }, {
53         .name = "CANcard-SJA",
54         .manf = 0x0168, .prod = 0x004,
55         .generation = 1,
56         .nbus = 2,
57         .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
58         .dpram_size = 0x0800,
59         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
60         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
61         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
62         .reset = softingcs_reset,
63         .enable_irq = softingcs_enable_irq,
64 }, {
65         .name = "CANcard-2",
66         .manf = 0x0168, .prod = 0x005,
67         .generation = 2,
68         .nbus = 2,
69         .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
70         .dpram_size = 0x1000,
71         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
72         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
73         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
74         .reset = softingcs_reset,
75         .enable_irq = NULL,
76 }, {
77         .name = "Vector-CANcard",
78         .manf = 0x0168, .prod = 0x081,
79         .generation = 1,
80         .nbus = 2,
81         .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
82         .dpram_size = 0x0800,
83         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
84         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
85         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
86         .reset = softingcs_reset,
87         .enable_irq = softingcs_enable_irq,
88 }, {
89         .name = "Vector-CANcard-SJA",
90         .manf = 0x0168, .prod = 0x084,
91         .generation = 1,
92         .nbus = 2,
93         .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
94         .dpram_size = 0x0800,
95         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
96         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
97         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
98         .reset = softingcs_reset,
99         .enable_irq = softingcs_enable_irq,
100 }, {
101         .name = "Vector-CANcard-2",
102         .manf = 0x0168, .prod = 0x085,
103         .generation = 2,
104         .nbus = 2,
105         .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
106         .dpram_size = 0x1000,
107         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
108         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
109         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
110         .reset = softingcs_reset,
111         .enable_irq = NULL,
112 }, {
113         .name = "EDICcard-NEC",
114         .manf = 0x0168, .prod = 0x102,
115         .generation = 1,
116         .nbus = 2,
117         .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
118         .dpram_size = 0x0800,
119         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
120         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
121         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
122         .reset = softingcs_reset,
123         .enable_irq = softingcs_enable_irq,
124 }, {
125         .name = "EDICcard-2",
126         .manf = 0x0168, .prod = 0x105,
127         .generation = 2,
128         .nbus = 2,
129         .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
130         .dpram_size = 0x1000,
131         .boot = {0x0000, 0x000000, fw_dir "/*(DEBLOBBED)*/",},
132         .load = {0x0120, 0x00f600, fw_dir "/*(DEBLOBBED)*/",},
133         .app = {0x0010, 0x0d0000, fw_dir "/*(DEBLOBBED)*/",},
134         .reset = softingcs_reset,
135         .enable_irq = NULL,
136 }, {
137         0, 0,
138 },
139 };
140
141 /*(DEBLOBBED)*/
142
143 static const struct softing_platform_data
144 *softingcs_find_platform_data(unsigned int manf, unsigned int prod)
145 {
146         const struct softing_platform_data *lp;
147
148         for (lp = softingcs_platform_data; lp->manf; ++lp) {
149                 if ((lp->manf == manf) && (lp->prod == prod))
150                         return lp;
151         }
152         return NULL;
153 }
154
155 /*
156  * platformdata callbacks
157  */
158 static int softingcs_reset(struct platform_device *pdev, int v)
159 {
160         struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
161
162         dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
163         return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
164 }
165
166 static int softingcs_enable_irq(struct platform_device *pdev, int v)
167 {
168         struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
169
170         dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
171         return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
172 }
173
174 /*
175  * pcmcia check
176  */
177 static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data)
178 {
179         struct softing_platform_data *pdat = priv_data;
180         struct resource *pres;
181         int memspeed = 0;
182
183         WARN_ON(!pdat);
184         pres = pcmcia->resource[PCMCIA_IOMEM_0];
185         if (resource_size(pres) < 0x1000)
186                 return -ERANGE;
187
188         pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
189         if (pdat->generation < 2) {
190                 pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
191                 memspeed = 3;
192         } else {
193                 pres->flags |= WIN_DATA_WIDTH_16;
194         }
195         return pcmcia_request_window(pcmcia, pres, memspeed);
196 }
197
198 static void softingcs_remove(struct pcmcia_device *pcmcia)
199 {
200         struct platform_device *pdev = pcmcia->priv;
201
202         /* free bits */
203         platform_device_unregister(pdev);
204         /* release pcmcia stuff */
205         pcmcia_disable_device(pcmcia);
206 }
207
208 /*
209  * platform_device wrapper
210  * pdev->resource has 2 entries: io & irq
211  */
212 static void softingcs_pdev_release(struct device *dev)
213 {
214         struct platform_device *pdev = to_platform_device(dev);
215         kfree(pdev);
216 }
217
218 static int softingcs_probe(struct pcmcia_device *pcmcia)
219 {
220         int ret;
221         struct platform_device *pdev;
222         const struct softing_platform_data *pdat;
223         struct resource *pres;
224         struct dev {
225                 struct platform_device pdev;
226                 struct resource res[2];
227         } *dev;
228
229         /* find matching platform_data */
230         pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
231         if (!pdat)
232                 return -ENOTTY;
233
234         /* setup pcmcia device */
235         pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
236                 CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
237         ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
238         if (ret)
239                 goto pcmcia_failed;
240
241         ret = pcmcia_enable_device(pcmcia);
242         if (ret < 0)
243                 goto pcmcia_failed;
244
245         pres = pcmcia->resource[PCMCIA_IOMEM_0];
246         if (!pres) {
247                 ret = -EBADF;
248                 goto pcmcia_bad;
249         }
250
251         /* create softing platform device */
252         dev = kzalloc(sizeof(*dev), GFP_KERNEL);
253         if (!dev) {
254                 ret = -ENOMEM;
255                 goto mem_failed;
256         }
257         dev->pdev.resource = dev->res;
258         dev->pdev.num_resources = ARRAY_SIZE(dev->res);
259         dev->pdev.dev.release = softingcs_pdev_release;
260
261         pdev = &dev->pdev;
262         pdev->dev.platform_data = (void *)pdat;
263         pdev->dev.parent = &pcmcia->dev;
264         pcmcia->priv = pdev;
265
266         /* platform device resources */
267         pdev->resource[0].flags = IORESOURCE_MEM;
268         pdev->resource[0].start = pres->start;
269         pdev->resource[0].end = pres->end;
270
271         pdev->resource[1].flags = IORESOURCE_IRQ;
272         pdev->resource[1].start = pcmcia->irq;
273         pdev->resource[1].end = pdev->resource[1].start;
274
275         /* platform device setup */
276         spin_lock(&softingcs_index_lock);
277         pdev->id = softingcs_index++;
278         spin_unlock(&softingcs_index_lock);
279         pdev->name = "softing";
280         dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
281         ret = platform_device_register(pdev);
282         if (ret < 0)
283                 goto platform_failed;
284
285         dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
286         return 0;
287
288 platform_failed:
289         kfree(dev);
290 mem_failed:
291 pcmcia_bad:
292 pcmcia_failed:
293         pcmcia_disable_device(pcmcia);
294         pcmcia->priv = NULL;
295         return ret;
296 }
297
298 static const struct pcmcia_device_id softingcs_ids[] = {
299         /* softing */
300         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
301         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
302         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
303         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
304         /* vector, manufacturer? */
305         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
306         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
307         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
308         /* EDIC */
309         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
310         PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
311         PCMCIA_DEVICE_NULL,
312 };
313
314 MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
315
316 static struct pcmcia_driver softingcs_driver = {
317         .owner          = THIS_MODULE,
318         .name           = "softingcs",
319         .id_table       = softingcs_ids,
320         .probe          = softingcs_probe,
321         .remove         = softingcs_remove,
322 };
323
324 module_pcmcia_driver(softingcs_driver);
325
326 MODULE_DESCRIPTION("softing CANcard driver"
327                 ", links PCMCIA card to softing driver");
328 MODULE_LICENSE("GPL v2");