0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <linux/kernel.h>
0038 #include <linux/module.h>
0039 #include <linux/interrupt.h>
0040 #include <linux/netdevice.h>
0041 #include <linux/delay.h>
0042 #include <linux/platform_device.h>
0043 #include <linux/of.h>
0044 #include <linux/can.h>
0045 #include <linux/can/dev.h>
0046 #include <linux/can/platform/cc770.h>
0047
0048 #include "cc770.h"
0049
0050 #define DRV_NAME "cc770_platform"
0051
0052 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
0053 MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus");
0054 MODULE_LICENSE("GPL v2");
0055 MODULE_ALIAS("platform:" DRV_NAME);
0056
0057 #define CC770_PLATFORM_CAN_CLOCK 16000000
0058
0059 static u8 cc770_platform_read_reg(const struct cc770_priv *priv, int reg)
0060 {
0061 return ioread8(priv->reg_base + reg);
0062 }
0063
0064 static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg,
0065 u8 val)
0066 {
0067 iowrite8(val, priv->reg_base + reg);
0068 }
0069
0070 static int cc770_get_of_node_data(struct platform_device *pdev,
0071 struct cc770_priv *priv)
0072 {
0073 struct device_node *np = pdev->dev.of_node;
0074 const u32 *prop;
0075 int prop_size;
0076 u32 clkext;
0077
0078 prop = of_get_property(np, "bosch,external-clock-frequency",
0079 &prop_size);
0080 if (prop && (prop_size == sizeof(u32)))
0081 clkext = *prop;
0082 else
0083 clkext = CC770_PLATFORM_CAN_CLOCK;
0084 priv->can.clock.freq = clkext;
0085
0086
0087 if (priv->can.clock.freq > 10000000) {
0088 priv->cpu_interface |= CPUIF_DSC;
0089 priv->can.clock.freq /= 2;
0090 }
0091
0092
0093 if (priv->can.clock.freq > 8000000)
0094 priv->cpu_interface |= CPUIF_DMC;
0095
0096 if (of_get_property(np, "bosch,divide-memory-clock", NULL))
0097 priv->cpu_interface |= CPUIF_DMC;
0098 if (of_get_property(np, "bosch,iso-low-speed-mux", NULL))
0099 priv->cpu_interface |= CPUIF_MUX;
0100
0101 if (!of_get_property(np, "bosch,no-comperator-bypass", NULL))
0102 priv->bus_config |= BUSCFG_CBY;
0103 if (of_get_property(np, "bosch,disconnect-rx0-input", NULL))
0104 priv->bus_config |= BUSCFG_DR0;
0105 if (of_get_property(np, "bosch,disconnect-rx1-input", NULL))
0106 priv->bus_config |= BUSCFG_DR1;
0107 if (of_get_property(np, "bosch,disconnect-tx1-output", NULL))
0108 priv->bus_config |= BUSCFG_DT1;
0109 if (of_get_property(np, "bosch,polarity-dominant", NULL))
0110 priv->bus_config |= BUSCFG_POL;
0111
0112 prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size);
0113 if (prop && (prop_size == sizeof(u32)) && *prop > 0) {
0114 u32 cdv = clkext / *prop;
0115 int slew;
0116
0117 if (cdv > 0 && cdv < 16) {
0118 priv->cpu_interface |= CPUIF_CEN;
0119 priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK;
0120
0121 prop = of_get_property(np, "bosch,slew-rate",
0122 &prop_size);
0123 if (prop && (prop_size == sizeof(u32))) {
0124 slew = *prop;
0125 } else {
0126
0127 slew = (CLKOUT_SL_MASK >>
0128 CLKOUT_SL_SHIFT) -
0129 ((cdv * clkext - 1) / 8000000);
0130 if (slew < 0)
0131 slew = 0;
0132 }
0133 priv->clkout |= (slew << CLKOUT_SL_SHIFT) &
0134 CLKOUT_SL_MASK;
0135 } else {
0136 dev_dbg(&pdev->dev, "invalid clock-out-frequency\n");
0137 }
0138 }
0139
0140 return 0;
0141 }
0142
0143 static int cc770_get_platform_data(struct platform_device *pdev,
0144 struct cc770_priv *priv)
0145 {
0146
0147 struct cc770_platform_data *pdata = dev_get_platdata(&pdev->dev);
0148
0149 priv->can.clock.freq = pdata->osc_freq;
0150 if (priv->cpu_interface & CPUIF_DSC)
0151 priv->can.clock.freq /= 2;
0152 priv->clkout = pdata->cor;
0153 priv->bus_config = pdata->bcr;
0154 priv->cpu_interface = pdata->cir;
0155
0156 return 0;
0157 }
0158
0159 static int cc770_platform_probe(struct platform_device *pdev)
0160 {
0161 struct net_device *dev;
0162 struct cc770_priv *priv;
0163 struct resource *mem;
0164 resource_size_t mem_size;
0165 void __iomem *base;
0166 int err, irq;
0167
0168 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0169 irq = platform_get_irq(pdev, 0);
0170 if (!mem || irq <= 0)
0171 return -ENODEV;
0172
0173 mem_size = resource_size(mem);
0174 if (!request_mem_region(mem->start, mem_size, pdev->name))
0175 return -EBUSY;
0176
0177 base = ioremap(mem->start, mem_size);
0178 if (!base) {
0179 err = -ENOMEM;
0180 goto exit_release_mem;
0181 }
0182
0183 dev = alloc_cc770dev(0);
0184 if (!dev) {
0185 err = -ENOMEM;
0186 goto exit_unmap_mem;
0187 }
0188
0189 dev->irq = irq;
0190 priv = netdev_priv(dev);
0191 priv->read_reg = cc770_platform_read_reg;
0192 priv->write_reg = cc770_platform_write_reg;
0193 priv->irq_flags = IRQF_SHARED;
0194 priv->reg_base = base;
0195
0196 if (pdev->dev.of_node)
0197 err = cc770_get_of_node_data(pdev, priv);
0198 else if (dev_get_platdata(&pdev->dev))
0199 err = cc770_get_platform_data(pdev, priv);
0200 else
0201 err = -ENODEV;
0202 if (err)
0203 goto exit_free_cc770;
0204
0205 dev_dbg(&pdev->dev,
0206 "reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x "
0207 "bus_config=0x%02x clkout=0x%02x\n",
0208 priv->reg_base, dev->irq, priv->can.clock.freq,
0209 priv->cpu_interface, priv->bus_config, priv->clkout);
0210
0211 platform_set_drvdata(pdev, dev);
0212 SET_NETDEV_DEV(dev, &pdev->dev);
0213
0214 err = register_cc770dev(dev);
0215 if (err) {
0216 dev_err(&pdev->dev,
0217 "couldn't register CC700 device (err=%d)\n", err);
0218 goto exit_free_cc770;
0219 }
0220
0221 return 0;
0222
0223 exit_free_cc770:
0224 free_cc770dev(dev);
0225 exit_unmap_mem:
0226 iounmap(base);
0227 exit_release_mem:
0228 release_mem_region(mem->start, mem_size);
0229
0230 return err;
0231 }
0232
0233 static int cc770_platform_remove(struct platform_device *pdev)
0234 {
0235 struct net_device *dev = platform_get_drvdata(pdev);
0236 struct cc770_priv *priv = netdev_priv(dev);
0237 struct resource *mem;
0238
0239 unregister_cc770dev(dev);
0240 iounmap(priv->reg_base);
0241 free_cc770dev(dev);
0242
0243 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0244 release_mem_region(mem->start, resource_size(mem));
0245
0246 return 0;
0247 }
0248
0249 static const struct of_device_id cc770_platform_table[] = {
0250 {.compatible = "bosch,cc770"},
0251 {.compatible = "intc,82527"},
0252 {},
0253 };
0254 MODULE_DEVICE_TABLE(of, cc770_platform_table);
0255
0256 static struct platform_driver cc770_platform_driver = {
0257 .driver = {
0258 .name = DRV_NAME,
0259 .of_match_table = cc770_platform_table,
0260 },
0261 .probe = cc770_platform_probe,
0262 .remove = cc770_platform_remove,
0263 };
0264
0265 module_platform_driver(cc770_platform_driver);