1f534e52fSWolfgang Grandegger /* 2f534e52fSWolfgang Grandegger * Copyright (C) 2005 Sascha Hauer, Pengutronix 3f534e52fSWolfgang Grandegger * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> 4f534e52fSWolfgang Grandegger * 5f534e52fSWolfgang Grandegger * This program is free software; you can redistribute it and/or modify 6f534e52fSWolfgang Grandegger * it under the terms of the version 2 of the GNU General Public License 7f534e52fSWolfgang Grandegger * as published by the Free Software Foundation 8f534e52fSWolfgang Grandegger * 9f534e52fSWolfgang Grandegger * This program is distributed in the hope that it will be useful, 10f534e52fSWolfgang Grandegger * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f534e52fSWolfgang Grandegger * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f534e52fSWolfgang Grandegger * GNU General Public License for more details. 13f534e52fSWolfgang Grandegger * 14f534e52fSWolfgang Grandegger * You should have received a copy of the GNU General Public License 15f534e52fSWolfgang Grandegger * along with this program; if not, write to the Free Software 16f534e52fSWolfgang Grandegger * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17f534e52fSWolfgang Grandegger */ 18f534e52fSWolfgang Grandegger 19f534e52fSWolfgang Grandegger #include <linux/kernel.h> 20f534e52fSWolfgang Grandegger #include <linux/module.h> 21f534e52fSWolfgang Grandegger #include <linux/interrupt.h> 22f534e52fSWolfgang Grandegger #include <linux/netdevice.h> 23f534e52fSWolfgang Grandegger #include <linux/delay.h> 24f534e52fSWolfgang Grandegger #include <linux/pci.h> 25f534e52fSWolfgang Grandegger #include <linux/platform_device.h> 26f534e52fSWolfgang Grandegger #include <linux/irq.h> 27f534e52fSWolfgang Grandegger #include <linux/can/dev.h> 28f534e52fSWolfgang Grandegger #include <linux/can/platform/sja1000.h> 29f534e52fSWolfgang Grandegger #include <linux/io.h> 30f534e52fSWolfgang Grandegger 31f534e52fSWolfgang Grandegger #include "sja1000.h" 32f534e52fSWolfgang Grandegger 33f534e52fSWolfgang Grandegger #define DRV_NAME "sja1000_platform" 34f534e52fSWolfgang Grandegger 35f534e52fSWolfgang Grandegger MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 36f534e52fSWolfgang Grandegger MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); 37f534e52fSWolfgang Grandegger MODULE_LICENSE("GPL v2"); 38f534e52fSWolfgang Grandegger 39986917b7SYegor Yefremov static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) 40f534e52fSWolfgang Grandegger { 41255a9154SWolfgang Grandegger return ioread8(priv->reg_base + reg); 42f534e52fSWolfgang Grandegger } 43f534e52fSWolfgang Grandegger 44986917b7SYegor Yefremov static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val) 45f534e52fSWolfgang Grandegger { 46255a9154SWolfgang Grandegger iowrite8(val, priv->reg_base + reg); 47f534e52fSWolfgang Grandegger } 48f534e52fSWolfgang Grandegger 49986917b7SYegor Yefremov static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg) 50986917b7SYegor Yefremov { 51986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 2); 52986917b7SYegor Yefremov } 53986917b7SYegor Yefremov 54986917b7SYegor Yefremov static void sp_write_reg16(const struct sja1000_priv *priv, int reg, u8 val) 55986917b7SYegor Yefremov { 56986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 2); 57986917b7SYegor Yefremov } 58986917b7SYegor Yefremov 59986917b7SYegor Yefremov static u8 sp_read_reg32(const struct sja1000_priv *priv, int reg) 60986917b7SYegor Yefremov { 61986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 4); 62986917b7SYegor Yefremov } 63986917b7SYegor Yefremov 64986917b7SYegor Yefremov static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) 65986917b7SYegor Yefremov { 66986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 4); 67986917b7SYegor Yefremov } 68986917b7SYegor Yefremov 69f534e52fSWolfgang Grandegger static int sp_probe(struct platform_device *pdev) 70f534e52fSWolfgang Grandegger { 71f534e52fSWolfgang Grandegger int err; 72f534e52fSWolfgang Grandegger void __iomem *addr; 73f534e52fSWolfgang Grandegger struct net_device *dev; 74f534e52fSWolfgang Grandegger struct sja1000_priv *priv; 75f534e52fSWolfgang Grandegger struct resource *res_mem, *res_irq; 76f534e52fSWolfgang Grandegger struct sja1000_platform_data *pdata; 77f534e52fSWolfgang Grandegger 78f534e52fSWolfgang Grandegger pdata = pdev->dev.platform_data; 79f534e52fSWolfgang Grandegger if (!pdata) { 80f534e52fSWolfgang Grandegger dev_err(&pdev->dev, "No platform data provided!\n"); 81f534e52fSWolfgang Grandegger err = -ENODEV; 82f534e52fSWolfgang Grandegger goto exit; 83f534e52fSWolfgang Grandegger } 84f534e52fSWolfgang Grandegger 85f534e52fSWolfgang Grandegger res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 86f534e52fSWolfgang Grandegger res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 87f534e52fSWolfgang Grandegger if (!res_mem || !res_irq) { 88f534e52fSWolfgang Grandegger err = -ENODEV; 89f534e52fSWolfgang Grandegger goto exit; 90f534e52fSWolfgang Grandegger } 91f534e52fSWolfgang Grandegger 92f534e52fSWolfgang Grandegger if (!request_mem_region(res_mem->start, resource_size(res_mem), 93f534e52fSWolfgang Grandegger DRV_NAME)) { 94f534e52fSWolfgang Grandegger err = -EBUSY; 95f534e52fSWolfgang Grandegger goto exit; 96f534e52fSWolfgang Grandegger } 97f534e52fSWolfgang Grandegger 98f534e52fSWolfgang Grandegger addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); 99f534e52fSWolfgang Grandegger if (!addr) { 100f534e52fSWolfgang Grandegger err = -ENOMEM; 101f534e52fSWolfgang Grandegger goto exit_release; 102f534e52fSWolfgang Grandegger } 103f534e52fSWolfgang Grandegger 104f534e52fSWolfgang Grandegger dev = alloc_sja1000dev(0); 105f534e52fSWolfgang Grandegger if (!dev) { 106f534e52fSWolfgang Grandegger err = -ENOMEM; 107f534e52fSWolfgang Grandegger goto exit_iounmap; 108f534e52fSWolfgang Grandegger } 109f534e52fSWolfgang Grandegger priv = netdev_priv(dev); 110f534e52fSWolfgang Grandegger 111f534e52fSWolfgang Grandegger dev->irq = res_irq->start; 112abde89d7SYegor Yefremov priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED); 113255a9154SWolfgang Grandegger priv->reg_base = addr; 11456e6943bSWolfgang Grandegger /* The CAN clock frequency is half the oscillator clock frequency */ 11556e6943bSWolfgang Grandegger priv->can.clock.freq = pdata->osc_freq / 2; 116f534e52fSWolfgang Grandegger priv->ocr = pdata->ocr; 117f534e52fSWolfgang Grandegger priv->cdr = pdata->cdr; 118f534e52fSWolfgang Grandegger 119986917b7SYegor Yefremov switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { 120986917b7SYegor Yefremov case IORESOURCE_MEM_32BIT: 121986917b7SYegor Yefremov priv->read_reg = sp_read_reg32; 122986917b7SYegor Yefremov priv->write_reg = sp_write_reg32; 123986917b7SYegor Yefremov break; 124986917b7SYegor Yefremov case IORESOURCE_MEM_16BIT: 125986917b7SYegor Yefremov priv->read_reg = sp_read_reg16; 126986917b7SYegor Yefremov priv->write_reg = sp_write_reg16; 127986917b7SYegor Yefremov break; 128986917b7SYegor Yefremov case IORESOURCE_MEM_8BIT: 129986917b7SYegor Yefremov default: 130986917b7SYegor Yefremov priv->read_reg = sp_read_reg8; 131986917b7SYegor Yefremov priv->write_reg = sp_write_reg8; 132986917b7SYegor Yefremov break; 133986917b7SYegor Yefremov } 134986917b7SYegor Yefremov 135f534e52fSWolfgang Grandegger dev_set_drvdata(&pdev->dev, dev); 136f534e52fSWolfgang Grandegger SET_NETDEV_DEV(dev, &pdev->dev); 137f534e52fSWolfgang Grandegger 138f534e52fSWolfgang Grandegger err = register_sja1000dev(dev); 139f534e52fSWolfgang Grandegger if (err) { 140f534e52fSWolfgang Grandegger dev_err(&pdev->dev, "registering %s failed (err=%d)\n", 141f534e52fSWolfgang Grandegger DRV_NAME, err); 142f534e52fSWolfgang Grandegger goto exit_free; 143f534e52fSWolfgang Grandegger } 144f534e52fSWolfgang Grandegger 145255a9154SWolfgang Grandegger dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", 146255a9154SWolfgang Grandegger DRV_NAME, priv->reg_base, dev->irq); 147f534e52fSWolfgang Grandegger return 0; 148f534e52fSWolfgang Grandegger 149f534e52fSWolfgang Grandegger exit_free: 150f534e52fSWolfgang Grandegger free_sja1000dev(dev); 151f534e52fSWolfgang Grandegger exit_iounmap: 152f534e52fSWolfgang Grandegger iounmap(addr); 153f534e52fSWolfgang Grandegger exit_release: 154f534e52fSWolfgang Grandegger release_mem_region(res_mem->start, resource_size(res_mem)); 155f534e52fSWolfgang Grandegger exit: 156f534e52fSWolfgang Grandegger return err; 157f534e52fSWolfgang Grandegger } 158f534e52fSWolfgang Grandegger 159f534e52fSWolfgang Grandegger static int sp_remove(struct platform_device *pdev) 160f534e52fSWolfgang Grandegger { 161f534e52fSWolfgang Grandegger struct net_device *dev = dev_get_drvdata(&pdev->dev); 162255a9154SWolfgang Grandegger struct sja1000_priv *priv = netdev_priv(dev); 163f534e52fSWolfgang Grandegger struct resource *res; 164f534e52fSWolfgang Grandegger 165f534e52fSWolfgang Grandegger unregister_sja1000dev(dev); 166f534e52fSWolfgang Grandegger dev_set_drvdata(&pdev->dev, NULL); 167f534e52fSWolfgang Grandegger 168255a9154SWolfgang Grandegger if (priv->reg_base) 169255a9154SWolfgang Grandegger iounmap(priv->reg_base); 170f534e52fSWolfgang Grandegger 171f534e52fSWolfgang Grandegger res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 172f534e52fSWolfgang Grandegger release_mem_region(res->start, resource_size(res)); 173f534e52fSWolfgang Grandegger 174f534e52fSWolfgang Grandegger free_sja1000dev(dev); 175f534e52fSWolfgang Grandegger 176f534e52fSWolfgang Grandegger return 0; 177f534e52fSWolfgang Grandegger } 178f534e52fSWolfgang Grandegger 179f534e52fSWolfgang Grandegger static struct platform_driver sp_driver = { 180f534e52fSWolfgang Grandegger .probe = sp_probe, 181f534e52fSWolfgang Grandegger .remove = sp_remove, 182f534e52fSWolfgang Grandegger .driver = { 183f534e52fSWolfgang Grandegger .name = DRV_NAME, 184f534e52fSWolfgang Grandegger .owner = THIS_MODULE, 185f534e52fSWolfgang Grandegger }, 186f534e52fSWolfgang Grandegger }; 187f534e52fSWolfgang Grandegger 188*871d3372SAxel Lin module_platform_driver(sp_driver); 189