1 /* 2 * Driver for CC770 and AN82527 CAN controllers on the platform bus 3 * 4 * Copyright (C) 2009, 2011 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 16 /* 17 * If platform data are used you should have similar definitions 18 * in your board-specific code: 19 * 20 * static struct cc770_platform_data myboard_cc770_pdata = { 21 * .osc_freq = 16000000, 22 * .cir = 0x41, 23 * .cor = 0x20, 24 * .bcr = 0x40, 25 * }; 26 * 27 * Please see include/linux/can/platform/cc770.h for description of 28 * above fields. 29 * 30 * If the device tree is used, you need a CAN node definition in your 31 * DTS file similar to: 32 * 33 * can@3,100 { 34 * compatible = "bosch,cc770"; 35 * reg = <3 0x100 0x80>; 36 * interrupts = <2 0>; 37 * interrupt-parent = <&mpic>; 38 * bosch,external-clock-frequency = <16000000>; 39 * }; 40 * 41 * See "Documentation/devicetree/bindings/net/can/cc770.txt" for further 42 * information. 43 */ 44 45 #include <linux/kernel.h> 46 #include <linux/module.h> 47 #include <linux/interrupt.h> 48 #include <linux/netdevice.h> 49 #include <linux/delay.h> 50 #include <linux/platform_device.h> 51 #include <linux/of.h> 52 #include <linux/can.h> 53 #include <linux/can/dev.h> 54 #include <linux/can/platform/cc770.h> 55 56 #include "cc770.h" 57 58 #define DRV_NAME "cc770_platform" 59 60 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); 61 MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the platform bus"); 62 MODULE_LICENSE("GPL v2"); 63 64 #define CC770_PLATFORM_CAN_CLOCK 16000000 65 66 static u8 cc770_platform_read_reg(const struct cc770_priv *priv, int reg) 67 { 68 return ioread8(priv->reg_base + reg); 69 } 70 71 static void cc770_platform_write_reg(const struct cc770_priv *priv, int reg, 72 u8 val) 73 { 74 iowrite8(val, priv->reg_base + reg); 75 } 76 77 static int __devinit cc770_get_of_node_data(struct platform_device *pdev, 78 struct cc770_priv *priv) 79 { 80 struct device_node *np = pdev->dev.of_node; 81 const u32 *prop; 82 int prop_size; 83 u32 clkext; 84 85 prop = of_get_property(np, "bosch,external-clock-frequency", 86 &prop_size); 87 if (prop && (prop_size == sizeof(u32))) 88 clkext = *prop; 89 else 90 clkext = CC770_PLATFORM_CAN_CLOCK; /* default */ 91 priv->can.clock.freq = clkext; 92 93 /* The system clock may not exceed 10 MHz */ 94 if (priv->can.clock.freq > 10000000) { 95 priv->cpu_interface |= CPUIF_DSC; 96 priv->can.clock.freq /= 2; 97 } 98 99 /* The memory clock may not exceed 8 MHz */ 100 if (priv->can.clock.freq > 8000000) 101 priv->cpu_interface |= CPUIF_DMC; 102 103 if (of_get_property(np, "bosch,divide-memory-clock", NULL)) 104 priv->cpu_interface |= CPUIF_DMC; 105 if (of_get_property(np, "bosch,iso-low-speed-mux", NULL)) 106 priv->cpu_interface |= CPUIF_MUX; 107 108 if (!of_get_property(np, "bosch,no-comperator-bypass", NULL)) 109 priv->bus_config |= BUSCFG_CBY; 110 if (of_get_property(np, "bosch,disconnect-rx0-input", NULL)) 111 priv->bus_config |= BUSCFG_DR0; 112 if (of_get_property(np, "bosch,disconnect-rx1-input", NULL)) 113 priv->bus_config |= BUSCFG_DR1; 114 if (of_get_property(np, "bosch,disconnect-tx1-output", NULL)) 115 priv->bus_config |= BUSCFG_DT1; 116 if (of_get_property(np, "bosch,polarity-dominant", NULL)) 117 priv->bus_config |= BUSCFG_POL; 118 119 prop = of_get_property(np, "bosch,clock-out-frequency", &prop_size); 120 if (prop && (prop_size == sizeof(u32)) && *prop > 0) { 121 u32 cdv = clkext / *prop; 122 int slew; 123 124 if (cdv > 0 && cdv < 16) { 125 priv->cpu_interface |= CPUIF_CEN; 126 priv->clkout |= (cdv - 1) & CLKOUT_CD_MASK; 127 128 prop = of_get_property(np, "bosch,slew-rate", 129 &prop_size); 130 if (prop && (prop_size == sizeof(u32))) { 131 slew = *prop; 132 } else { 133 /* Determine default slew rate */ 134 slew = (CLKOUT_SL_MASK >> 135 CLKOUT_SL_SHIFT) - 136 ((cdv * clkext - 1) / 8000000); 137 if (slew < 0) 138 slew = 0; 139 } 140 priv->clkout |= (slew << CLKOUT_SL_SHIFT) & 141 CLKOUT_SL_MASK; 142 } else { 143 dev_dbg(&pdev->dev, "invalid clock-out-frequency\n"); 144 } 145 } 146 147 return 0; 148 } 149 150 static int __devinit cc770_get_platform_data(struct platform_device *pdev, 151 struct cc770_priv *priv) 152 { 153 154 struct cc770_platform_data *pdata = pdev->dev.platform_data; 155 156 priv->can.clock.freq = pdata->osc_freq; 157 if (priv->cpu_interface | CPUIF_DSC) 158 priv->can.clock.freq /= 2; 159 priv->clkout = pdata->cor; 160 priv->bus_config = pdata->bcr; 161 priv->cpu_interface = pdata->cir; 162 163 return 0; 164 } 165 166 static int __devinit cc770_platform_probe(struct platform_device *pdev) 167 { 168 struct net_device *dev; 169 struct cc770_priv *priv; 170 struct resource *mem; 171 resource_size_t mem_size; 172 void __iomem *base; 173 int err, irq; 174 175 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 176 irq = platform_get_irq(pdev, 0); 177 if (!mem || irq <= 0) 178 return -ENODEV; 179 180 mem_size = resource_size(mem); 181 if (!request_mem_region(mem->start, mem_size, pdev->name)) 182 return -EBUSY; 183 184 base = ioremap(mem->start, mem_size); 185 if (!base) { 186 err = -ENOMEM; 187 goto exit_release_mem; 188 } 189 190 dev = alloc_cc770dev(0); 191 if (!dev) { 192 err = -ENOMEM; 193 goto exit_unmap_mem; 194 } 195 196 dev->irq = irq; 197 priv = netdev_priv(dev); 198 priv->read_reg = cc770_platform_read_reg; 199 priv->write_reg = cc770_platform_write_reg; 200 priv->irq_flags = IRQF_SHARED; 201 priv->reg_base = base; 202 203 if (pdev->dev.of_node) 204 err = cc770_get_of_node_data(pdev, priv); 205 else if (pdev->dev.platform_data) 206 err = cc770_get_platform_data(pdev, priv); 207 else 208 err = -ENODEV; 209 if (err) 210 goto exit_free_cc770; 211 212 dev_dbg(&pdev->dev, 213 "reg_base=0x%p irq=%d clock=%d cpu_interface=0x%02x " 214 "bus_config=0x%02x clkout=0x%02x\n", 215 priv->reg_base, dev->irq, priv->can.clock.freq, 216 priv->cpu_interface, priv->bus_config, priv->clkout); 217 218 dev_set_drvdata(&pdev->dev, dev); 219 SET_NETDEV_DEV(dev, &pdev->dev); 220 221 err = register_cc770dev(dev); 222 if (err) { 223 dev_err(&pdev->dev, 224 "couldn't register CC700 device (err=%d)\n", err); 225 goto exit_free_cc770; 226 } 227 228 return 0; 229 230 exit_free_cc770: 231 free_cc770dev(dev); 232 exit_unmap_mem: 233 iounmap(base); 234 exit_release_mem: 235 release_mem_region(mem->start, mem_size); 236 237 return err; 238 } 239 240 static int __devexit cc770_platform_remove(struct platform_device *pdev) 241 { 242 struct net_device *dev = dev_get_drvdata(&pdev->dev); 243 struct cc770_priv *priv = netdev_priv(dev); 244 struct resource *mem; 245 246 unregister_cc770dev(dev); 247 iounmap(priv->reg_base); 248 free_cc770dev(dev); 249 250 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 251 release_mem_region(mem->start, resource_size(mem)); 252 253 return 0; 254 } 255 256 static struct of_device_id __devinitdata cc770_platform_table[] = { 257 {.compatible = "bosch,cc770"}, /* CC770 from Bosch */ 258 {.compatible = "intc,82527"}, /* AN82527 from Intel CP */ 259 {}, 260 }; 261 262 static struct platform_driver cc770_platform_driver = { 263 .driver = { 264 .name = DRV_NAME, 265 .owner = THIS_MODULE, 266 .of_match_table = cc770_platform_table, 267 }, 268 .probe = cc770_platform_probe, 269 .remove = __devexit_p(cc770_platform_remove), 270 }; 271 272 module_platform_driver(cc770_platform_driver); 273