brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 093bea5 Raw
296 lines · c
1/*2 * PCI bus driver for Bosch C_CAN/D_CAN controller3 *4 * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>5 *6 * Borrowed from c_can_platform.c7 *8 * This file is licensed under the terms of the GNU General Public9 * License version 2. This program is licensed "as is" without any10 * warranty of any kind, whether express or implied.11 */12 13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/netdevice.h>16#include <linux/pci.h>17 18#include <linux/can/dev.h>19 20#include "c_can.h"21 22#define PCI_DEVICE_ID_PCH_CAN	0x881823#define PCH_PCI_SOFT_RESET	0x01fc24 25enum c_can_pci_reg_align {26	C_CAN_REG_ALIGN_16,27	C_CAN_REG_ALIGN_32,28	C_CAN_REG_32,29};30 31struct c_can_pci_data {32	/* Specify if is C_CAN or D_CAN */33	enum c_can_dev_id type;34	/* Number of message objects */35	unsigned int msg_obj_num;36	/* Set the register alignment in the memory */37	enum c_can_pci_reg_align reg_align;38	/* Set the frequency */39	unsigned int freq;40	/* PCI bar number */41	int bar;42	/* Callback for reset */43	void (*init)(const struct c_can_priv *priv, bool enable);44};45 46/* 16-bit c_can registers can be arranged differently in the memory47 * architecture of different implementations. For example: 16-bit48 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.49 * Handle the same by providing a common read/write interface.50 */51static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv,52					       enum reg index)53{54	return readw(priv->base + priv->regs[index]);55}56 57static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv,58						 enum reg index, u16 val)59{60	writew(val, priv->base + priv->regs[index]);61}62 63static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv,64					       enum reg index)65{66	return readw(priv->base + 2 * priv->regs[index]);67}68 69static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv,70						 enum reg index, u16 val)71{72	writew(val, priv->base + 2 * priv->regs[index]);73}74 75static u16 c_can_pci_read_reg_32bit(const struct c_can_priv *priv,76				    enum reg index)77{78	return (u16)ioread32(priv->base + 2 * priv->regs[index]);79}80 81static void c_can_pci_write_reg_32bit(const struct c_can_priv *priv,82				      enum reg index, u16 val)83{84	iowrite32((u32)val, priv->base + 2 * priv->regs[index]);85}86 87static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)88{89	u32 val;90 91	val = priv->read_reg(priv, index);92	val |= ((u32)priv->read_reg(priv, index + 1)) << 16;93 94	return val;95}96 97static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index,98				  u32 val)99{100	priv->write_reg(priv, index + 1, val >> 16);101	priv->write_reg(priv, index, val);102}103 104static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable)105{106	if (enable) {107		u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET;108 109		/* write to sw reset register */110		iowrite32(1, addr);111		iowrite32(0, addr);112	}113}114 115static int c_can_pci_probe(struct pci_dev *pdev,116			   const struct pci_device_id *ent)117{118	struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;119	struct c_can_priv *priv;120	struct net_device *dev;121	void __iomem *addr;122	int ret;123 124	ret = pci_enable_device(pdev);125	if (ret) {126		dev_err(&pdev->dev, "pci_enable_device FAILED\n");127		goto out;128	}129 130	ret = pci_request_regions(pdev, KBUILD_MODNAME);131	if (ret) {132		dev_err(&pdev->dev, "pci_request_regions FAILED\n");133		goto out_disable_device;134	}135 136	ret = pci_enable_msi(pdev);137	if (!ret) {138		dev_info(&pdev->dev, "MSI enabled\n");139		pci_set_master(pdev);140	}141 142	addr = pci_iomap(pdev, c_can_pci_data->bar,143			 pci_resource_len(pdev, c_can_pci_data->bar));144	if (!addr) {145		dev_err(&pdev->dev,146			"device has no PCI memory resources, failing adapter\n");147		ret = -ENOMEM;148		goto out_release_regions;149	}150 151	/* allocate the c_can device */152	dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num);153	if (!dev) {154		ret = -ENOMEM;155		goto out_iounmap;156	}157 158	priv = netdev_priv(dev);159	pci_set_drvdata(pdev, dev);160	SET_NETDEV_DEV(dev, &pdev->dev);161 162	dev->irq = pdev->irq;163	priv->base = addr;164	priv->device = &pdev->dev;165 166	if (!c_can_pci_data->freq) {167		dev_err(&pdev->dev, "no clock frequency defined\n");168		ret = -ENODEV;169		goto out_free_c_can;170	} else {171		priv->can.clock.freq = c_can_pci_data->freq;172	}173 174	/* Configure CAN type */175	switch (c_can_pci_data->type) {176	case BOSCH_C_CAN:177		priv->regs = reg_map_c_can;178		break;179	case BOSCH_D_CAN:180		priv->regs = reg_map_d_can;181		break;182	default:183		ret = -EINVAL;184		goto out_free_c_can;185	}186 187	priv->type = c_can_pci_data->type;188 189	/* Configure access to registers */190	switch (c_can_pci_data->reg_align) {191	case C_CAN_REG_ALIGN_32:192		priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;193		priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;194		break;195	case C_CAN_REG_ALIGN_16:196		priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;197		priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;198		break;199	case C_CAN_REG_32:200		priv->read_reg = c_can_pci_read_reg_32bit;201		priv->write_reg = c_can_pci_write_reg_32bit;202		break;203	default:204		ret = -EINVAL;205		goto out_free_c_can;206	}207	priv->read_reg32 = c_can_pci_read_reg32;208	priv->write_reg32 = c_can_pci_write_reg32;209 210	priv->raminit = c_can_pci_data->init;211 212	ret = register_c_can_dev(dev);213	if (ret) {214		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",215			KBUILD_MODNAME, ret);216		goto out_free_c_can;217	}218 219	dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",220		KBUILD_MODNAME, priv->regs, dev->irq);221 222	return 0;223 224out_free_c_can:225	free_c_can_dev(dev);226out_iounmap:227	pci_iounmap(pdev, addr);228out_release_regions:229	pci_disable_msi(pdev);230	pci_release_regions(pdev);231out_disable_device:232	pci_disable_device(pdev);233out:234	return ret;235}236 237static void c_can_pci_remove(struct pci_dev *pdev)238{239	struct net_device *dev = pci_get_drvdata(pdev);240	struct c_can_priv *priv = netdev_priv(dev);241	void __iomem *addr = priv->base;242 243	unregister_c_can_dev(dev);244 245	free_c_can_dev(dev);246 247	pci_iounmap(pdev, addr);248	pci_disable_msi(pdev);249	pci_release_regions(pdev);250	pci_disable_device(pdev);251}252 253static const struct c_can_pci_data c_can_sta2x11 = {254	.type = BOSCH_C_CAN,255	.msg_obj_num = 32,256	.reg_align = C_CAN_REG_ALIGN_32,257	.freq = 52000000, /* 52 Mhz */258	.bar = 0,259};260 261static const struct c_can_pci_data c_can_pch = {262	.type = BOSCH_C_CAN,263	.msg_obj_num = 32,264	.reg_align = C_CAN_REG_32,265	.freq = 50000000, /* 50 MHz */266	.init = c_can_pci_reset_pch,267	.bar = 1,268};269 270#define C_CAN_ID(_vend, _dev, _driverdata) {		\271	PCI_DEVICE(_vend, _dev),			\272	.driver_data = (unsigned long)&(_driverdata),	\273}274 275static const struct pci_device_id c_can_pci_tbl[] = {276	C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,277		 c_can_sta2x11),278	C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN,279		 c_can_pch),280	{},281};282 283static struct pci_driver c_can_pci_driver = {284	.name = KBUILD_MODNAME,285	.id_table = c_can_pci_tbl,286	.probe = c_can_pci_probe,287	.remove = c_can_pci_remove,288};289 290module_pci_driver(c_can_pci_driver);291 292MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");293MODULE_LICENSE("GPL v2");294MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");295MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);296