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