15b92da04SFederico Vaga /* 25b92da04SFederico Vaga * PCI bus driver for Bosch C_CAN/D_CAN controller 35b92da04SFederico Vaga * 45b92da04SFederico Vaga * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com> 55b92da04SFederico Vaga * 65b92da04SFederico Vaga * Borrowed from c_can_platform.c 75b92da04SFederico Vaga * 85b92da04SFederico Vaga * This file is licensed under the terms of the GNU General Public 95b92da04SFederico Vaga * License version 2. This program is licensed "as is" without any 105b92da04SFederico Vaga * warranty of any kind, whether express or implied. 115b92da04SFederico Vaga */ 125b92da04SFederico Vaga 135b92da04SFederico Vaga #include <linux/kernel.h> 145b92da04SFederico Vaga #include <linux/module.h> 155b92da04SFederico Vaga #include <linux/netdevice.h> 165b92da04SFederico Vaga #include <linux/pci.h> 175b92da04SFederico Vaga 185b92da04SFederico Vaga #include <linux/can/dev.h> 195b92da04SFederico Vaga 205b92da04SFederico Vaga #include "c_can.h" 215b92da04SFederico Vaga 22abcd7f75SAlexander Stein #define PCI_DEVICE_ID_PCH_CAN 0x8818 23abcd7f75SAlexander Stein #define PCH_PCI_SOFT_RESET 0x01fc 24abcd7f75SAlexander Stein 255b92da04SFederico Vaga enum c_can_pci_reg_align { 265b92da04SFederico Vaga C_CAN_REG_ALIGN_16, 275b92da04SFederico Vaga C_CAN_REG_ALIGN_32, 28abcd7f75SAlexander Stein C_CAN_REG_32, 295b92da04SFederico Vaga }; 305b92da04SFederico Vaga 315b92da04SFederico Vaga struct c_can_pci_data { 325b92da04SFederico Vaga /* Specify if is C_CAN or D_CAN */ 335b92da04SFederico Vaga enum c_can_dev_id type; 34*132f2d45SDario Binacchi /* Number of message objects */ 35*132f2d45SDario Binacchi unsigned int msg_obj_num; 365b92da04SFederico Vaga /* Set the register alignment in the memory */ 375b92da04SFederico Vaga enum c_can_pci_reg_align reg_align; 381aa2d1daSMarc Kleine-Budde /* Set the frequency */ 395b92da04SFederico Vaga unsigned int freq; 40abcd7f75SAlexander Stein /* PCI bar number */ 41abcd7f75SAlexander Stein int bar; 42abcd7f75SAlexander Stein /* Callback for reset */ 43abcd7f75SAlexander Stein void (*init)(const struct c_can_priv *priv, bool enable); 445b92da04SFederico Vaga }; 455b92da04SFederico Vaga 46172f6d3aSMarc Kleine-Budde /* 16-bit c_can registers can be arranged differently in the memory 475b92da04SFederico Vaga * architecture of different implementations. For example: 16-bit 485b92da04SFederico Vaga * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. 495b92da04SFederico Vaga * Handle the same by providing a common read/write interface. 505b92da04SFederico Vaga */ 51e07e83aeSPavel Machek static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv, 525b92da04SFederico Vaga enum reg index) 535b92da04SFederico Vaga { 545b92da04SFederico Vaga return readw(priv->base + priv->regs[index]); 555b92da04SFederico Vaga } 565b92da04SFederico Vaga 57e07e83aeSPavel Machek static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv, 585b92da04SFederico Vaga enum reg index, u16 val) 595b92da04SFederico Vaga { 605b92da04SFederico Vaga writew(val, priv->base + priv->regs[index]); 615b92da04SFederico Vaga } 625b92da04SFederico Vaga 63e07e83aeSPavel Machek static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv, 645b92da04SFederico Vaga enum reg index) 655b92da04SFederico Vaga { 665b92da04SFederico Vaga return readw(priv->base + 2 * priv->regs[index]); 675b92da04SFederico Vaga } 685b92da04SFederico Vaga 69e07e83aeSPavel Machek static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv, 705b92da04SFederico Vaga enum reg index, u16 val) 715b92da04SFederico Vaga { 725b92da04SFederico Vaga writew(val, priv->base + 2 * priv->regs[index]); 735b92da04SFederico Vaga } 745b92da04SFederico Vaga 75e07e83aeSPavel Machek static u16 c_can_pci_read_reg_32bit(const struct c_can_priv *priv, 76abcd7f75SAlexander Stein enum reg index) 77abcd7f75SAlexander Stein { 78abcd7f75SAlexander Stein return (u16)ioread32(priv->base + 2 * priv->regs[index]); 79abcd7f75SAlexander Stein } 80abcd7f75SAlexander Stein 81e07e83aeSPavel Machek static void c_can_pci_write_reg_32bit(const struct c_can_priv *priv, 82abcd7f75SAlexander Stein enum reg index, u16 val) 83abcd7f75SAlexander Stein { 84abcd7f75SAlexander Stein iowrite32((u32)val, priv->base + 2 * priv->regs[index]); 85abcd7f75SAlexander Stein } 86abcd7f75SAlexander Stein 87ccbc5357SPavel Machek static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index) 88ccbc5357SPavel Machek { 89ccbc5357SPavel Machek u32 val; 90ccbc5357SPavel Machek 91ccbc5357SPavel Machek val = priv->read_reg(priv, index); 92ccbc5357SPavel Machek val |= ((u32)priv->read_reg(priv, index + 1)) << 16; 93ccbc5357SPavel Machek 94ccbc5357SPavel Machek return val; 95ccbc5357SPavel Machek } 96ccbc5357SPavel Machek 97ccbc5357SPavel Machek static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index, 98ccbc5357SPavel Machek u32 val) 99ccbc5357SPavel Machek { 100ccbc5357SPavel Machek priv->write_reg(priv, index + 1, val >> 16); 101ccbc5357SPavel Machek priv->write_reg(priv, index, val); 102ccbc5357SPavel Machek } 103ccbc5357SPavel Machek 104abcd7f75SAlexander Stein static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable) 105abcd7f75SAlexander Stein { 106abcd7f75SAlexander Stein if (enable) { 107abcd7f75SAlexander Stein u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET; 108abcd7f75SAlexander Stein 109abcd7f75SAlexander Stein /* write to sw reset register */ 110abcd7f75SAlexander Stein iowrite32(1, addr); 111abcd7f75SAlexander Stein iowrite32(0, addr); 112abcd7f75SAlexander Stein } 113abcd7f75SAlexander Stein } 114abcd7f75SAlexander Stein 1153c8ac0f2SBill Pemberton static int c_can_pci_probe(struct pci_dev *pdev, 1165b92da04SFederico Vaga const struct pci_device_id *ent) 1175b92da04SFederico Vaga { 1185b92da04SFederico Vaga struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data; 1195b92da04SFederico Vaga struct c_can_priv *priv; 1205b92da04SFederico Vaga struct net_device *dev; 1215b92da04SFederico Vaga void __iomem *addr; 1225b92da04SFederico Vaga int ret; 1235b92da04SFederico Vaga 1245b92da04SFederico Vaga ret = pci_enable_device(pdev); 1255b92da04SFederico Vaga if (ret) { 1265b92da04SFederico Vaga dev_err(&pdev->dev, "pci_enable_device FAILED\n"); 1275b92da04SFederico Vaga goto out; 1285b92da04SFederico Vaga } 1295b92da04SFederico Vaga 1305b92da04SFederico Vaga ret = pci_request_regions(pdev, KBUILD_MODNAME); 1315b92da04SFederico Vaga if (ret) { 1325b92da04SFederico Vaga dev_err(&pdev->dev, "pci_request_regions FAILED\n"); 1335b92da04SFederico Vaga goto out_disable_device; 1345b92da04SFederico Vaga } 1355b92da04SFederico Vaga 13678c181bcSWolfgang Grandegger ret = pci_enable_msi(pdev); 13778c181bcSWolfgang Grandegger if (!ret) { 13878c181bcSWolfgang Grandegger dev_info(&pdev->dev, "MSI enabled\n"); 1395b92da04SFederico Vaga pci_set_master(pdev); 14078c181bcSWolfgang Grandegger } 1415b92da04SFederico Vaga 142abcd7f75SAlexander Stein addr = pci_iomap(pdev, c_can_pci_data->bar, 143abcd7f75SAlexander Stein pci_resource_len(pdev, c_can_pci_data->bar)); 1445b92da04SFederico Vaga if (!addr) { 1455b92da04SFederico Vaga dev_err(&pdev->dev, 1460c1b0138SMarc Kleine-Budde "device has no PCI memory resources, failing adapter\n"); 1475b92da04SFederico Vaga ret = -ENOMEM; 1485b92da04SFederico Vaga goto out_release_regions; 1495b92da04SFederico Vaga } 1505b92da04SFederico Vaga 1515b92da04SFederico Vaga /* allocate the c_can device */ 152*132f2d45SDario Binacchi dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num); 1535b92da04SFederico Vaga if (!dev) { 1545b92da04SFederico Vaga ret = -ENOMEM; 1555b92da04SFederico Vaga goto out_iounmap; 1565b92da04SFederico Vaga } 1575b92da04SFederico Vaga 1585b92da04SFederico Vaga priv = netdev_priv(dev); 1595b92da04SFederico Vaga pci_set_drvdata(pdev, dev); 1605b92da04SFederico Vaga SET_NETDEV_DEV(dev, &pdev->dev); 1615b92da04SFederico Vaga 1625b92da04SFederico Vaga dev->irq = pdev->irq; 1635b92da04SFederico Vaga priv->base = addr; 164c97c52beSEinar Jón priv->device = &pdev->dev; 1655b92da04SFederico Vaga 1665b92da04SFederico Vaga if (!c_can_pci_data->freq) { 1671aa2d1daSMarc Kleine-Budde dev_err(&pdev->dev, "no clock frequency defined\n"); 1685b92da04SFederico Vaga ret = -ENODEV; 1695b92da04SFederico Vaga goto out_free_c_can; 1705b92da04SFederico Vaga } else { 1715b92da04SFederico Vaga priv->can.clock.freq = c_can_pci_data->freq; 1725b92da04SFederico Vaga } 1735b92da04SFederico Vaga 1745b92da04SFederico Vaga /* Configure CAN type */ 1755b92da04SFederico Vaga switch (c_can_pci_data->type) { 176f27b1db9SAnilKumar Ch case BOSCH_C_CAN: 1775b92da04SFederico Vaga priv->regs = reg_map_c_can; 1785b92da04SFederico Vaga break; 179f27b1db9SAnilKumar Ch case BOSCH_D_CAN: 1805b92da04SFederico Vaga priv->regs = reg_map_d_can; 1815b92da04SFederico Vaga break; 1825b92da04SFederico Vaga default: 1835b92da04SFederico Vaga ret = -EINVAL; 1841aa2d1daSMarc Kleine-Budde goto out_free_c_can; 1855b92da04SFederico Vaga } 1865b92da04SFederico Vaga 187129eef21SThomas Gleixner priv->type = c_can_pci_data->type; 188129eef21SThomas Gleixner 1895b92da04SFederico Vaga /* Configure access to registers */ 1905b92da04SFederico Vaga switch (c_can_pci_data->reg_align) { 1915b92da04SFederico Vaga case C_CAN_REG_ALIGN_32: 1925b92da04SFederico Vaga priv->read_reg = c_can_pci_read_reg_aligned_to_32bit; 1935b92da04SFederico Vaga priv->write_reg = c_can_pci_write_reg_aligned_to_32bit; 1945b92da04SFederico Vaga break; 1955b92da04SFederico Vaga case C_CAN_REG_ALIGN_16: 1965b92da04SFederico Vaga priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; 1975b92da04SFederico Vaga priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; 1985b92da04SFederico Vaga break; 199abcd7f75SAlexander Stein case C_CAN_REG_32: 200abcd7f75SAlexander Stein priv->read_reg = c_can_pci_read_reg_32bit; 201abcd7f75SAlexander Stein priv->write_reg = c_can_pci_write_reg_32bit; 202abcd7f75SAlexander Stein break; 2035b92da04SFederico Vaga default: 2045b92da04SFederico Vaga ret = -EINVAL; 2051aa2d1daSMarc Kleine-Budde goto out_free_c_can; 2065b92da04SFederico Vaga } 207ccbc5357SPavel Machek priv->read_reg32 = c_can_pci_read_reg32; 208ccbc5357SPavel Machek priv->write_reg32 = c_can_pci_write_reg32; 2095b92da04SFederico Vaga 210abcd7f75SAlexander Stein priv->raminit = c_can_pci_data->init; 211abcd7f75SAlexander Stein 2125b92da04SFederico Vaga ret = register_c_can_dev(dev); 2135b92da04SFederico Vaga if (ret) { 2145b92da04SFederico Vaga dev_err(&pdev->dev, "registering %s failed (err=%d)\n", 2155b92da04SFederico Vaga KBUILD_MODNAME, ret); 2161aa2d1daSMarc Kleine-Budde goto out_free_c_can; 2175b92da04SFederico Vaga } 2185b92da04SFederico Vaga 2195b92da04SFederico Vaga dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n", 2205b92da04SFederico Vaga KBUILD_MODNAME, priv->regs, dev->irq); 2215b92da04SFederico Vaga 2225b92da04SFederico Vaga return 0; 2235b92da04SFederico Vaga 2245b92da04SFederico Vaga out_free_c_can: 2255b92da04SFederico Vaga free_c_can_dev(dev); 2265b92da04SFederico Vaga out_iounmap: 2275b92da04SFederico Vaga pci_iounmap(pdev, addr); 2285b92da04SFederico Vaga out_release_regions: 2295b92da04SFederico Vaga pci_disable_msi(pdev); 2305b92da04SFederico Vaga pci_clear_master(pdev); 2315b92da04SFederico Vaga pci_release_regions(pdev); 2325b92da04SFederico Vaga out_disable_device: 2335b92da04SFederico Vaga pci_disable_device(pdev); 2345b92da04SFederico Vaga out: 2355b92da04SFederico Vaga return ret; 2365b92da04SFederico Vaga } 2375b92da04SFederico Vaga 2383c8ac0f2SBill Pemberton static void c_can_pci_remove(struct pci_dev *pdev) 2395b92da04SFederico Vaga { 2405b92da04SFederico Vaga struct net_device *dev = pci_get_drvdata(pdev); 2415b92da04SFederico Vaga struct c_can_priv *priv = netdev_priv(dev); 2420429d6d8STong Zhang void __iomem *addr = priv->base; 2435b92da04SFederico Vaga 2445b92da04SFederico Vaga unregister_c_can_dev(dev); 2455b92da04SFederico Vaga 2465b92da04SFederico Vaga free_c_can_dev(dev); 2475b92da04SFederico Vaga 2480429d6d8STong Zhang pci_iounmap(pdev, addr); 2495b92da04SFederico Vaga pci_disable_msi(pdev); 2505b92da04SFederico Vaga pci_clear_master(pdev); 2515b92da04SFederico Vaga pci_release_regions(pdev); 2525b92da04SFederico Vaga pci_disable_device(pdev); 2535b92da04SFederico Vaga } 2545b92da04SFederico Vaga 255a4efd5d8SBhumika Goyal static const struct c_can_pci_data c_can_sta2x11 = { 256f27b1db9SAnilKumar Ch .type = BOSCH_C_CAN, 257*132f2d45SDario Binacchi .msg_obj_num = 32, 2585b92da04SFederico Vaga .reg_align = C_CAN_REG_ALIGN_32, 2595b92da04SFederico Vaga .freq = 52000000, /* 52 Mhz */ 260abcd7f75SAlexander Stein .bar = 0, 261abcd7f75SAlexander Stein }; 262abcd7f75SAlexander Stein 263a4efd5d8SBhumika Goyal static const struct c_can_pci_data c_can_pch = { 264abcd7f75SAlexander Stein .type = BOSCH_C_CAN, 265*132f2d45SDario Binacchi .msg_obj_num = 32, 266abcd7f75SAlexander Stein .reg_align = C_CAN_REG_32, 267abcd7f75SAlexander Stein .freq = 50000000, /* 50 MHz */ 268abcd7f75SAlexander Stein .init = c_can_pci_reset_pch, 269abcd7f75SAlexander Stein .bar = 1, 2705b92da04SFederico Vaga }; 2715b92da04SFederico Vaga 2725b92da04SFederico Vaga #define C_CAN_ID(_vend, _dev, _driverdata) { \ 2735b92da04SFederico Vaga PCI_DEVICE(_vend, _dev), \ 274dd477500SMarc Kleine-Budde .driver_data = (unsigned long)&(_driverdata), \ 2755b92da04SFederico Vaga } 2769baa3c34SBenoit Taine 2779baa3c34SBenoit Taine static const struct pci_device_id c_can_pci_tbl[] = { 2785b92da04SFederico Vaga C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, 2795b92da04SFederico Vaga c_can_sta2x11), 280abcd7f75SAlexander Stein C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN, 281abcd7f75SAlexander Stein c_can_pch), 2825b92da04SFederico Vaga {}, 2835b92da04SFederico Vaga }; 284beb7e88aSMarc Kleine-Budde 2855b92da04SFederico Vaga static struct pci_driver c_can_pci_driver = { 2865b92da04SFederico Vaga .name = KBUILD_MODNAME, 2875b92da04SFederico Vaga .id_table = c_can_pci_tbl, 2885b92da04SFederico Vaga .probe = c_can_pci_probe, 2893c8ac0f2SBill Pemberton .remove = c_can_pci_remove, 2905b92da04SFederico Vaga }; 2915b92da04SFederico Vaga 2925b92da04SFederico Vaga module_pci_driver(c_can_pci_driver); 2935b92da04SFederico Vaga 2945b92da04SFederico Vaga MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>"); 2955b92da04SFederico Vaga MODULE_LICENSE("GPL v2"); 2965b92da04SFederico Vaga MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller"); 2975b92da04SFederico Vaga MODULE_DEVICE_TABLE(pci, c_can_pci_tbl); 298