1*35e62ae8SThomas 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> 17f534e52fSWolfgang Grandegger #include <linux/io.h> 1802729c3dSFlorian Vaussard #include <linux/of.h> 19f49cbe6bSDamien Riegel #include <linux/of_device.h> 2002729c3dSFlorian Vaussard #include <linux/of_irq.h> 21f534e52fSWolfgang Grandegger 22f534e52fSWolfgang Grandegger #include "sja1000.h" 23f534e52fSWolfgang Grandegger 24f534e52fSWolfgang Grandegger #define DRV_NAME "sja1000_platform" 2502729c3dSFlorian Vaussard #define SP_CAN_CLOCK (16000000 / 2) 26f534e52fSWolfgang Grandegger 27f534e52fSWolfgang Grandegger MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 2802729c3dSFlorian Vaussard MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); 29f534e52fSWolfgang Grandegger MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); 30d8c4386dSMarc Kleine-Budde MODULE_ALIAS("platform:" DRV_NAME); 31f534e52fSWolfgang Grandegger MODULE_LICENSE("GPL v2"); 32f534e52fSWolfgang Grandegger 33f49cbe6bSDamien Riegel struct sja1000_of_data { 34f49cbe6bSDamien Riegel size_t priv_sz; 35f49cbe6bSDamien Riegel int (*init)(struct sja1000_priv *priv, struct device_node *of); 36f49cbe6bSDamien Riegel }; 37f49cbe6bSDamien Riegel 38dfb86c0dSDamien Riegel struct technologic_priv { 39dfb86c0dSDamien Riegel spinlock_t io_lock; 40dfb86c0dSDamien Riegel }; 41dfb86c0dSDamien Riegel 42986917b7SYegor Yefremov static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg) 43f534e52fSWolfgang Grandegger { 44255a9154SWolfgang Grandegger return ioread8(priv->reg_base + reg); 45f534e52fSWolfgang Grandegger } 46f534e52fSWolfgang Grandegger 47986917b7SYegor Yefremov static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val) 48f534e52fSWolfgang Grandegger { 49255a9154SWolfgang Grandegger iowrite8(val, priv->reg_base + reg); 50f534e52fSWolfgang Grandegger } 51f534e52fSWolfgang Grandegger 52986917b7SYegor Yefremov static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg) 53986917b7SYegor Yefremov { 54986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 2); 55986917b7SYegor Yefremov } 56986917b7SYegor Yefremov 57986917b7SYegor Yefremov static void sp_write_reg16(const struct sja1000_priv *priv, int reg, u8 val) 58986917b7SYegor Yefremov { 59986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 2); 60986917b7SYegor Yefremov } 61986917b7SYegor Yefremov 62986917b7SYegor Yefremov static u8 sp_read_reg32(const struct sja1000_priv *priv, int reg) 63986917b7SYegor Yefremov { 64986917b7SYegor Yefremov return ioread8(priv->reg_base + reg * 4); 65986917b7SYegor Yefremov } 66986917b7SYegor Yefremov 67986917b7SYegor Yefremov static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) 68986917b7SYegor Yefremov { 69986917b7SYegor Yefremov iowrite8(val, priv->reg_base + reg * 4); 70986917b7SYegor Yefremov } 71986917b7SYegor Yefremov 72dfb86c0dSDamien Riegel static u8 sp_technologic_read_reg16(const struct sja1000_priv *priv, int reg) 73dfb86c0dSDamien Riegel { 74dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv; 75dfb86c0dSDamien Riegel unsigned long flags; 76dfb86c0dSDamien Riegel u8 val; 77dfb86c0dSDamien Riegel 78dfb86c0dSDamien Riegel spin_lock_irqsave(&tp->io_lock, flags); 79dfb86c0dSDamien Riegel iowrite16(reg, priv->reg_base + 0); 80dfb86c0dSDamien Riegel val = ioread16(priv->reg_base + 2); 81dfb86c0dSDamien Riegel spin_unlock_irqrestore(&tp->io_lock, flags); 82dfb86c0dSDamien Riegel 83dfb86c0dSDamien Riegel return val; 84dfb86c0dSDamien Riegel } 85dfb86c0dSDamien Riegel 86dfb86c0dSDamien Riegel static void sp_technologic_write_reg16(const struct sja1000_priv *priv, 87dfb86c0dSDamien Riegel int reg, u8 val) 88dfb86c0dSDamien Riegel { 89dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv; 90dfb86c0dSDamien Riegel unsigned long flags; 91dfb86c0dSDamien Riegel 92dfb86c0dSDamien Riegel spin_lock_irqsave(&tp->io_lock, flags); 93dfb86c0dSDamien Riegel iowrite16(reg, priv->reg_base + 0); 94dfb86c0dSDamien Riegel iowrite16(val, priv->reg_base + 2); 95dfb86c0dSDamien Riegel spin_unlock_irqrestore(&tp->io_lock, flags); 96dfb86c0dSDamien Riegel } 97dfb86c0dSDamien Riegel 98dfb86c0dSDamien Riegel static int sp_technologic_init(struct sja1000_priv *priv, struct device_node *of) 99dfb86c0dSDamien Riegel { 100dfb86c0dSDamien Riegel struct technologic_priv *tp = priv->priv; 101dfb86c0dSDamien Riegel 102dfb86c0dSDamien Riegel priv->read_reg = sp_technologic_read_reg16; 103dfb86c0dSDamien Riegel priv->write_reg = sp_technologic_write_reg16; 104dfb86c0dSDamien Riegel spin_lock_init(&tp->io_lock); 105dfb86c0dSDamien Riegel 106dfb86c0dSDamien Riegel return 0; 107dfb86c0dSDamien Riegel } 108dfb86c0dSDamien Riegel 10902729c3dSFlorian Vaussard static void sp_populate(struct sja1000_priv *priv, 11002729c3dSFlorian Vaussard struct sja1000_platform_data *pdata, 11102729c3dSFlorian Vaussard unsigned long resource_mem_flags) 112f534e52fSWolfgang Grandegger { 11356e6943bSWolfgang Grandegger /* The CAN clock frequency is half the oscillator clock frequency */ 11456e6943bSWolfgang Grandegger priv->can.clock.freq = pdata->osc_freq / 2; 115f534e52fSWolfgang Grandegger priv->ocr = pdata->ocr; 116f534e52fSWolfgang Grandegger priv->cdr = pdata->cdr; 117f534e52fSWolfgang Grandegger 11802729c3dSFlorian Vaussard switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) { 119986917b7SYegor Yefremov case IORESOURCE_MEM_32BIT: 120986917b7SYegor Yefremov priv->read_reg = sp_read_reg32; 121986917b7SYegor Yefremov priv->write_reg = sp_write_reg32; 122986917b7SYegor Yefremov break; 123986917b7SYegor Yefremov case IORESOURCE_MEM_16BIT: 124986917b7SYegor Yefremov priv->read_reg = sp_read_reg16; 125986917b7SYegor Yefremov priv->write_reg = sp_write_reg16; 126986917b7SYegor Yefremov break; 127986917b7SYegor Yefremov case IORESOURCE_MEM_8BIT: 128986917b7SYegor Yefremov default: 129986917b7SYegor Yefremov priv->read_reg = sp_read_reg8; 130986917b7SYegor Yefremov priv->write_reg = sp_write_reg8; 131986917b7SYegor Yefremov break; 132986917b7SYegor Yefremov } 13302729c3dSFlorian Vaussard } 13402729c3dSFlorian Vaussard 13502729c3dSFlorian Vaussard static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) 13602729c3dSFlorian Vaussard { 13702729c3dSFlorian Vaussard int err; 13802729c3dSFlorian Vaussard u32 prop; 13902729c3dSFlorian Vaussard 140b18ec27cSFlorian Vaussard err = of_property_read_u32(of, "reg-io-width", &prop); 141b18ec27cSFlorian Vaussard if (err) 142b18ec27cSFlorian Vaussard prop = 1; /* 8 bit is default */ 143b18ec27cSFlorian Vaussard 144b18ec27cSFlorian Vaussard switch (prop) { 145b18ec27cSFlorian Vaussard case 4: 146b18ec27cSFlorian Vaussard priv->read_reg = sp_read_reg32; 147b18ec27cSFlorian Vaussard priv->write_reg = sp_write_reg32; 148b18ec27cSFlorian Vaussard break; 149b18ec27cSFlorian Vaussard case 2: 150b18ec27cSFlorian Vaussard priv->read_reg = sp_read_reg16; 151b18ec27cSFlorian Vaussard priv->write_reg = sp_write_reg16; 152b18ec27cSFlorian Vaussard break; 153b18ec27cSFlorian Vaussard case 1: /* fallthrough */ 154b18ec27cSFlorian Vaussard default: 15502729c3dSFlorian Vaussard priv->read_reg = sp_read_reg8; 15602729c3dSFlorian Vaussard priv->write_reg = sp_write_reg8; 157b18ec27cSFlorian Vaussard } 15802729c3dSFlorian Vaussard 15902729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop); 16002729c3dSFlorian Vaussard if (!err) 16102729c3dSFlorian Vaussard priv->can.clock.freq = prop / 2; 16202729c3dSFlorian Vaussard else 16302729c3dSFlorian Vaussard priv->can.clock.freq = SP_CAN_CLOCK; /* default */ 16402729c3dSFlorian Vaussard 16502729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,tx-output-mode", &prop); 16602729c3dSFlorian Vaussard if (!err) 16702729c3dSFlorian Vaussard priv->ocr |= prop & OCR_MODE_MASK; 16802729c3dSFlorian Vaussard else 16902729c3dSFlorian Vaussard priv->ocr |= OCR_MODE_NORMAL; /* default */ 17002729c3dSFlorian Vaussard 17102729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,tx-output-config", &prop); 17202729c3dSFlorian Vaussard if (!err) 17302729c3dSFlorian Vaussard priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; 17402729c3dSFlorian Vaussard else 17502729c3dSFlorian Vaussard priv->ocr |= OCR_TX0_PULLDOWN; /* default */ 17602729c3dSFlorian Vaussard 17702729c3dSFlorian Vaussard err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop); 17802729c3dSFlorian Vaussard if (!err && prop) { 17902729c3dSFlorian Vaussard u32 divider = priv->can.clock.freq * 2 / prop; 18002729c3dSFlorian Vaussard 18102729c3dSFlorian Vaussard if (divider > 1) 18202729c3dSFlorian Vaussard priv->cdr |= divider / 2 - 1; 18302729c3dSFlorian Vaussard else 18402729c3dSFlorian Vaussard priv->cdr |= CDR_CLKOUT_MASK; 18502729c3dSFlorian Vaussard } else { 18602729c3dSFlorian Vaussard priv->cdr |= CDR_CLK_OFF; /* default */ 18702729c3dSFlorian Vaussard } 18802729c3dSFlorian Vaussard 18902729c3dSFlorian Vaussard if (!of_property_read_bool(of, "nxp,no-comparator-bypass")) 19002729c3dSFlorian Vaussard priv->cdr |= CDR_CBP; /* default */ 19102729c3dSFlorian Vaussard } 19202729c3dSFlorian Vaussard 193dfb86c0dSDamien Riegel static struct sja1000_of_data technologic_data = { 194dfb86c0dSDamien Riegel .priv_sz = sizeof(struct technologic_priv), 195dfb86c0dSDamien Riegel .init = sp_technologic_init, 196dfb86c0dSDamien Riegel }; 197dfb86c0dSDamien Riegel 198f49cbe6bSDamien Riegel static const struct of_device_id sp_of_table[] = { 199f49cbe6bSDamien Riegel { .compatible = "nxp,sja1000", .data = NULL, }, 200dfb86c0dSDamien Riegel { .compatible = "technologic,sja1000", .data = &technologic_data, }, 201f49cbe6bSDamien Riegel { /* sentinel */ }, 202f49cbe6bSDamien Riegel }; 203f49cbe6bSDamien Riegel MODULE_DEVICE_TABLE(of, sp_of_table); 204f49cbe6bSDamien Riegel 20502729c3dSFlorian Vaussard static int sp_probe(struct platform_device *pdev) 20602729c3dSFlorian Vaussard { 20702729c3dSFlorian Vaussard int err, irq = 0; 20802729c3dSFlorian Vaussard void __iomem *addr; 20902729c3dSFlorian Vaussard struct net_device *dev; 21002729c3dSFlorian Vaussard struct sja1000_priv *priv; 21102729c3dSFlorian Vaussard struct resource *res_mem, *res_irq = NULL; 21202729c3dSFlorian Vaussard struct sja1000_platform_data *pdata; 21302729c3dSFlorian Vaussard struct device_node *of = pdev->dev.of_node; 214f49cbe6bSDamien Riegel const struct of_device_id *of_id; 215f49cbe6bSDamien Riegel const struct sja1000_of_data *of_data = NULL; 216f49cbe6bSDamien Riegel size_t priv_sz = 0; 21702729c3dSFlorian Vaussard 21802729c3dSFlorian Vaussard pdata = dev_get_platdata(&pdev->dev); 21902729c3dSFlorian Vaussard if (!pdata && !of) { 22002729c3dSFlorian Vaussard dev_err(&pdev->dev, "No platform data provided!\n"); 22102729c3dSFlorian Vaussard return -ENODEV; 22202729c3dSFlorian Vaussard } 22302729c3dSFlorian Vaussard 22402729c3dSFlorian Vaussard res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 22502729c3dSFlorian Vaussard if (!res_mem) 22602729c3dSFlorian Vaussard return -ENODEV; 22702729c3dSFlorian Vaussard 22802729c3dSFlorian Vaussard if (!devm_request_mem_region(&pdev->dev, res_mem->start, 22902729c3dSFlorian Vaussard resource_size(res_mem), DRV_NAME)) 23002729c3dSFlorian Vaussard return -EBUSY; 23102729c3dSFlorian Vaussard 23202729c3dSFlorian Vaussard addr = devm_ioremap_nocache(&pdev->dev, res_mem->start, 23302729c3dSFlorian Vaussard resource_size(res_mem)); 23402729c3dSFlorian Vaussard if (!addr) 23502729c3dSFlorian Vaussard return -ENOMEM; 23602729c3dSFlorian Vaussard 23702729c3dSFlorian Vaussard if (of) 23802729c3dSFlorian Vaussard irq = irq_of_parse_and_map(of, 0); 23902729c3dSFlorian Vaussard else 24002729c3dSFlorian Vaussard res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 24102729c3dSFlorian Vaussard 24202729c3dSFlorian Vaussard if (!irq && !res_irq) 24302729c3dSFlorian Vaussard return -ENODEV; 24402729c3dSFlorian Vaussard 245f49cbe6bSDamien Riegel of_id = of_match_device(sp_of_table, &pdev->dev); 246f49cbe6bSDamien Riegel if (of_id && of_id->data) { 247f49cbe6bSDamien Riegel of_data = of_id->data; 248f49cbe6bSDamien Riegel priv_sz = of_data->priv_sz; 249f49cbe6bSDamien Riegel } 250f49cbe6bSDamien Riegel 251f49cbe6bSDamien Riegel dev = alloc_sja1000dev(priv_sz); 25202729c3dSFlorian Vaussard if (!dev) 25302729c3dSFlorian Vaussard return -ENOMEM; 25402729c3dSFlorian Vaussard priv = netdev_priv(dev); 25502729c3dSFlorian Vaussard 25602729c3dSFlorian Vaussard if (res_irq) { 25702729c3dSFlorian Vaussard irq = res_irq->start; 25802729c3dSFlorian Vaussard priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; 25902729c3dSFlorian Vaussard if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) 26002729c3dSFlorian Vaussard priv->irq_flags |= IRQF_SHARED; 26102729c3dSFlorian Vaussard } else { 26202729c3dSFlorian Vaussard priv->irq_flags = IRQF_SHARED; 26302729c3dSFlorian Vaussard } 26402729c3dSFlorian Vaussard 26502729c3dSFlorian Vaussard dev->irq = irq; 26602729c3dSFlorian Vaussard priv->reg_base = addr; 26702729c3dSFlorian Vaussard 268f49cbe6bSDamien Riegel if (of) { 26902729c3dSFlorian Vaussard sp_populate_of(priv, of); 270f49cbe6bSDamien Riegel 271f49cbe6bSDamien Riegel if (of_data && of_data->init) { 272f49cbe6bSDamien Riegel err = of_data->init(priv, of); 273f49cbe6bSDamien Riegel if (err) 274f49cbe6bSDamien Riegel goto exit_free; 275f49cbe6bSDamien Riegel } 276f49cbe6bSDamien Riegel } else { 27702729c3dSFlorian Vaussard sp_populate(priv, pdata, res_mem->flags); 278f49cbe6bSDamien Riegel } 279986917b7SYegor Yefremov 28000e4bbc8SJingoo Han platform_set_drvdata(pdev, dev); 281f534e52fSWolfgang Grandegger SET_NETDEV_DEV(dev, &pdev->dev); 282f534e52fSWolfgang Grandegger 283f534e52fSWolfgang Grandegger err = register_sja1000dev(dev); 284f534e52fSWolfgang Grandegger if (err) { 285f534e52fSWolfgang Grandegger dev_err(&pdev->dev, "registering %s failed (err=%d)\n", 286f534e52fSWolfgang Grandegger DRV_NAME, err); 287f534e52fSWolfgang Grandegger goto exit_free; 288f534e52fSWolfgang Grandegger } 289f534e52fSWolfgang Grandegger 290255a9154SWolfgang Grandegger dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n", 291255a9154SWolfgang Grandegger DRV_NAME, priv->reg_base, dev->irq); 292f534e52fSWolfgang Grandegger return 0; 293f534e52fSWolfgang Grandegger 294f534e52fSWolfgang Grandegger exit_free: 295f534e52fSWolfgang Grandegger free_sja1000dev(dev); 296f534e52fSWolfgang Grandegger return err; 297f534e52fSWolfgang Grandegger } 298f534e52fSWolfgang Grandegger 299f534e52fSWolfgang Grandegger static int sp_remove(struct platform_device *pdev) 300f534e52fSWolfgang Grandegger { 30100e4bbc8SJingoo Han struct net_device *dev = platform_get_drvdata(pdev); 302f534e52fSWolfgang Grandegger 303f534e52fSWolfgang Grandegger unregister_sja1000dev(dev); 304f534e52fSWolfgang Grandegger free_sja1000dev(dev); 305f534e52fSWolfgang Grandegger 306f534e52fSWolfgang Grandegger return 0; 307f534e52fSWolfgang Grandegger } 308f534e52fSWolfgang Grandegger 309f534e52fSWolfgang Grandegger static struct platform_driver sp_driver = { 310f534e52fSWolfgang Grandegger .probe = sp_probe, 311f534e52fSWolfgang Grandegger .remove = sp_remove, 312f534e52fSWolfgang Grandegger .driver = { 313f534e52fSWolfgang Grandegger .name = DRV_NAME, 31402729c3dSFlorian Vaussard .of_match_table = sp_of_table, 315f534e52fSWolfgang Grandegger }, 316f534e52fSWolfgang Grandegger }; 317f534e52fSWolfgang Grandegger 318871d3372SAxel Lin module_platform_driver(sp_driver); 319