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 225b92da04SFederico Vaga enum c_can_pci_reg_align { 235b92da04SFederico Vaga C_CAN_REG_ALIGN_16, 245b92da04SFederico Vaga C_CAN_REG_ALIGN_32, 255b92da04SFederico Vaga }; 265b92da04SFederico Vaga 275b92da04SFederico Vaga struct c_can_pci_data { 285b92da04SFederico Vaga /* Specify if is C_CAN or D_CAN */ 295b92da04SFederico Vaga enum c_can_dev_id type; 305b92da04SFederico Vaga /* Set the register alignment in the memory */ 315b92da04SFederico Vaga enum c_can_pci_reg_align reg_align; 321aa2d1daSMarc Kleine-Budde /* Set the frequency */ 335b92da04SFederico Vaga unsigned int freq; 345b92da04SFederico Vaga }; 355b92da04SFederico Vaga 365b92da04SFederico Vaga /* 375b92da04SFederico Vaga * 16-bit c_can registers can be arranged differently in the memory 385b92da04SFederico Vaga * architecture of different implementations. For example: 16-bit 395b92da04SFederico Vaga * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. 405b92da04SFederico Vaga * Handle the same by providing a common read/write interface. 415b92da04SFederico Vaga */ 425b92da04SFederico Vaga static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv, 435b92da04SFederico Vaga enum reg index) 445b92da04SFederico Vaga { 455b92da04SFederico Vaga return readw(priv->base + priv->regs[index]); 465b92da04SFederico Vaga } 475b92da04SFederico Vaga 485b92da04SFederico Vaga static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv, 495b92da04SFederico Vaga enum reg index, u16 val) 505b92da04SFederico Vaga { 515b92da04SFederico Vaga writew(val, priv->base + priv->regs[index]); 525b92da04SFederico Vaga } 535b92da04SFederico Vaga 545b92da04SFederico Vaga static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv, 555b92da04SFederico Vaga enum reg index) 565b92da04SFederico Vaga { 575b92da04SFederico Vaga return readw(priv->base + 2 * priv->regs[index]); 585b92da04SFederico Vaga } 595b92da04SFederico Vaga 605b92da04SFederico Vaga static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv, 615b92da04SFederico Vaga enum reg index, u16 val) 625b92da04SFederico Vaga { 635b92da04SFederico Vaga writew(val, priv->base + 2 * priv->regs[index]); 645b92da04SFederico Vaga } 655b92da04SFederico Vaga 665b92da04SFederico Vaga static int __devinit c_can_pci_probe(struct pci_dev *pdev, 675b92da04SFederico Vaga const struct pci_device_id *ent) 685b92da04SFederico Vaga { 695b92da04SFederico Vaga struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data; 705b92da04SFederico Vaga struct c_can_priv *priv; 715b92da04SFederico Vaga struct net_device *dev; 725b92da04SFederico Vaga void __iomem *addr; 735b92da04SFederico Vaga int ret; 745b92da04SFederico Vaga 755b92da04SFederico Vaga ret = pci_enable_device(pdev); 765b92da04SFederico Vaga if (ret) { 775b92da04SFederico Vaga dev_err(&pdev->dev, "pci_enable_device FAILED\n"); 785b92da04SFederico Vaga goto out; 795b92da04SFederico Vaga } 805b92da04SFederico Vaga 815b92da04SFederico Vaga ret = pci_request_regions(pdev, KBUILD_MODNAME); 825b92da04SFederico Vaga if (ret) { 835b92da04SFederico Vaga dev_err(&pdev->dev, "pci_request_regions FAILED\n"); 845b92da04SFederico Vaga goto out_disable_device; 855b92da04SFederico Vaga } 865b92da04SFederico Vaga 875b92da04SFederico Vaga pci_set_master(pdev); 885b92da04SFederico Vaga pci_enable_msi(pdev); 895b92da04SFederico Vaga 905b92da04SFederico Vaga addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); 915b92da04SFederico Vaga if (!addr) { 925b92da04SFederico Vaga dev_err(&pdev->dev, 935b92da04SFederico Vaga "device has no PCI memory resources, " 945b92da04SFederico Vaga "failing adapter\n"); 955b92da04SFederico Vaga ret = -ENOMEM; 965b92da04SFederico Vaga goto out_release_regions; 975b92da04SFederico Vaga } 985b92da04SFederico Vaga 995b92da04SFederico Vaga /* allocate the c_can device */ 1005b92da04SFederico Vaga dev = alloc_c_can_dev(); 1015b92da04SFederico Vaga if (!dev) { 1025b92da04SFederico Vaga ret = -ENOMEM; 1035b92da04SFederico Vaga goto out_iounmap; 1045b92da04SFederico Vaga } 1055b92da04SFederico Vaga 1065b92da04SFederico Vaga priv = netdev_priv(dev); 1075b92da04SFederico Vaga pci_set_drvdata(pdev, dev); 1085b92da04SFederico Vaga SET_NETDEV_DEV(dev, &pdev->dev); 1095b92da04SFederico Vaga 1105b92da04SFederico Vaga dev->irq = pdev->irq; 1115b92da04SFederico Vaga priv->base = addr; 1125b92da04SFederico Vaga 1135b92da04SFederico Vaga if (!c_can_pci_data->freq) { 1141aa2d1daSMarc Kleine-Budde dev_err(&pdev->dev, "no clock frequency defined\n"); 1155b92da04SFederico Vaga ret = -ENODEV; 1165b92da04SFederico Vaga goto out_free_c_can; 1175b92da04SFederico Vaga } else { 1185b92da04SFederico Vaga priv->can.clock.freq = c_can_pci_data->freq; 1195b92da04SFederico Vaga } 1205b92da04SFederico Vaga 1215b92da04SFederico Vaga /* Configure CAN type */ 1225b92da04SFederico Vaga switch (c_can_pci_data->type) { 123f27b1db9SAnilKumar Ch case BOSCH_C_CAN: 1245b92da04SFederico Vaga priv->regs = reg_map_c_can; 1255b92da04SFederico Vaga break; 126f27b1db9SAnilKumar Ch case BOSCH_D_CAN: 1275b92da04SFederico Vaga priv->regs = reg_map_d_can; 1285b92da04SFederico Vaga priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; 1295b92da04SFederico Vaga break; 1305b92da04SFederico Vaga default: 1315b92da04SFederico Vaga ret = -EINVAL; 1321aa2d1daSMarc Kleine-Budde goto out_free_c_can; 1335b92da04SFederico Vaga } 1345b92da04SFederico Vaga 1355b92da04SFederico Vaga /* Configure access to registers */ 1365b92da04SFederico Vaga switch (c_can_pci_data->reg_align) { 1375b92da04SFederico Vaga case C_CAN_REG_ALIGN_32: 1385b92da04SFederico Vaga priv->read_reg = c_can_pci_read_reg_aligned_to_32bit; 1395b92da04SFederico Vaga priv->write_reg = c_can_pci_write_reg_aligned_to_32bit; 1405b92da04SFederico Vaga break; 1415b92da04SFederico Vaga case C_CAN_REG_ALIGN_16: 1425b92da04SFederico Vaga priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; 1435b92da04SFederico Vaga priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; 1445b92da04SFederico Vaga break; 1455b92da04SFederico Vaga default: 1465b92da04SFederico Vaga ret = -EINVAL; 1471aa2d1daSMarc Kleine-Budde goto out_free_c_can; 1485b92da04SFederico Vaga } 1495b92da04SFederico Vaga 1505b92da04SFederico Vaga ret = register_c_can_dev(dev); 1515b92da04SFederico Vaga if (ret) { 1525b92da04SFederico Vaga dev_err(&pdev->dev, "registering %s failed (err=%d)\n", 1535b92da04SFederico Vaga KBUILD_MODNAME, ret); 1541aa2d1daSMarc Kleine-Budde goto out_free_c_can; 1555b92da04SFederico Vaga } 1565b92da04SFederico Vaga 1575b92da04SFederico Vaga dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n", 1585b92da04SFederico Vaga KBUILD_MODNAME, priv->regs, dev->irq); 1595b92da04SFederico Vaga 1605b92da04SFederico Vaga return 0; 1615b92da04SFederico Vaga 1625b92da04SFederico Vaga out_free_c_can: 1635b92da04SFederico Vaga pci_set_drvdata(pdev, NULL); 1645b92da04SFederico Vaga free_c_can_dev(dev); 1655b92da04SFederico Vaga out_iounmap: 1665b92da04SFederico Vaga pci_iounmap(pdev, addr); 1675b92da04SFederico Vaga out_release_regions: 1685b92da04SFederico Vaga pci_disable_msi(pdev); 1695b92da04SFederico Vaga pci_clear_master(pdev); 1705b92da04SFederico Vaga pci_release_regions(pdev); 1715b92da04SFederico Vaga out_disable_device: 1725b92da04SFederico Vaga pci_disable_device(pdev); 1735b92da04SFederico Vaga out: 1745b92da04SFederico Vaga return ret; 1755b92da04SFederico Vaga } 1765b92da04SFederico Vaga 1775b92da04SFederico Vaga static void __devexit c_can_pci_remove(struct pci_dev *pdev) 1785b92da04SFederico Vaga { 1795b92da04SFederico Vaga struct net_device *dev = pci_get_drvdata(pdev); 1805b92da04SFederico Vaga struct c_can_priv *priv = netdev_priv(dev); 1815b92da04SFederico Vaga 1825b92da04SFederico Vaga unregister_c_can_dev(dev); 1835b92da04SFederico Vaga 1845b92da04SFederico Vaga pci_set_drvdata(pdev, NULL); 1855b92da04SFederico Vaga free_c_can_dev(dev); 1865b92da04SFederico Vaga 1875b92da04SFederico Vaga pci_iounmap(pdev, priv->base); 1885b92da04SFederico Vaga pci_disable_msi(pdev); 1895b92da04SFederico Vaga pci_clear_master(pdev); 1905b92da04SFederico Vaga pci_release_regions(pdev); 1915b92da04SFederico Vaga pci_disable_device(pdev); 1925b92da04SFederico Vaga } 1935b92da04SFederico Vaga 1945b92da04SFederico Vaga static struct c_can_pci_data c_can_sta2x11= { 195f27b1db9SAnilKumar Ch .type = BOSCH_C_CAN, 1965b92da04SFederico Vaga .reg_align = C_CAN_REG_ALIGN_32, 1975b92da04SFederico Vaga .freq = 52000000, /* 52 Mhz */ 1985b92da04SFederico Vaga }; 1995b92da04SFederico Vaga 2005b92da04SFederico Vaga #define C_CAN_ID(_vend, _dev, _driverdata) { \ 2015b92da04SFederico Vaga PCI_DEVICE(_vend, _dev), \ 2025b92da04SFederico Vaga .driver_data = (unsigned long)&_driverdata, \ 2035b92da04SFederico Vaga } 2045b92da04SFederico Vaga static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { 2055b92da04SFederico Vaga C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, 2065b92da04SFederico Vaga c_can_sta2x11), 2075b92da04SFederico Vaga {}, 2085b92da04SFederico Vaga }; 2095b92da04SFederico Vaga static struct pci_driver c_can_pci_driver = { 2105b92da04SFederico Vaga .name = KBUILD_MODNAME, 2115b92da04SFederico Vaga .id_table = c_can_pci_tbl, 2125b92da04SFederico Vaga .probe = c_can_pci_probe, 2135b92da04SFederico Vaga .remove = __devexit_p(c_can_pci_remove), 2145b92da04SFederico Vaga }; 2155b92da04SFederico Vaga 2165b92da04SFederico Vaga module_pci_driver(c_can_pci_driver); 2175b92da04SFederico Vaga 2185b92da04SFederico Vaga MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>"); 2195b92da04SFederico Vaga MODULE_LICENSE("GPL v2"); 2205b92da04SFederico Vaga MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller"); 2215b92da04SFederico Vaga MODULE_DEVICE_TABLE(pci, c_can_pci_tbl); 222