1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Fintek F81601 PCIE to 2 CAN controller driver |
3 | * |
4 | * Copyright (C) 2019 Peter Hong <peter_hong@fintek.com.tw> |
5 | * Copyright (C) 2019 Linux Foundation |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/netdevice.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/pci.h> |
15 | #include <linux/can/dev.h> |
16 | #include <linux/io.h> |
17 | |
18 | #include "sja1000.h" |
19 | |
20 | #define F81601_PCI_MAX_CHAN 2 |
21 | |
22 | #define F81601_DECODE_REG 0x209 |
23 | #define F81601_IO_MODE BIT(7) |
24 | #define F81601_MEM_MODE BIT(6) |
25 | #define F81601_CFG_MODE BIT(5) |
26 | #define F81601_CAN2_INTERNAL_CLK BIT(3) |
27 | #define F81601_CAN1_INTERNAL_CLK BIT(2) |
28 | #define F81601_CAN2_EN BIT(1) |
29 | #define F81601_CAN1_EN BIT(0) |
30 | |
31 | #define F81601_TRAP_REG 0x20a |
32 | #define F81601_CAN2_HAS_EN BIT(4) |
33 | |
34 | struct f81601_pci_card { |
35 | void __iomem *addr; |
36 | spinlock_t lock; /* use this spin lock only for write access */ |
37 | struct pci_dev *dev; |
38 | struct net_device *net_dev[F81601_PCI_MAX_CHAN]; |
39 | }; |
40 | |
41 | static const struct pci_device_id f81601_pci_tbl[] = { |
42 | { PCI_DEVICE(0x1c29, 0x1703) }, |
43 | { /* sentinel */ }, |
44 | }; |
45 | |
46 | MODULE_DEVICE_TABLE(pci, f81601_pci_tbl); |
47 | |
48 | static bool internal_clk = true; |
49 | module_param(internal_clk, bool, 0444); |
50 | MODULE_PARM_DESC(internal_clk, "Use internal clock, default true (24MHz)" ); |
51 | |
52 | static unsigned int external_clk; |
53 | module_param(external_clk, uint, 0444); |
54 | MODULE_PARM_DESC(external_clk, "External clock when internal_clk disabled" ); |
55 | |
56 | static u8 f81601_pci_read_reg(const struct sja1000_priv *priv, int port) |
57 | { |
58 | return readb(addr: priv->reg_base + port); |
59 | } |
60 | |
61 | static void f81601_pci_write_reg(const struct sja1000_priv *priv, int port, |
62 | u8 val) |
63 | { |
64 | struct f81601_pci_card *card = priv->priv; |
65 | unsigned long flags; |
66 | |
67 | spin_lock_irqsave(&card->lock, flags); |
68 | writeb(val, addr: priv->reg_base + port); |
69 | readb(addr: priv->reg_base); |
70 | spin_unlock_irqrestore(lock: &card->lock, flags); |
71 | } |
72 | |
73 | static void f81601_pci_remove(struct pci_dev *pdev) |
74 | { |
75 | struct f81601_pci_card *card = pci_get_drvdata(pdev); |
76 | struct net_device *dev; |
77 | int i; |
78 | |
79 | for (i = 0; i < ARRAY_SIZE(card->net_dev); i++) { |
80 | dev = card->net_dev[i]; |
81 | if (!dev) |
82 | continue; |
83 | |
84 | dev_info(&pdev->dev, "%s: Removing %s\n" , __func__, dev->name); |
85 | |
86 | unregister_sja1000dev(dev); |
87 | free_sja1000dev(dev); |
88 | } |
89 | } |
90 | |
91 | /* Probe F81601 based device for the SJA1000 chips and register each |
92 | * available CAN channel to SJA1000 Socket-CAN subsystem. |
93 | */ |
94 | static int f81601_pci_probe(struct pci_dev *pdev, |
95 | const struct pci_device_id *ent) |
96 | { |
97 | struct sja1000_priv *priv; |
98 | struct net_device *dev; |
99 | struct f81601_pci_card *card; |
100 | int err, i, count; |
101 | u8 tmp; |
102 | |
103 | if (pcim_enable_device(pdev) < 0) { |
104 | dev_err(&pdev->dev, "Failed to enable PCI device\n" ); |
105 | return -ENODEV; |
106 | } |
107 | |
108 | dev_info(&pdev->dev, "Detected card at slot #%i\n" , |
109 | PCI_SLOT(pdev->devfn)); |
110 | |
111 | card = devm_kzalloc(dev: &pdev->dev, size: sizeof(*card), GFP_KERNEL); |
112 | if (!card) |
113 | return -ENOMEM; |
114 | |
115 | card->dev = pdev; |
116 | spin_lock_init(&card->lock); |
117 | |
118 | pci_set_drvdata(pdev, data: card); |
119 | |
120 | tmp = F81601_IO_MODE | F81601_MEM_MODE | F81601_CFG_MODE | |
121 | F81601_CAN2_EN | F81601_CAN1_EN; |
122 | |
123 | if (internal_clk) { |
124 | tmp |= F81601_CAN2_INTERNAL_CLK | F81601_CAN1_INTERNAL_CLK; |
125 | |
126 | dev_info(&pdev->dev, |
127 | "F81601 running with internal clock: 24Mhz\n" ); |
128 | } else { |
129 | dev_info(&pdev->dev, |
130 | "F81601 running with external clock: %dMhz\n" , |
131 | external_clk / 1000000); |
132 | } |
133 | |
134 | pci_write_config_byte(dev: pdev, F81601_DECODE_REG, val: tmp); |
135 | |
136 | card->addr = pcim_iomap(pdev, bar: 0, pci_resource_len(pdev, 0)); |
137 | |
138 | if (!card->addr) { |
139 | err = -ENOMEM; |
140 | dev_err(&pdev->dev, "%s: Failed to remap BAR\n" , __func__); |
141 | goto failure_cleanup; |
142 | } |
143 | |
144 | /* read CAN2_HW_EN strap pin to detect how many CANBUS do we have */ |
145 | count = ARRAY_SIZE(card->net_dev); |
146 | pci_read_config_byte(dev: pdev, F81601_TRAP_REG, val: &tmp); |
147 | if (!(tmp & F81601_CAN2_HAS_EN)) |
148 | count = 1; |
149 | |
150 | for (i = 0; i < count; i++) { |
151 | dev = alloc_sja1000dev(sizeof_priv: 0); |
152 | if (!dev) { |
153 | err = -ENOMEM; |
154 | goto failure_cleanup; |
155 | } |
156 | |
157 | priv = netdev_priv(dev); |
158 | priv->priv = card; |
159 | priv->irq_flags = IRQF_SHARED; |
160 | priv->reg_base = card->addr + 0x80 * i; |
161 | priv->read_reg = f81601_pci_read_reg; |
162 | priv->write_reg = f81601_pci_write_reg; |
163 | |
164 | if (internal_clk) |
165 | priv->can.clock.freq = 24000000 / 2; |
166 | else |
167 | priv->can.clock.freq = external_clk / 2; |
168 | |
169 | priv->ocr = OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL; |
170 | priv->cdr = CDR_CBP; |
171 | |
172 | SET_NETDEV_DEV(dev, &pdev->dev); |
173 | dev->dev_id = i; |
174 | dev->irq = pdev->irq; |
175 | |
176 | /* Register SJA1000 device */ |
177 | err = register_sja1000dev(dev); |
178 | if (err) { |
179 | dev_err(&pdev->dev, |
180 | "%s: Registering device failed: %x\n" , __func__, |
181 | err); |
182 | free_sja1000dev(dev); |
183 | goto failure_cleanup; |
184 | } |
185 | |
186 | card->net_dev[i] = dev; |
187 | dev_info(&pdev->dev, "Channel #%d, %s at 0x%p, irq %d\n" , i, |
188 | dev->name, priv->reg_base, dev->irq); |
189 | } |
190 | |
191 | return 0; |
192 | |
193 | failure_cleanup: |
194 | dev_err(&pdev->dev, "%s: failed: %d. Cleaning Up.\n" , __func__, err); |
195 | f81601_pci_remove(pdev); |
196 | |
197 | return err; |
198 | } |
199 | |
200 | static struct pci_driver f81601_pci_driver = { |
201 | .name = "f81601" , |
202 | .id_table = f81601_pci_tbl, |
203 | .probe = f81601_pci_probe, |
204 | .remove = f81601_pci_remove, |
205 | }; |
206 | |
207 | MODULE_DESCRIPTION("Fintek F81601 PCIE to 2 CANBUS adaptor driver" ); |
208 | MODULE_AUTHOR("Peter Hong <peter_hong@fintek.com.tw>" ); |
209 | MODULE_LICENSE("GPL v2" ); |
210 | |
211 | module_pci_driver(f81601_pci_driver); |
212 | |