Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2008-2010
0004  *
0005  * - Kurt Van Dijck, EIA Electronics
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/slab.h>
0011 
0012 #include <pcmcia/cistpl.h>
0013 #include <pcmcia/ds.h>
0014 
0015 #include "softing_platform.h"
0016 
0017 static int softingcs_index;
0018 static DEFINE_SPINLOCK(softingcs_index_lock);
0019 
0020 static int softingcs_reset(struct platform_device *pdev, int v);
0021 static int softingcs_enable_irq(struct platform_device *pdev, int v);
0022 
0023 /*
0024  * platform_data descriptions
0025  */
0026 #define MHZ (1000*1000)
0027 static const struct softing_platform_data softingcs_platform_data[] = {
0028 {
0029     .name = "CANcard",
0030     .manf = 0x0168, .prod = 0x001,
0031     .generation = 1,
0032     .nbus = 2,
0033     .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
0034     .dpram_size = 0x0800,
0035     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0036     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0037     .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
0038     .reset = softingcs_reset,
0039     .enable_irq = softingcs_enable_irq,
0040 }, {
0041     .name = "CANcard-NEC",
0042     .manf = 0x0168, .prod = 0x002,
0043     .generation = 1,
0044     .nbus = 2,
0045     .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
0046     .dpram_size = 0x0800,
0047     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0048     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0049     .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
0050     .reset = softingcs_reset,
0051     .enable_irq = softingcs_enable_irq,
0052 }, {
0053     .name = "CANcard-SJA",
0054     .manf = 0x0168, .prod = 0x004,
0055     .generation = 1,
0056     .nbus = 2,
0057     .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
0058     .dpram_size = 0x0800,
0059     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0060     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0061     .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
0062     .reset = softingcs_reset,
0063     .enable_irq = softingcs_enable_irq,
0064 }, {
0065     .name = "CANcard-2",
0066     .manf = 0x0168, .prod = 0x005,
0067     .generation = 2,
0068     .nbus = 2,
0069     .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
0070     .dpram_size = 0x1000,
0071     .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
0072     .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
0073     .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
0074     .reset = softingcs_reset,
0075     .enable_irq = NULL,
0076 }, {
0077     .name = "Vector-CANcard",
0078     .manf = 0x0168, .prod = 0x081,
0079     .generation = 1,
0080     .nbus = 2,
0081     .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
0082     .dpram_size = 0x0800,
0083     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0084     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0085     .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
0086     .reset = softingcs_reset,
0087     .enable_irq = softingcs_enable_irq,
0088 }, {
0089     .name = "Vector-CANcard-SJA",
0090     .manf = 0x0168, .prod = 0x084,
0091     .generation = 1,
0092     .nbus = 2,
0093     .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
0094     .dpram_size = 0x0800,
0095     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0096     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0097     .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
0098     .reset = softingcs_reset,
0099     .enable_irq = softingcs_enable_irq,
0100 }, {
0101     .name = "Vector-CANcard-2",
0102     .manf = 0x0168, .prod = 0x085,
0103     .generation = 2,
0104     .nbus = 2,
0105     .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
0106     .dpram_size = 0x1000,
0107     .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
0108     .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
0109     .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
0110     .reset = softingcs_reset,
0111     .enable_irq = NULL,
0112 }, {
0113     .name = "EDICcard-NEC",
0114     .manf = 0x0168, .prod = 0x102,
0115     .generation = 1,
0116     .nbus = 2,
0117     .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
0118     .dpram_size = 0x0800,
0119     .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
0120     .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
0121     .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
0122     .reset = softingcs_reset,
0123     .enable_irq = softingcs_enable_irq,
0124 }, {
0125     .name = "EDICcard-2",
0126     .manf = 0x0168, .prod = 0x105,
0127     .generation = 2,
0128     .nbus = 2,
0129     .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
0130     .dpram_size = 0x1000,
0131     .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
0132     .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
0133     .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
0134     .reset = softingcs_reset,
0135     .enable_irq = NULL,
0136 }, {
0137     0, 0,
0138 },
0139 };
0140 
0141 MODULE_FIRMWARE(fw_dir "bcard.bin");
0142 MODULE_FIRMWARE(fw_dir "ldcard.bin");
0143 MODULE_FIRMWARE(fw_dir "cancard.bin");
0144 MODULE_FIRMWARE(fw_dir "cansja.bin");
0145 
0146 MODULE_FIRMWARE(fw_dir "bcard2.bin");
0147 MODULE_FIRMWARE(fw_dir "ldcard2.bin");
0148 MODULE_FIRMWARE(fw_dir "cancrd2.bin");
0149 
0150 static const struct softing_platform_data
0151 *softingcs_find_platform_data(unsigned int manf, unsigned int prod)
0152 {
0153     const struct softing_platform_data *lp;
0154 
0155     for (lp = softingcs_platform_data; lp->manf; ++lp) {
0156         if ((lp->manf == manf) && (lp->prod == prod))
0157             return lp;
0158     }
0159     return NULL;
0160 }
0161 
0162 /*
0163  * platformdata callbacks
0164  */
0165 static int softingcs_reset(struct platform_device *pdev, int v)
0166 {
0167     struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
0168 
0169     dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
0170     return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
0171 }
0172 
0173 static int softingcs_enable_irq(struct platform_device *pdev, int v)
0174 {
0175     struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
0176 
0177     dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
0178     return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
0179 }
0180 
0181 /*
0182  * pcmcia check
0183  */
0184 static int softingcs_probe_config(struct pcmcia_device *pcmcia, void *priv_data)
0185 {
0186     struct softing_platform_data *pdat = priv_data;
0187     struct resource *pres;
0188     int memspeed = 0;
0189 
0190     WARN_ON(!pdat);
0191     pres = pcmcia->resource[PCMCIA_IOMEM_0];
0192     if (resource_size(pres) < 0x1000)
0193         return -ERANGE;
0194 
0195     pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
0196     if (pdat->generation < 2) {
0197         pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
0198         memspeed = 3;
0199     } else {
0200         pres->flags |= WIN_DATA_WIDTH_16;
0201     }
0202     return pcmcia_request_window(pcmcia, pres, memspeed);
0203 }
0204 
0205 static void softingcs_remove(struct pcmcia_device *pcmcia)
0206 {
0207     struct platform_device *pdev = pcmcia->priv;
0208 
0209     /* free bits */
0210     platform_device_unregister(pdev);
0211     /* release pcmcia stuff */
0212     pcmcia_disable_device(pcmcia);
0213 }
0214 
0215 /*
0216  * platform_device wrapper
0217  * pdev->resource has 2 entries: io & irq
0218  */
0219 static void softingcs_pdev_release(struct device *dev)
0220 {
0221     struct platform_device *pdev = to_platform_device(dev);
0222     kfree(pdev);
0223 }
0224 
0225 static int softingcs_probe(struct pcmcia_device *pcmcia)
0226 {
0227     int ret;
0228     struct platform_device *pdev;
0229     const struct softing_platform_data *pdat;
0230     struct resource *pres;
0231     struct dev {
0232         struct platform_device pdev;
0233         struct resource res[2];
0234     } *dev;
0235 
0236     /* find matching platform_data */
0237     pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
0238     if (!pdat)
0239         return -ENOTTY;
0240 
0241     /* setup pcmcia device */
0242     pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
0243         CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
0244     ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
0245     if (ret)
0246         goto pcmcia_failed;
0247 
0248     ret = pcmcia_enable_device(pcmcia);
0249     if (ret < 0)
0250         goto pcmcia_failed;
0251 
0252     pres = pcmcia->resource[PCMCIA_IOMEM_0];
0253     if (!pres) {
0254         ret = -EBADF;
0255         goto pcmcia_bad;
0256     }
0257 
0258     /* create softing platform device */
0259     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0260     if (!dev) {
0261         ret = -ENOMEM;
0262         goto mem_failed;
0263     }
0264     dev->pdev.resource = dev->res;
0265     dev->pdev.num_resources = ARRAY_SIZE(dev->res);
0266     dev->pdev.dev.release = softingcs_pdev_release;
0267 
0268     pdev = &dev->pdev;
0269     pdev->dev.platform_data = (void *)pdat;
0270     pdev->dev.parent = &pcmcia->dev;
0271     pcmcia->priv = pdev;
0272 
0273     /* platform device resources */
0274     pdev->resource[0].flags = IORESOURCE_MEM;
0275     pdev->resource[0].start = pres->start;
0276     pdev->resource[0].end = pres->end;
0277 
0278     pdev->resource[1].flags = IORESOURCE_IRQ;
0279     pdev->resource[1].start = pcmcia->irq;
0280     pdev->resource[1].end = pdev->resource[1].start;
0281 
0282     /* platform device setup */
0283     spin_lock(&softingcs_index_lock);
0284     pdev->id = softingcs_index++;
0285     spin_unlock(&softingcs_index_lock);
0286     pdev->name = "softing";
0287     dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
0288     ret = platform_device_register(pdev);
0289     if (ret < 0)
0290         goto platform_failed;
0291 
0292     dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
0293     return 0;
0294 
0295 platform_failed:
0296     platform_device_put(pdev);
0297 mem_failed:
0298 pcmcia_bad:
0299 pcmcia_failed:
0300     pcmcia_disable_device(pcmcia);
0301     pcmcia->priv = NULL;
0302     return ret;
0303 }
0304 
0305 static const struct pcmcia_device_id softingcs_ids[] = {
0306     /* softing */
0307     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
0308     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
0309     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
0310     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
0311     /* vector, manufacturer? */
0312     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
0313     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
0314     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
0315     /* EDIC */
0316     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
0317     PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
0318     PCMCIA_DEVICE_NULL,
0319 };
0320 
0321 MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
0322 
0323 static struct pcmcia_driver softingcs_driver = {
0324     .owner      = THIS_MODULE,
0325     .name       = "softingcs",
0326     .id_table   = softingcs_ids,
0327     .probe      = softingcs_probe,
0328     .remove     = softingcs_remove,
0329 };
0330 
0331 module_pcmcia_driver(softingcs_driver);
0332 
0333 MODULE_DESCRIPTION("softing CANcard driver"
0334         ", links PCMCIA card to softing driver");
0335 MODULE_LICENSE("GPL v2");