1 // SPDX-License-Identifier: GPL-2.0 2 // IOMapped CAN bus driver for Bosch M_CAN controller 3 // Copyright (C) 2014 Freescale Semiconductor, Inc. 4 // Dong Aisheng <b29396@freescale.com> 5 // 6 // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ 7 8 #include <linux/platform_device.h> 9 #include <linux/phy/phy.h> 10 11 #include "m_can.h" 12 13 struct m_can_plat_priv { 14 struct m_can_classdev cdev; 15 16 void __iomem *base; 17 void __iomem *mram_base; 18 }; 19 20 static inline struct m_can_plat_priv *cdev_to_priv(struct m_can_classdev *cdev) 21 { 22 return container_of(cdev, struct m_can_plat_priv, cdev); 23 } 24 25 static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg) 26 { 27 struct m_can_plat_priv *priv = cdev_to_priv(cdev); 28 29 return readl(priv->base + reg); 30 } 31 32 static u32 iomap_read_fifo(struct m_can_classdev *cdev, int offset) 33 { 34 struct m_can_plat_priv *priv = cdev_to_priv(cdev); 35 36 return readl(priv->mram_base + offset); 37 } 38 39 static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val) 40 { 41 struct m_can_plat_priv *priv = cdev_to_priv(cdev); 42 43 writel(val, priv->base + reg); 44 45 return 0; 46 } 47 48 static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, int val) 49 { 50 struct m_can_plat_priv *priv = cdev_to_priv(cdev); 51 52 writel(val, priv->mram_base + offset); 53 54 return 0; 55 } 56 57 static struct m_can_ops m_can_plat_ops = { 58 .read_reg = iomap_read_reg, 59 .write_reg = iomap_write_reg, 60 .write_fifo = iomap_write_fifo, 61 .read_fifo = iomap_read_fifo, 62 }; 63 64 static int m_can_plat_probe(struct platform_device *pdev) 65 { 66 struct m_can_classdev *mcan_class; 67 struct m_can_plat_priv *priv; 68 struct resource *res; 69 void __iomem *addr; 70 void __iomem *mram_addr; 71 struct phy *transceiver; 72 int irq, ret = 0; 73 74 mcan_class = m_can_class_allocate_dev(&pdev->dev, 75 sizeof(struct m_can_plat_priv)); 76 if (!mcan_class) 77 return -ENOMEM; 78 79 priv = cdev_to_priv(mcan_class); 80 81 ret = m_can_class_get_clocks(mcan_class); 82 if (ret) 83 goto probe_fail; 84 85 addr = devm_platform_ioremap_resource_byname(pdev, "m_can"); 86 irq = platform_get_irq_byname(pdev, "int0"); 87 if (IS_ERR(addr) || irq < 0) { 88 ret = -EINVAL; 89 goto probe_fail; 90 } 91 92 /* message ram could be shared */ 93 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram"); 94 if (!res) { 95 ret = -ENODEV; 96 goto probe_fail; 97 } 98 99 mram_addr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 100 if (!mram_addr) { 101 ret = -ENOMEM; 102 goto probe_fail; 103 } 104 105 transceiver = devm_phy_optional_get(&pdev->dev, NULL); 106 if (IS_ERR(transceiver)) { 107 ret = PTR_ERR(transceiver); 108 dev_err_probe(&pdev->dev, ret, "failed to get phy\n"); 109 goto probe_fail; 110 } 111 112 if (transceiver) 113 mcan_class->can.bitrate_max = transceiver->attrs.max_link_rate; 114 115 priv->base = addr; 116 priv->mram_base = mram_addr; 117 118 mcan_class->net->irq = irq; 119 mcan_class->pm_clock_support = 1; 120 mcan_class->can.clock.freq = clk_get_rate(mcan_class->cclk); 121 mcan_class->dev = &pdev->dev; 122 mcan_class->transceiver = transceiver; 123 124 mcan_class->ops = &m_can_plat_ops; 125 126 mcan_class->is_peripheral = false; 127 128 platform_set_drvdata(pdev, mcan_class); 129 130 m_can_init_ram(mcan_class); 131 132 pm_runtime_enable(mcan_class->dev); 133 ret = m_can_class_register(mcan_class); 134 if (ret) 135 goto out_runtime_disable; 136 137 return ret; 138 139 out_runtime_disable: 140 pm_runtime_disable(mcan_class->dev); 141 probe_fail: 142 m_can_class_free_dev(mcan_class->net); 143 return ret; 144 } 145 146 static __maybe_unused int m_can_suspend(struct device *dev) 147 { 148 return m_can_class_suspend(dev); 149 } 150 151 static __maybe_unused int m_can_resume(struct device *dev) 152 { 153 return m_can_class_resume(dev); 154 } 155 156 static int m_can_plat_remove(struct platform_device *pdev) 157 { 158 struct m_can_plat_priv *priv = platform_get_drvdata(pdev); 159 struct m_can_classdev *mcan_class = &priv->cdev; 160 161 m_can_class_unregister(mcan_class); 162 163 m_can_class_free_dev(mcan_class->net); 164 165 return 0; 166 } 167 168 static int __maybe_unused m_can_runtime_suspend(struct device *dev) 169 { 170 struct m_can_plat_priv *priv = dev_get_drvdata(dev); 171 struct m_can_classdev *mcan_class = &priv->cdev; 172 173 clk_disable_unprepare(mcan_class->cclk); 174 clk_disable_unprepare(mcan_class->hclk); 175 176 return 0; 177 } 178 179 static int __maybe_unused m_can_runtime_resume(struct device *dev) 180 { 181 struct m_can_plat_priv *priv = dev_get_drvdata(dev); 182 struct m_can_classdev *mcan_class = &priv->cdev; 183 int err; 184 185 err = clk_prepare_enable(mcan_class->hclk); 186 if (err) 187 return err; 188 189 err = clk_prepare_enable(mcan_class->cclk); 190 if (err) 191 clk_disable_unprepare(mcan_class->hclk); 192 193 return err; 194 } 195 196 static const struct dev_pm_ops m_can_pmops = { 197 SET_RUNTIME_PM_OPS(m_can_runtime_suspend, 198 m_can_runtime_resume, NULL) 199 SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume) 200 }; 201 202 static const struct of_device_id m_can_of_table[] = { 203 { .compatible = "bosch,m_can", .data = NULL }, 204 { /* sentinel */ }, 205 }; 206 MODULE_DEVICE_TABLE(of, m_can_of_table); 207 208 static struct platform_driver m_can_plat_driver = { 209 .driver = { 210 .name = KBUILD_MODNAME, 211 .of_match_table = m_can_of_table, 212 .pm = &m_can_pmops, 213 }, 214 .probe = m_can_plat_probe, 215 .remove = m_can_plat_remove, 216 }; 217 218 module_platform_driver(m_can_plat_driver); 219 220 MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>"); 221 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 222 MODULE_LICENSE("GPL v2"); 223 MODULE_DESCRIPTION("M_CAN driver for IO Mapped Bosch controllers"); 224