135e62ae8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f534e52fSWolfgang Grandegger /*
3f534e52fSWolfgang Grandegger * Copyright (C) 2005 Sascha Hauer, Pengutronix
4f534e52fSWolfgang Grandegger * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
5f534e52fSWolfgang Grandegger */
6f534e52fSWolfgang Grandegger
7f534e52fSWolfgang Grandegger #include <linux/kernel.h>
8f534e52fSWolfgang Grandegger #include <linux/module.h>
9f534e52fSWolfgang Grandegger #include <linux/interrupt.h>
10f534e52fSWolfgang Grandegger #include <linux/netdevice.h>
11f534e52fSWolfgang Grandegger #include <linux/delay.h>
12f534e52fSWolfgang Grandegger #include <linux/pci.h>
13f534e52fSWolfgang Grandegger #include <linux/platform_device.h>
14f534e52fSWolfgang Grandegger #include <linux/irq.h>
15f534e52fSWolfgang Grandegger #include <linux/can/dev.h>
16f534e52fSWolfgang Grandegger #include <linux/can/platform/sja1000.h>
170838921bSBiju Das #include <linux/clk.h>
18f534e52fSWolfgang Grandegger #include <linux/io.h>
1902729c3dSFlorian Vaussard #include <linux/of.h>
20f534e52fSWolfgang Grandegger
21f534e52fSWolfgang Grandegger #include "sja1000.h"
22f534e52fSWolfgang Grandegger
23f534e52fSWolfgang Grandegger #define DRV_NAME "sja1000_platform"
2402729c3dSFlorian Vaussard #define SP_CAN_CLOCK (16000000 / 2)
25f534e52fSWolfgang Grandegger
26f534e52fSWolfgang Grandegger MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
2702729c3dSFlorian Vaussard MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
28f534e52fSWolfgang Grandegger MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
29d8c4386dSMarc Kleine-Budde MODULE_ALIAS("platform:" DRV_NAME);
30f534e52fSWolfgang Grandegger MODULE_LICENSE("GPL v2");
31f534e52fSWolfgang Grandegger
32f49cbe6bSDamien Riegel struct sja1000_of_data {
33f49cbe6bSDamien Riegel size_t priv_sz;
346d5fe107SBiju Das void (*init)(struct sja1000_priv *priv, struct device_node *of);
35f49cbe6bSDamien Riegel };
36f49cbe6bSDamien Riegel
37dfb86c0dSDamien Riegel struct technologic_priv {
38dfb86c0dSDamien Riegel spinlock_t io_lock;
39dfb86c0dSDamien Riegel };
40dfb86c0dSDamien Riegel
sp_read_reg8(const struct sja1000_priv * priv,int reg)41986917b7SYegor Yefremov static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
42f534e52fSWolfgang Grandegger {
43255a9154SWolfgang Grandegger return ioread8(priv->reg_base + reg);
44f534e52fSWolfgang Grandegger }
45f534e52fSWolfgang Grandegger
sp_write_reg8(const struct sja1000_priv * priv,int reg,u8 val)46986917b7SYegor Yefremov static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
47f534e52fSWolfgang Grandegger {
48255a9154SWolfgang Grandegger iowrite8(val, priv->reg_base + reg);
49f534e52fSWolfgang Grandegger }
50f534e52fSWolfgang Grandegger
sp_read_reg16(const struct sja1000_priv * priv,int reg)51986917b7SYegor Yefremov static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg)
52986917b7SYegor Yefremov {
53986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 2);
54986917b7SYegor Yefremov }
55986917b7SYegor Yefremov
sp_write_reg16(const struct sja1000_priv * priv,int reg,u8 val)56986917b7SYegor Yefremov static void sp_write_reg16(const struct sja1000_priv *priv, int reg, u8 val)
57986917b7SYegor Yefremov {
58986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 2);
59986917b7SYegor Yefremov }
60986917b7SYegor Yefremov
sp_read_reg32(const struct sja1000_priv * priv,int reg)61986917b7SYegor Yefremov static u8 sp_read_reg32(const struct sja1000_priv *priv, int reg)
62986917b7SYegor Yefremov {
63986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 4);
64986917b7SYegor Yefremov }
65986917b7SYegor Yefremov
sp_write_reg32(const struct sja1000_priv * priv,int reg,u8 val)66986917b7SYegor Yefremov static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
67986917b7SYegor Yefremov {
68986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 4);
69986917b7SYegor Yefremov }
70986917b7SYegor Yefremov
sp_technologic_read_reg16(const struct sja1000_priv * priv,int reg)71dfb86c0dSDamien Riegel static u8 sp_technologic_read_reg16(const struct sja1000_priv *priv, int reg)
72dfb86c0dSDamien Riegel {
73dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv;
74dfb86c0dSDamien Riegel unsigned long flags;
75dfb86c0dSDamien Riegel u8 val;
76dfb86c0dSDamien Riegel
77dfb86c0dSDamien Riegel spin_lock_irqsave(&tp->io_lock, flags);
78dfb86c0dSDamien Riegel iowrite16(reg, priv->reg_base + 0);
79dfb86c0dSDamien Riegel val = ioread16(priv->reg_base + 2);
80dfb86c0dSDamien Riegel spin_unlock_irqrestore(&tp->io_lock, flags);
81dfb86c0dSDamien Riegel
82dfb86c0dSDamien Riegel return val;
83dfb86c0dSDamien Riegel }
84dfb86c0dSDamien Riegel
sp_technologic_write_reg16(const struct sja1000_priv * priv,int reg,u8 val)85dfb86c0dSDamien Riegel static void sp_technologic_write_reg16(const struct sja1000_priv *priv,
86dfb86c0dSDamien Riegel int reg, u8 val)
87dfb86c0dSDamien Riegel {
88dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv;
89dfb86c0dSDamien Riegel unsigned long flags;
90dfb86c0dSDamien Riegel
91dfb86c0dSDamien Riegel spin_lock_irqsave(&tp->io_lock, flags);
92dfb86c0dSDamien Riegel iowrite16(reg, priv->reg_base + 0);
93dfb86c0dSDamien Riegel iowrite16(val, priv->reg_base + 2);
94dfb86c0dSDamien Riegel spin_unlock_irqrestore(&tp->io_lock, flags);
95dfb86c0dSDamien Riegel }
96dfb86c0dSDamien Riegel
sp_technologic_init(struct sja1000_priv * priv,struct device_node * of)976d5fe107SBiju Das static void sp_technologic_init(struct sja1000_priv *priv, struct device_node *of)
98dfb86c0dSDamien Riegel {
99dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv;
100dfb86c0dSDamien Riegel
101dfb86c0dSDamien Riegel priv->read_reg = sp_technologic_read_reg16;
102dfb86c0dSDamien Riegel priv->write_reg = sp_technologic_write_reg16;
103dfb86c0dSDamien Riegel spin_lock_init(&tp->io_lock);
104dfb86c0dSDamien Riegel }
105dfb86c0dSDamien Riegel
sp_rzn1_init(struct sja1000_priv * priv,struct device_node * of)1060838921bSBiju Das static void sp_rzn1_init(struct sja1000_priv *priv, struct device_node *of)
1070838921bSBiju Das {
108*717c6ec2SMiquel Raynal priv->flags = SJA1000_QUIRK_NO_CDR_REG | SJA1000_QUIRK_RESET_ON_OVERRUN;
1090838921bSBiju Das }
1100838921bSBiju Das
sp_populate(struct sja1000_priv * priv,struct sja1000_platform_data * pdata,unsigned long resource_mem_flags)11102729c3dSFlorian Vaussard static void sp_populate(struct sja1000_priv *priv,
11202729c3dSFlorian Vaussard struct sja1000_platform_data *pdata,
11302729c3dSFlorian Vaussard unsigned long resource_mem_flags)
114f534e52fSWolfgang Grandegger {
11556e6943bSWolfgang Grandegger /* The CAN clock frequency is half the oscillator clock frequency */
11656e6943bSWolfgang Grandegger priv->can.clock.freq = pdata->osc_freq / 2;
117f534e52fSWolfgang Grandegger priv->ocr = pdata->ocr;
118f534e52fSWolfgang Grandegger priv->cdr = pdata->cdr;
119f534e52fSWolfgang Grandegger
12002729c3dSFlorian Vaussard switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
121986917b7SYegor Yefremov case IORESOURCE_MEM_32BIT:
122986917b7SYegor Yefremov priv->read_reg = sp_read_reg32;
123986917b7SYegor Yefremov priv->write_reg = sp_write_reg32;
124986917b7SYegor Yefremov break;
125986917b7SYegor Yefremov case IORESOURCE_MEM_16BIT:
126986917b7SYegor Yefremov priv->read_reg = sp_read_reg16;
127986917b7SYegor Yefremov priv->write_reg = sp_write_reg16;
128986917b7SYegor Yefremov break;
129986917b7SYegor Yefremov case IORESOURCE_MEM_8BIT:
130986917b7SYegor Yefremov default:
131986917b7SYegor Yefremov priv->read_reg = sp_read_reg8;
132986917b7SYegor Yefremov priv->write_reg = sp_write_reg8;
133986917b7SYegor Yefremov break;
134986917b7SYegor Yefremov }
13502729c3dSFlorian Vaussard }
13602729c3dSFlorian Vaussard
sp_populate_of(struct sja1000_priv * priv,struct device_node * of)13702729c3dSFlorian Vaussard static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
13802729c3dSFlorian Vaussard {
13902729c3dSFlorian Vaussard int err;
14002729c3dSFlorian Vaussard u32 prop;
14102729c3dSFlorian Vaussard
142b18ec27cSFlorian Vaussard err = of_property_read_u32(of, "reg-io-width", &prop);
143b18ec27cSFlorian Vaussard if (err)
144b18ec27cSFlorian Vaussard prop = 1; /* 8 bit is default */
145b18ec27cSFlorian Vaussard
146b18ec27cSFlorian Vaussard switch (prop) {
147b18ec27cSFlorian Vaussard case 4:
148b18ec27cSFlorian Vaussard priv->read_reg = sp_read_reg32;
149b18ec27cSFlorian Vaussard priv->write_reg = sp_write_reg32;
150b18ec27cSFlorian Vaussard break;
151b18ec27cSFlorian Vaussard case 2:
152b18ec27cSFlorian Vaussard priv->read_reg = sp_read_reg16;
153b18ec27cSFlorian Vaussard priv->write_reg = sp_write_reg16;
154b18ec27cSFlorian Vaussard break;
155df561f66SGustavo A. R. Silva case 1:
156b18ec27cSFlorian Vaussard default:
15702729c3dSFlorian Vaussard priv->read_reg = sp_read_reg8;
15802729c3dSFlorian Vaussard priv->write_reg = sp_write_reg8;
159b18ec27cSFlorian Vaussard }
16002729c3dSFlorian Vaussard
1610838921bSBiju Das if (!priv->can.clock.freq) {
16202729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
16302729c3dSFlorian Vaussard if (!err)
16402729c3dSFlorian Vaussard priv->can.clock.freq = prop / 2;
16502729c3dSFlorian Vaussard else
16602729c3dSFlorian Vaussard priv->can.clock.freq = SP_CAN_CLOCK; /* default */
1670838921bSBiju Das }
16802729c3dSFlorian Vaussard
16902729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
17002729c3dSFlorian Vaussard if (!err)
17102729c3dSFlorian Vaussard priv->ocr |= prop & OCR_MODE_MASK;
17202729c3dSFlorian Vaussard else
17302729c3dSFlorian Vaussard priv->ocr |= OCR_MODE_NORMAL; /* default */
17402729c3dSFlorian Vaussard
17502729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
17602729c3dSFlorian Vaussard if (!err)
17702729c3dSFlorian Vaussard priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
17802729c3dSFlorian Vaussard else
17902729c3dSFlorian Vaussard priv->ocr |= OCR_TX0_PULLDOWN; /* default */
18002729c3dSFlorian Vaussard
18102729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
18202729c3dSFlorian Vaussard if (!err && prop) {
18302729c3dSFlorian Vaussard u32 divider = priv->can.clock.freq * 2 / prop;
18402729c3dSFlorian Vaussard
18502729c3dSFlorian Vaussard if (divider > 1)
18602729c3dSFlorian Vaussard priv->cdr |= divider / 2 - 1;
18702729c3dSFlorian Vaussard else
18802729c3dSFlorian Vaussard priv->cdr |= CDR_CLKOUT_MASK;
18902729c3dSFlorian Vaussard } else {
19002729c3dSFlorian Vaussard priv->cdr |= CDR_CLK_OFF; /* default */
19102729c3dSFlorian Vaussard }
19202729c3dSFlorian Vaussard
19302729c3dSFlorian Vaussard if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
19402729c3dSFlorian Vaussard priv->cdr |= CDR_CBP; /* default */
19502729c3dSFlorian Vaussard }
19602729c3dSFlorian Vaussard
197dfb86c0dSDamien Riegel static struct sja1000_of_data technologic_data = {
198dfb86c0dSDamien Riegel .priv_sz = sizeof(struct technologic_priv),
199dfb86c0dSDamien Riegel .init = sp_technologic_init,
200dfb86c0dSDamien Riegel };
201dfb86c0dSDamien Riegel
2020838921bSBiju Das static struct sja1000_of_data renesas_data = {
2030838921bSBiju Das .init = sp_rzn1_init,
2040838921bSBiju Das };
2050838921bSBiju Das
206f49cbe6bSDamien Riegel static const struct of_device_id sp_of_table[] = {
207f49cbe6bSDamien Riegel { .compatible = "nxp,sja1000", .data = NULL, },
2080838921bSBiju Das { .compatible = "renesas,rzn1-sja1000", .data = &renesas_data, },
209dfb86c0dSDamien Riegel { .compatible = "technologic,sja1000", .data = &technologic_data, },
210f49cbe6bSDamien Riegel { /* sentinel */ },
211f49cbe6bSDamien Riegel };
212f49cbe6bSDamien Riegel MODULE_DEVICE_TABLE(of, sp_of_table);
213f49cbe6bSDamien Riegel
sp_probe(struct platform_device * pdev)21402729c3dSFlorian Vaussard static int sp_probe(struct platform_device *pdev)
21502729c3dSFlorian Vaussard {
21602729c3dSFlorian Vaussard int err, irq = 0;
21702729c3dSFlorian Vaussard void __iomem *addr;
21802729c3dSFlorian Vaussard struct net_device *dev;
21902729c3dSFlorian Vaussard struct sja1000_priv *priv;
22002729c3dSFlorian Vaussard struct resource *res_mem, *res_irq = NULL;
22102729c3dSFlorian Vaussard struct sja1000_platform_data *pdata;
22202729c3dSFlorian Vaussard struct device_node *of = pdev->dev.of_node;
223f49cbe6bSDamien Riegel const struct sja1000_of_data *of_data = NULL;
224f49cbe6bSDamien Riegel size_t priv_sz = 0;
2250838921bSBiju Das struct clk *clk;
22602729c3dSFlorian Vaussard
22702729c3dSFlorian Vaussard pdata = dev_get_platdata(&pdev->dev);
22802729c3dSFlorian Vaussard if (!pdata && !of) {
22902729c3dSFlorian Vaussard dev_err(&pdev->dev, "No platform data provided!\n");
23002729c3dSFlorian Vaussard return -ENODEV;
23102729c3dSFlorian Vaussard }
23202729c3dSFlorian Vaussard
23302729c3dSFlorian Vaussard res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
23402729c3dSFlorian Vaussard if (!res_mem)
23502729c3dSFlorian Vaussard return -ENODEV;
23602729c3dSFlorian Vaussard
23702729c3dSFlorian Vaussard if (!devm_request_mem_region(&pdev->dev, res_mem->start,
23802729c3dSFlorian Vaussard resource_size(res_mem), DRV_NAME))
23902729c3dSFlorian Vaussard return -EBUSY;
24002729c3dSFlorian Vaussard
2414bdc0d67SChristoph Hellwig addr = devm_ioremap(&pdev->dev, res_mem->start,
24202729c3dSFlorian Vaussard resource_size(res_mem));
24302729c3dSFlorian Vaussard if (!addr)
24402729c3dSFlorian Vaussard return -ENOMEM;
24502729c3dSFlorian Vaussard
246decdcaeeSLad Prabhakar if (of) {
247decdcaeeSLad Prabhakar irq = platform_get_irq(pdev, 0);
248decdcaeeSLad Prabhakar if (irq < 0)
249decdcaeeSLad Prabhakar return irq;
2500838921bSBiju Das
2510838921bSBiju Das clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
2520838921bSBiju Das if (IS_ERR(clk))
2530838921bSBiju Das return dev_err_probe(&pdev->dev, PTR_ERR(clk),
2540838921bSBiju Das "CAN clk operation failed");
255decdcaeeSLad Prabhakar } else {
25602729c3dSFlorian Vaussard res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
257decdcaeeSLad Prabhakar if (!res_irq)
25802729c3dSFlorian Vaussard return -ENODEV;
259decdcaeeSLad Prabhakar }
26002729c3dSFlorian Vaussard
26163ab1b63SBiju Das of_data = device_get_match_data(&pdev->dev);
26263ab1b63SBiju Das if (of_data)
263f49cbe6bSDamien Riegel priv_sz = of_data->priv_sz;
264f49cbe6bSDamien Riegel
265f49cbe6bSDamien Riegel dev = alloc_sja1000dev(priv_sz);
26602729c3dSFlorian Vaussard if (!dev)
26702729c3dSFlorian Vaussard return -ENOMEM;
26802729c3dSFlorian Vaussard priv = netdev_priv(dev);
26902729c3dSFlorian Vaussard
27002729c3dSFlorian Vaussard if (res_irq) {
27102729c3dSFlorian Vaussard irq = res_irq->start;
27202729c3dSFlorian Vaussard priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
27302729c3dSFlorian Vaussard if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
27402729c3dSFlorian Vaussard priv->irq_flags |= IRQF_SHARED;
27502729c3dSFlorian Vaussard } else {
27602729c3dSFlorian Vaussard priv->irq_flags = IRQF_SHARED;
27702729c3dSFlorian Vaussard }
27802729c3dSFlorian Vaussard
279*717c6ec2SMiquel Raynal if (priv->flags & SJA1000_QUIRK_RESET_ON_OVERRUN)
280*717c6ec2SMiquel Raynal priv->irq_flags |= IRQF_ONESHOT;
281*717c6ec2SMiquel Raynal
28202729c3dSFlorian Vaussard dev->irq = irq;
28302729c3dSFlorian Vaussard priv->reg_base = addr;
28402729c3dSFlorian Vaussard
285f49cbe6bSDamien Riegel if (of) {
2860838921bSBiju Das if (clk) {
2870838921bSBiju Das priv->can.clock.freq = clk_get_rate(clk) / 2;
2880838921bSBiju Das if (!priv->can.clock.freq) {
2890838921bSBiju Das err = -EINVAL;
2900838921bSBiju Das dev_err(&pdev->dev, "Zero CAN clk rate");
2910838921bSBiju Das goto exit_free;
2920838921bSBiju Das }
2930838921bSBiju Das }
2940838921bSBiju Das
29502729c3dSFlorian Vaussard sp_populate_of(priv, of);
296f49cbe6bSDamien Riegel
2976d5fe107SBiju Das if (of_data && of_data->init)
2986d5fe107SBiju Das of_data->init(priv, of);
299f49cbe6bSDamien Riegel } else {
30002729c3dSFlorian Vaussard sp_populate(priv, pdata, res_mem->flags);
301f49cbe6bSDamien Riegel }
302986917b7SYegor Yefremov
30300e4bbc8SJingoo Han platform_set_drvdata(pdev, dev);
304f534e52fSWolfgang Grandegger SET_NETDEV_DEV(dev, &pdev->dev);
305f534e52fSWolfgang Grandegger
306f534e52fSWolfgang Grandegger err = register_sja1000dev(dev);
307f534e52fSWolfgang Grandegger if (err) {
308f534e52fSWolfgang Grandegger dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
309f534e52fSWolfgang Grandegger DRV_NAME, err);
310f534e52fSWolfgang Grandegger goto exit_free;
311f534e52fSWolfgang Grandegger }
312f534e52fSWolfgang Grandegger
313255a9154SWolfgang Grandegger dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
314255a9154SWolfgang Grandegger DRV_NAME, priv->reg_base, dev->irq);
315f534e52fSWolfgang Grandegger return 0;
316f534e52fSWolfgang Grandegger
317f534e52fSWolfgang Grandegger exit_free:
318f534e52fSWolfgang Grandegger free_sja1000dev(dev);
319f534e52fSWolfgang Grandegger return err;
320f534e52fSWolfgang Grandegger }
321f534e52fSWolfgang Grandegger
sp_remove(struct platform_device * pdev)322bc79adfbSUwe Kleine-König static void sp_remove(struct platform_device *pdev)
323f534e52fSWolfgang Grandegger {
32400e4bbc8SJingoo Han struct net_device *dev = platform_get_drvdata(pdev);
325f534e52fSWolfgang Grandegger
326f534e52fSWolfgang Grandegger unregister_sja1000dev(dev);
327f534e52fSWolfgang Grandegger free_sja1000dev(dev);
328f534e52fSWolfgang Grandegger }
329f534e52fSWolfgang Grandegger
330f534e52fSWolfgang Grandegger static struct platform_driver sp_driver = {
331f534e52fSWolfgang Grandegger .probe = sp_probe,
332bc79adfbSUwe Kleine-König .remove_new = sp_remove,
333f534e52fSWolfgang Grandegger .driver = {
334f534e52fSWolfgang Grandegger .name = DRV_NAME,
33502729c3dSFlorian Vaussard .of_match_table = sp_of_table,
336f534e52fSWolfgang Grandegger },
337f534e52fSWolfgang Grandegger };
338f534e52fSWolfgang Grandegger
339871d3372SAxel Lin module_platform_driver(sp_driver);
340